LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3 0/2] powerpc kvm: fix deadlock scene
From: Liu ping fan @ 2013-11-11  1:02 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, Alexander Graf, kvm-ppc
In-Reply-To: <20131108105837.GC16470@iris.ozlabs.ibm.com>

On Fri, Nov 8, 2013 at 6:58 PM, Paul Mackerras <paulus@samba.org> wrote:
> On Fri, Nov 08, 2013 at 03:29:52PM +0800, Liu Ping Fan wrote:
>> v2->v3:
>>   introduce kvmppc_hv_unlock_hpte() to pair with kvmppc_hv_find_lock_hpte()
>>   and hide the preemption detail inside this pair from the callers
>
> Actually, I preferred v2.  This version seems a bit over-engineered.
>
> Making a kvmppc_hv_unlock_hpte() is not such a bad idea, though I
> would make it identical to the existing unlock_hpte() from

Do you think it is helpful to distingusish HPTE_V_LOCK from
HPTE_V_HVLOCK at an API level?
If it is, I will keep patch 1/2 and just fix patch 2/2 .

> book3s_hv_rm_mmu.c, just in a header.  I'm really not convinced about
> putting the preempt_disable/enable inside the lock/unlock functions,
> with the consequent need to pass in a 'vmode' parameter, given that
> there is just one caller that needs to do the preempt_disable/enable.
>
Ok, will fix patch 2/2

Thanks and regards,
Pingfan

^ permalink raw reply

* Re: [PATCH] powerpc: kvm: optimize "sc 0" as fast return
From: Liu ping fan @ 2013-11-11  1:02 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, Alexander Graf, kvm-ppc
In-Reply-To: <20131108111217.GD16470@iris.ozlabs.ibm.com>

On Fri, Nov 8, 2013 at 7:12 PM, Paul Mackerras <paulus@samba.org> wrote:
> On Fri, Nov 08, 2013 at 10:44:16AM +0800, Liu Ping Fan wrote:
>> syscall is a very common behavior inside guest, and this patch
>> optimizes the path for the emulation of BOOK3S_INTERRUPT_SYSCALL,
>> so hypervisor can return to guest without heavy exit, i.e, no need
>> to swap TLB, HTAB,.. etc
>
> Many interrupts that are caused by guest code go directly to the guest
> and don't come to the hypervisor at all.  That includes system call
> (sc 0), alignment interrupts, program interrupts, SLB miss interrupts,
> etc.  See section 6.5 of Book 3S of the Power ISA specification; all
> the interrupts with '-' in the 'HV' column of the table there get
> delivered directly to the guest when they occur inside a guest.
>
Oh,got it, thanks! That is an important thing I tried to find out but
missed all these days.

>> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
>> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
>> @@ -1388,7 +1388,8 @@ kvmppc_hisi:
>>  hcall_try_real_mode:
>>       ld      r3,VCPU_GPR(R3)(r9)
>>       andi.   r0,r11,MSR_PR
>> -     bne     guest_exit_cont
>> +     /* sc 1 from userspace - reflect to guest syscall */
>> +     bne     sc_0_fast_return
>
> Discrepancy between comment and code here.  In fact we would only take
> the branch for a sc 1 instruction in userspace, which occurs when a PR
> KVM guest nested inside a HV KVM guest does a hypercall (i.e., not for

I made a big mistake from the beginning, and now get a more clear
understand of the scene. Thanks!

> normal system calls).  It is probably worthwhile to speed those up.
>
>> +sc_0_fast_return:
>> +     ld      r10,VCPU_PC(r9)
>> +     ld      r11,VCPU_MSR(r9)
>
> r11 must already contain this since you just did andi. r0,r11,MSR_PR.
> In fact r10 already contains VCPU_PC(r9) at this point also, though
> that is not so obvious.
>
>> +     mtspr   SPRN_SRR0,r10
>> +     mtspr   SPRN_SRR1,r11
>> +     li      r10, BOOK3S_INTERRUPT_SYSCALL
>> +     LOAD_REG_IMMEDIATE(r3,0xffffffff87a0ffff)       /* zero 33:36,42:47 */
>> +     and     r11,r11,r3
>
> This is not correct, since you don't even clear PR.  In fact what you

Yes.
> need is to load up MSR_SF | MSR_ME, though that value changes with

Is it enough to only set "MSR_SF | MSR_ME"? Sould the HV guest(PR KVM)
need to fake msr,  so that PR guest feels that "sc 1" is trapped by PR
KVM directly? I.e, according to ISA "Figure 51. MSR setting due to
interrupt", about "System Call", we need to keep MSR_IR/_DR unchanged.
If it is true, then HV need to help HV guest to make this fake. Right?

> little-endian support and changes again with transactional memory
> support for POWER8.  There is an idiom for loading that MSR value,
> which is:
>
>         li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
>         rotldi  r11, r11, 63
>
Why do we define MSR_SF_LG as bit 63, not like the ISA says bit 0 is SF?
And could you enlighten me briefly that what is the effect on the
value, when LE and  transactional memory are introduced?

Thanks and best regards,
Pingfan

> which you could use for now, but it will need to be changed when
> Anton's LE patch gets accepted.
>
> Paul.

^ permalink raw reply

* RE: [PATCH v5 4/4] powerpc/85xx: add sysfs for pw20 state and altivec idle
From: Dongsheng Wang @ 2013-11-11  2:13 UTC (permalink / raw)
  To: Scott Wood; +Cc: Bharat Bhushan, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1383787214.23598.96.camel@snotra.buserror.net>

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogV2FuZyBEb25nc2hlbmct
QjQwNTM0DQo+IFNlbnQ6IFRodXJzZGF5LCBOb3ZlbWJlciAwNywgMjAxMyAxMDoxMyBBTQ0KPiBU
bzogV29vZCBTY290dC1CMDc0MjENCj4gQ2M6IEJodXNoYW4gQmhhcmF0LVI2NTc3NzsgbGludXhw
cGMtZGV2QGxpc3RzLm96bGFicy5vcmcNCj4gU3ViamVjdDogUkU6IFtQQVRDSCB2NSA0LzRdIHBv
d2VycGMvODV4eDogYWRkIHN5c2ZzIGZvciBwdzIwIHN0YXRlIGFuZA0KPiBhbHRpdmVjIGlkbGUN
Cj4gDQo+IA0KPiANCj4gPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+IEZyb206IFdv
b2QgU2NvdHQtQjA3NDIxDQo+ID4gU2VudDogVGh1cnNkYXksIE5vdmVtYmVyIDA3LCAyMDEzIDk6
MjAgQU0NCj4gPiBUbzogV2FuZyBEb25nc2hlbmctQjQwNTM0DQo+ID4gQ2M6IEJodXNoYW4gQmhh
cmF0LVI2NTc3NzsgV29vZCBTY290dC1CMDc0MjE7IGxpbnV4cHBjLQ0KPiA+IGRldkBsaXN0cy5v
emxhYnMub3JnDQo+ID4gU3ViamVjdDogUmU6IFtQQVRDSCB2NSA0LzRdIHBvd2VycGMvODV4eDog
YWRkIHN5c2ZzIGZvciBwdzIwIHN0YXRlIGFuZA0KPiA+IGFsdGl2ZWMgaWRsZQ0KPiA+DQo+ID4g
T24gV2VkLCAyMDEzLTExLTA2IGF0IDAxOjUwIC0wNjAwLCBXYW5nIERvbmdzaGVuZy1CNDA1MzQg
d3JvdGU6DQo+ID4gPg0KPiA+ID4gPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+ID4g
PiBGcm9tOiBCaHVzaGFuIEJoYXJhdC1SNjU3NzcNCj4gPiA+ID4gU2VudDogV2VkbmVzZGF5LCBO
b3ZlbWJlciAwNiwgMjAxMyAxOjI1IFBNDQo+ID4gPiA+IFRvOiBXYW5nIERvbmdzaGVuZy1CNDA1
MzQ7IFdvb2QgU2NvdHQtQjA3NDIxDQo+ID4gPiA+IENjOiBsaW51eHBwYy1kZXZAbGlzdHMub3ps
YWJzLm9yZw0KPiA+ID4gPiBTdWJqZWN0OiBSRTogW1BBVENIIHY1IDQvNF0gcG93ZXJwYy84NXh4
OiBhZGQgc3lzZnMgZm9yIHB3MjAgc3RhdGUNCj4gPiA+ID4gYW5kIGFsdGl2ZWMgaWRsZQ0KPiA+
ID4gPg0KPiA+ID4gPg0KPiA+ID4gPg0KPiA+ID4gPiA+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0t
LS0tDQo+ID4gPiA+ID4gRnJvbTogV2FuZyBEb25nc2hlbmctQjQwNTM0DQo+ID4gPiA+ID4gU2Vu
dDogVHVlc2RheSwgTm92ZW1iZXIgMDUsIDIwMTMgODo0MCBBTQ0KPiA+ID4gPiA+IFRvOiBXb29k
IFNjb3R0LUIwNzQyMQ0KPiA+ID4gPiA+IENjOiBCaHVzaGFuIEJoYXJhdC1SNjU3Nzc7IGxpbnV4
cHBjLWRldkBsaXN0cy5vemxhYnMub3JnDQo+ID4gPiA+ID4gU3ViamVjdDogUkU6IFtQQVRDSCB2
NSA0LzRdIHBvd2VycGMvODV4eDogYWRkIHN5c2ZzIGZvciBwdzIwDQo+IHN0YXRlDQo+ID4gPiA+
ID4gYW5kIGFsdGl2ZWMgaWRsZQ0KPiA+ID4gPiA+DQo+ID4gPiA+ID4NCj4gPiA+ID4gPg0KPiA+
ID4gPiA+ID4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gPiA+ID4gPiA+IEZyb206IFdv
b2QgU2NvdHQtQjA3NDIxDQo+ID4gPiA+ID4gPiBTZW50OiBUdWVzZGF5LCBOb3ZlbWJlciAwNSwg
MjAxMyA1OjUyIEFNDQo+ID4gPiA+ID4gPiBUbzogV2FuZyBEb25nc2hlbmctQjQwNTM0DQo+ID4g
PiA+ID4gPiBDYzogV29vZCBTY290dC1CMDc0MjE7IEJodXNoYW4gQmhhcmF0LVI2NTc3NzsgbGlu
dXhwcGMtDQo+ID4gPiA+ID4gPiBkZXZAbGlzdHMub3psYWJzLm9yZw0KPiA+ID4gPiA+ID4gU3Vi
amVjdDogUmU6IFtQQVRDSCB2NSA0LzRdIHBvd2VycGMvODV4eDogYWRkIHN5c2ZzIGZvciBwdzIw
DQo+ID4gPiA+ID4gPiBzdGF0ZSBhbmQgYWx0aXZlYyBpZGxlDQo+ID4gPiA+ID4gPg0KPiA+ID4g
PiA+ID4gT24gU3VuLCAyMDEzLTExLTAzIGF0IDIyOjA0IC0wNjAwLCBXYW5nIERvbmdzaGVuZy1C
NDA1MzQgd3JvdGU6DQo+ID4gPiA+ID4gPiA+ID4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0N
Cj4gPiA+ID4gPiA+ID4gPiBGcm9tOiBXYW5nIERvbmdzaGVuZy1CNDA1MzQNCj4gPiA+ID4gPiA+
ID4gPiBTZW50OiBNb25kYXksIE9jdG9iZXIgMjEsIDIwMTMgMTE6MTEgQU0NCj4gPiA+ID4gPiA+
ID4gPiBUbzogV29vZCBTY290dC1CMDc0MjENCj4gPiA+ID4gPiA+ID4gPiBDYzogQmh1c2hhbiBC
aGFyYXQtUjY1Nzc3OyBsaW51eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZw0KPiA+ID4gPiA+ID4g
PiA+IFN1YmplY3Q6IFJFOiBbUEFUQ0ggdjUgNC80XSBwb3dlcnBjLzg1eHg6IGFkZCBzeXNmcyBm
b3INCj4gcHcyMA0KPiA+ID4gPiA+ID4gPiA+IHN0YXRlIGFuZCBhbHRpdmVjIGlkbGUNCj4gPiA+
ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+
ID4gPiA+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+ID4gPiA+ID4gPiA+ID4gPiBGcm9t
OiBXb29kIFNjb3R0LUIwNzQyMQ0KPiA+ID4gPiA+ID4gPiA+ID4gU2VudDogU2F0dXJkYXksIE9j
dG9iZXIgMTksIDIwMTMgMzoyMiBBTQ0KPiA+ID4gPiA+ID4gPiA+ID4gVG86IFdhbmcgRG9uZ3No
ZW5nLUI0MDUzNA0KPiA+ID4gPiA+ID4gPiA+ID4gQ2M6IEJodXNoYW4gQmhhcmF0LVI2NTc3Nzsg
V29vZCBTY290dC1CMDc0MjE7IGxpbnV4cHBjLQ0KPiA+ID4gPiA+ID4gPiA+ID4gZGV2QGxpc3Rz
Lm96bGFicy5vcmcNCj4gPiA+ID4gPiA+ID4gPiA+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjUgNC80
XSBwb3dlcnBjLzg1eHg6IGFkZCBzeXNmcyBmb3INCj4gPiA+ID4gPiA+ID4gPiA+IHB3MjAgc3Rh
dGUgYW5kIGFsdGl2ZWMgaWRsZQ0KPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+
IE9uIFRodSwgMjAxMy0xMC0xNyBhdCAyMjowMiAtMDUwMCwgV2FuZyBEb25nc2hlbmctQjQwNTM0
DQo+ID4gd3JvdGU6DQo+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
LS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiBGcm9tOiBC
aHVzaGFuIEJoYXJhdC1SNjU3NzcNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiBTZW50OiBUaHVyc2Rh
eSwgT2N0b2JlciAxNywgMjAxMyAyOjQ2IFBNDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gVG86IFdh
bmcgRG9uZ3NoZW5nLUI0MDUzNDsgV29vZCBTY290dC1CMDc0MjENCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBDYzogbGludXhwcGMtZGV2QGxpc3RzLm96bGFicy5vcmcNCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBTdWJqZWN0OiBSRTogW1BBVENIIHY1IDQvNF0gcG93ZXJwYy84NXh4OiBhZGQgc3lzZnMN
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiBmb3INCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiBwdzIwIHN0
YXRlIGFuZCBhbHRpdmVjIGlkbGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+IEZyb206IFdhbmcgRG9uZ3NoZW5nLUI0MDUzNA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE3LCAyMDEzIDExOjIyIEFNDQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gVG86IEJodXNoYW4gQmhhcmF0LVI2NTc3NzsgV29vZCBTY290dC1C
MDc0MjENCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBDYzogbGludXhwcGMtZGV2QGxpc3Rz
Lm96bGFicy5vcmcNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBTdWJqZWN0OiBSRTogW1BB
VENIIHY1IDQvNF0gcG93ZXJwYy84NXh4OiBhZGQNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiBzeXNmcyBmb3INCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBwdzIwIHN0YXRlIGFuZCBh
bHRpdmVjIGlkbGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiBGcm9tOiBCaHVzaGFuIEJoYXJhdC1SNjU3NzcNCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE3LCAyMDEzIDExOjIw
IEFNDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBUbzogV2FuZyBEb25nc2hlbmctQjQw
NTM0OyBXb29kIFNjb3R0LUIwNzQyMQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gQ2M6
IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3JnDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBTdWJqZWN0OiBSRTogW1BBVENIIHY1IDQvNF0gcG93ZXJwYy84NXh4OiBhZGQNCj4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IHN5c2ZzIGZvcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gcHcyMCBzdGF0ZSBhbmQgYWx0aXZlYyBpZGxlDQo+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IC0tLS0tT3Jp
Z2luYWwgTWVzc2FnZS0tLS0tDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IEZyb206
IFdhbmcgRG9uZ3NoZW5nLUI0MDUzNA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBT
ZW50OiBUaHVyc2RheSwgT2N0b2JlciAxNywgMjAxMyA4OjE2IEFNDQo+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+IFRvOiBCaHVzaGFuIEJoYXJhdC1SNjU3Nzc7IFdvb2QgU2NvdHQtDQo+
IEIwNzQyMQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBDYzogbGludXhwcGMtZGV2
QGxpc3RzLm96bGFicy5vcmcNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gU3ViamVj
dDogUkU6IFtQQVRDSCB2NSA0LzRdIHBvd2VycGMvODV4eDoNCj4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gYWRkIHN5c2ZzIGZvcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiBwdzIwIHN0YXRlIGFuZCBhbHRpdmVjIGlkbGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiAtLS0tLU9y
aWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IEZy
b206IEJodXNoYW4gQmhhcmF0LVI2NTc3Nw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE3LCAyMDEzIDE6MDEgQU0NCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBUbzogV2FuZyBEb25nc2hlbmctQjQwNTM0OyBXb29kDQo+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gU2NvdHQtQjA3NDIxDQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gQ2M6IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3Jn
DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gU3ViamVjdDogUkU6IFtQQVRDSCB2
NSA0LzRdIHBvd2VycGMvODV4eDoNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBh
ZGQgc3lzZnMgZm9yDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gcHcyMCBzdGF0
ZSBhbmQgYWx0aXZlYyBpZGxlDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiAtLS0tLU9yaWdp
bmFsIE1lc3NhZ2UtLS0tLQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gRnJv
bTogV2FuZyBEb25nc2hlbmctQjQwNTM0DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBTZW50OiBUdWVzZGF5LCBPY3RvYmVyIDE1LCAyMDEzIDI6NTEgUE0NCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IFRvOiBXb29kIFNjb3R0LUIwNzQyMQ0KPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gQ2M6IEJodXNoYW4gQmhhcmF0LVI2NTc3NzsNCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IGxpbnV4cHBjLWRldkBsaXN0cy5vemxh
YnMub3JnOyBXYW5nDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gRG9uZ3NoZW5n
LUI0MDUzNA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gU3ViamVjdDogW1BB
VENIIHY1IDQvNF0gcG93ZXJwYy84NXh4Og0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gYWRkIHN5c2ZzIGZvcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
cHcyMCBzdGF0ZSBhbmQNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBhbHRpdmVj
IGlkbGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBGcm9tOiBXYW5nIERvbmdzaGVuZw0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPGRvbmdzaGVuZy53YW5nQGZyZWVzY2FsZS5jb20+DQo+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gQWRkIGEgc3lzIGludGVyZmFjZSB0byBlbmFibGUvZGlhYmxlDQo+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBwdzIwIHN0YXRlIG9yIGFsdGl2ZWMgaWRs
ZSwgYW5kDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gY29udHJvbCB0aGUNCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IHdhaXQgZW50cnkgdGltZS4NCj4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiBFbmFibGUvRGlzYWJsZSBpbnRlcmZhY2U6DQo+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiAwLCBkaXNhYmxlLiAxLCBlbmFibGUuDQo+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiAvc3lzL2RldmljZXMvc3lzdGVtL2NwdS9jcHVYL3B3MjBfc3Rh
dGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+IC9zeXMvZGV2aWNlcy9z
eXN0ZW0vY3B1L2NwdVgvYWx0aXZlY19pZGwNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+IGUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBTZXQgd2FpdCB0aW1lIGludGVyZmFjZTooTmFub3Nl
Y29uZCkNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+IC9zeXMvZGV2aWNl
cy9zeXN0ZW0vY3B1L2NwdVgvcHcyMF93YWl0X3QNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+IGltZQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gL3N5
cy9kZXZpY2VzL3N5c3RlbS9jcHUvY3B1WC9hbHRpdmVjX2lkbA0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gZV93YQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gaXQNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IF90DQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBpbWUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+IEV4YW1wbGU6IEJhc2Ugb24gVEJmcmVxIGlzIDQxTUhaLg0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gMX40OChucyk6IFRCWzYzXQ0KPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gNDl+OTcobnMpOiBUQls2Ml0NCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+IDk4fjE5NShucyk6IFRCWzYxXQ0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gMTk2fjM5MChucyk6IFRCWzYwXQ0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gMzkxfjc4MChucyk6IFRCWzU5XQ0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gNzgxfjE1NjAobnMpOiBUQls1OF0gLi4uDQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gU2lnbmVkLW9mZi1ieTogV2FuZyBEb25nc2hlbmcNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+IDxkb25nc2hlbmcud2FuZ0BmcmVlc2NhbGUuY29tPg0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gLS0tDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiAqdjU6DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBDaGFuZ2Ug
Z2V0X2lkbGVfdGlja3NfYml0IGZ1bmN0aW9uDQo+ID4gPiA+IGltcGxlbWVudGF0aW9uLg0KPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ICp2NDoNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IE1v
dmUgY29kZSBmcm9tIDg1eHgvY29tbW9uLmMgdG8NCj4gPiA+ID4ga2VybmVsL3N5c2ZzLmMuDQo+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gUmVtb3ZlIGhhc19wdzIwX2FsdGl2ZWNfaWRsZSBmdW5jdGlvbi4NCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiBDaGFuZ2Ugd2FpdCAiZW50cnlfYml0IiB0byB3YWl0IHRpbWUuDQo+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gZGlmZiAtLWdpdA0KPiBhL2FyY2gvcG93ZXJwYy9rZXJuZWwvc3lzZnMuYw0K
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gYi9hcmNoL3Bvd2VycGMva2VybmVs
L3N5c2ZzLmMNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBpbmRleA0KPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gMjdhOTBiOS4uMTBkMTEyOCAxMDA2NDQNCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IC0tLSBhL2FyY2gvcG93ZXJwYy9rZXJu
ZWwvc3lzZnMuYw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKysrIGIvYXJj
aC9wb3dlcnBjL2tlcm5lbC9zeXNmcy5jDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBAQCAtODUsNiArODUsMjg0IEBADQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiBfX3NldHVwKCJzbXQtc25vb3plLWRlbGF5PSIsDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gc2V0dXBfc210X3Nub296ZV9kZWxheSk7DQo+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gICNl
bmRpZiAvKiBDT05GSUdfUFBDNjQgKi8NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArI2lmZGVmIENPTkZJR19G
U0xfU09DDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArI2RlZmluZSBNQVhf
QklUDQo+ID4gCTYzDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArDQo+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArc3RhdGljIHU2NCBwdzIwX3d0OyBzdGF0
aWMgdTY0DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArYWx0aXZlY19pZGxl
X3d0Ow0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gK3N0YXRpYyB1bnNpZ25lZCBpbnQNCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICtnZXRfaWRsZV90aWNrc19iaXQodTY0DQo+ID4gPiA+
IG5zKSB7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCXU2NCBjeWNsZTsN
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ICsJaWYgKG5zID49IDEwMDAwKQ0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gKwkJY3ljbGUgPSBkaXZfdTY0KG5zICsgNTAwLCAxMDAwKQ0KPiA+
ICoNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiB0Yl90aWNrc19wZXJfdXNlYzsNCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJZWxzZQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gKwkJY3ljbGUgPSBkaXZfdTY0KG5zICoNCj4gPiA+ID4gPiA+IHRiX3RpY2tz
X3Blcl91c2VjLA0KPiA+ID4gPiA+ID4gPiA+ID4gMTAwMCk7DQo+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiArDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiAr
CWlmICghY3ljbGUpDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQlyZXR1
cm4gMDsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJcmV0dXJuIGlsb2cyKGN5Y2xlKTsgfQ0KPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gK3N0YXRpYyB2b2lkIGRvX3Nob3dfcHdybWd0Y3IwKHZvaWQNCj4gKnZhbCkN
Cj4gPiB7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCXUzMiAqdmFsdWUg
PSB2YWw7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArDQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCSp2YWx1ZSA9IG1mc3ByKFNQUk5fUFdSTUdUQ1Iw
KTsgfQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gK3N0YXRpYyBzc2l6ZV90IHNob3dfcHcyMF9zdGF0ZShz
dHJ1Y3QNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICtkZXZpY2UNCj4gPiA+
ID4gPiA+ICpkZXYsDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQkJCXN0
cnVjdA0KPiA+IGRldmljZV9hdHRyaWJ1dGUNCj4gPiA+ID4gPiA+ICphdHRyLA0KPiA+ID4gPiA+
ID4gPiA+ID4gY2hhcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICpidWYpIHsNCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJdTMyIHZhbHVlOw0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gKwl1bnNpZ25lZCBpbnQgY3B1ID0gZGV2LT5pZDsNCj4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ICsJc21wX2NhbGxfZnVuY3Rpb25fc2luZ2xlKGNwdSwNCj4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ICtkb19zaG93X3B3cm1ndGNyMCwgJnZhbHVlLCAxKTsNCj4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ICsJdmFsdWUgJj0gUFdSTUdUQ1IwX1BXMjBfV0FJVDsNCj4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJXVcbiIsIHZhbHVlID8NCj4gPiAxIDoN
Cj4gPiA+ID4gPiA+IDApOyB9DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiAr
DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArc3RhdGljIHZvaWQgZG9fc3Rv
cmVfcHcyMF9zdGF0ZSh2b2lkDQo+ID4gKnZhbCkgew0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gKwl1MzIgKnZhbHVlID0gdmFsOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gKwl1MzIgcHcyMF9zdGF0ZTsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJcHcyMF9z
dGF0ZSA9IG1mc3ByKFNQUk5fUFdSTUdUQ1IwKTsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJaWYgKCp2
YWx1ZSkNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJCXB3MjBfc3RhdGUg
fD0NCj4gPiBQV1JNR1RDUjBfUFcyMF9XQUlUOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gKwllbHNlDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQlw
dzIwX3N0YXRlICY9DQo+ID4gflBXUk1HVENSMF9QVzIwX1dBSVQ7DQo+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiArDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiArCW10c3ByKFNQUk5fUFdSTUdUQ1IwLCBwdzIwX3N0YXRlKTsgfQ0KPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gK3N0YXRpYyBzc2l6ZV90IHN0b3JlX3B3MjBfc3RhdGUoc3RydWN0DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArZGV2aWNlDQo+ID4gPiA+ID4gPiAqZGV2LA0KPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKwkJCQlzdHJ1Y3QNCj4gPiBkZXZpY2VfYXR0
cmlidXRlDQo+ID4gPiA+ID4gPiAqYXR0ciwNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ICsJCQkJY29uc3QgY2hhciAqYnVmLA0KPiA+IHNpemVfdA0KPiA+ID4gPiA+ID4gY291
bnQpDQo+ID4gPiA+ID4gPiA+ID4gPiB7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiArCXUzMiB2YWx1ZTsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJ
dW5zaWduZWQgaW50IGNwdSA9IGRldi0+aWQ7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiArDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCWlmIChrc3Ry
dG91MzIoYnVmLCAwLCAmdmFsdWUpKQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiArDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCWlmICh2YWx1ZSA+IDEp
DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQlyZXR1cm4gLUVJTlZBTDsN
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ICsJc21wX2NhbGxfZnVuY3Rpb25fc2luZ2xlKGNwdSwNCj4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICtkb19zdG9yZV9wdzIwX3N0YXRlLCAmdmFs
dWUsIDEpOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKwlyZXR1cm4gY291bnQ7IH0NCj4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ICtzdGF0aWMgc3NpemVfdA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gK3Nob3dfcHcyMF93YWl0X3RpbWUoc3RydWN0IGRldmljZQ0KPiA+ID4gPiA+ID4gPiA+ICpk
ZXYsDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQkJCXN0cnVjdA0KPiA+
IGRldmljZV9hdHRyaWJ1dGUNCj4gPiA+ID4gPiA+ICphdHRyLA0KPiA+ID4gPiA+ID4gPiA+ID4g
Y2hhcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICpidWYpIHsNCj4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ICsJdTMyIHZhbHVlOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gKwl1NjQgdGJfY3ljbGU7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiArCXM2NCB0aW1lOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0K
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKwl1bnNpZ25lZCBpbnQgY3B1ID0g
ZGV2LT5pZDsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsNCj4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ICsJaWYgKCFwdzIwX3d0KSB7DQo+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQlzbXBfY2FsbF9mdW5jdGlvbl9zaW5nbGUoY3B1
LA0KPiA+ID4gPiA+ID4gPiA+ID4gZG9fc2hvd19wd3JtZ3RjcjAsDQo+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+ID4gPiArJnZhbHVlLA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gMSk7DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArCQl2YWx1ZSA9ICh2
YWx1ZSAmDQo+ID4gPiA+ID4gPiBQV1JNR1RDUjBfUFcyMF9FTlQpID4+DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiArDQo+ID4gPiA+ID4gPiAJUFdSTUdUQ1IwX1BXMjBfRU5U
X1NISUZUOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKwkJdGJfY3ljbGUgPSAoMSA8PCAoTUFYX0JJVCAt
DQo+ID4gdmFsdWUpKSAqDQo+ID4gPiA+ID4gPiAyOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gSXMgdmFsdWUgPSAw
IGFuZCB2YWx1ZSA9IDEgbGVnYWw/IFRoZXNlDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gd2lsbCBtYWtlIHRiX2N5Y2xlID0gMCwNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gKwkJdGltZSA9IGRp
dl91NjQodGJfY3ljbGUgKiAxMDAwLA0KPiA+ID4gPiA+ID4gPiA+ID4gdGJfdGlja3NfcGVyX3Vz
ZWMpDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gLSAxOw0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gQW5kIHRpbWUgPSAt
MTsNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiBQbGVhc2UgbG9vayBhdCB0aGUgZW5kIG9mIHRoZSBmdW5jdGlvbiwgOikN
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gInJldHVybiBzcHJpbnRmKGJ1ZiwgIiVsbHVcbiIsIHRpbWUgPiAwID8NCj4gPiB0
aW1lIDoNCj4gPiA+ID4gMCk7Ig0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IEkga25vdyB5b3UgcmV0dXJuIDAgaWYgdmFsdWUgPSAw
LzEsIG15DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBxdWVzdGlvbiB3YXMgdGhhdCwg
aXMgdGhpcyBjb3JyZWN0IGFzIHBlcg0KPiA+IHNwZWNpZmljYXRpb24/DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gQWhoLCBhbHNv
IGZvciAidmFsdWUiIHVwdG8gNyB5b3Ugd2lsbCByZXR1cm4NCj4gMCwNCj4gPiBubz8NCj4gPiA+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gSWYg
dmFsdWUgPSAwLCBNQVhfQklUIC0gdmFsdWUgPSA2MyB0Yl9jeWNsZSA9DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gMHhmZmZmZmZmZl9mZmZmZmZmZiwgdGJfY3ljbGUgKiAxMDAwIHdpbGwN
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBvdmVyZmxvdywgYnV0IHRoaXMNCj4gPiA+ID4g
PiA+ID4gPiA+IHNpdHVhdGlvbiBpcyBub3QgcG9zc2libGUuDQo+ID4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gQmVjYXVzZSBpZiB0aGUgInZhbHVlID0gMCIgbWVhbnMgdGhpcyBmZWF0dXJlDQo+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gd2lsbCBiZQ0KPiA+ID4gPiA+ID4gPiA+ICJkaXNh
YmxlIi4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBOb3cgVGhlIGRlZmF1bHQgd2FpdCBi
aXQgaXMgNTAoTUFYX0JJVCAtIHZhbHVlLA0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IHZh
bHVlID0gMTMpLCB0aGUgUFcyMC9BbHRpdmVjIElkbGUgd2FpdCBlbnRyeQ0KPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4gPiA+IHRpbWUgaXMgYWJvdXQgMW1zLCB0aGlzIHRpbWUgaXMgdmVyeSBsb25n
IGZvcg0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IHdhaXQgaWRsZSB0aW1lLCBhbmQgaXQn
cyBjYW5ub3QgYmUNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiBpbmNyZWFzZWQobWVhbnMg
KE1BWF9CSVQNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiAtIHZhbHVlKQ0KPiA+ID4gPiA+
ID4gPiA+ID4gPiA+ID4gPiBjYW5ub3QgZ3JlYXRlciB0aGFuIDUwKS4NCj4gPiA+ID4gPiA+ID4g
PiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gV2hhdCB5b3Ugc2FpZCBpcyBu
b3Qgb2J2aW91cyBmcm9tIGNvZGUgYW5kIHNvIGF0DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+
IGxlYXN0IHdyaXRlIGEgY29tbWVudCB0aGF0IHZhbHVlIHdpbGwgYmUNCj4gYWx3YXlzID49DQo+
ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IDEzIG9yIHZhbHVlIHdpbGwgbmV2ZXIgYmUgbGVzcyB0
aGFuIDwgOCBhbmQgYmVsb3cNCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gY2FsY3VsYXRpb24g
d2lsbCBub3Qgb3ZlcmZsb3cuIG1heSBiZSBlcnJvciBvdXQNCj4gaWYNCj4gPiA+ID4gdmFsdWUg
aXMgbGVzcyB0aGFuIDguDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gPiBUaGUgInZhbHVlIiBsZXNzIHRoYW4gMTAsIHRoaXMgd2lsbCBvdmVyZmxvdy4N
Cj4gPiA+ID4gPiA+ID4gPiA+ID4gPiA+IFRoZXJlIGlzIG5vdCBlcnJvciwgVGhlIGNvZGUgSSBr
bmV3IGl0IGNvdWxkIG5vdCBiZQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiA+ID4gbGVzcyB0aGFuIDEw
LCB0aGF0J3Mgd2h5IEkgdXNlIHRoZSBmb2xsb3dpbmcgY29kZS4NCj4gPiA+ID4gPiA+ID4gPiA+
ID4gPiA+IDopDQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPiBJ
IGFtIHNvcnJ5IHRvIHBlcnNpc3QgYnV0IHRoaXMgaXMgbm90IGFib3V0IHdoYXQgeW91DQo+ID4g
PiA+ID4gPiA+ID4gPiA+ID4ga25vdywgdGhpcyBpcyBhYm91dCBob3cgY29kZSBpcyByZWFkIGFu
ZCBjb2RlIGRvZXMNCj4gbm90DQo+ID4gPiA+ID4gPiA+ID4gPiA+ID4gc2F5IHdoYXQgeW91IGtu
b3csIHNvIGFkZCBhIGNvbW1lbnQgYXQgbGVhc3QgYW5kDQo+IGVycm9yDQo+ID4gPiA+ID4gPiA+
ID4gPiA+ID4gb3V0L3dhcm4gd2hlbiAidmFsdWUiIGlzIGxlc3MgdGhhbiBhDQo+ID4gPiA+ID4g
PiA+ID4gPiBjZXJ0YWluIG51bWJlci4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+
ID4gPiA+ID4gPiBTb3JyeSBmb3IgdGhlIGxhdGUgdG8gcmVzcG9uc2UgdGhlIG1haWwuIElmIGl0
IGNhdXNlZA0KPiA+ID4gPiA+ID4gPiA+ID4gPiBjb25mdXNpb24sIHdlIGNhbg0KPiA+ID4gPiA+
ID4gPiA+ID4gYWRkIGEgY29tbWVudC4NCj4gPiA+ID4gPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+
ID4gPiA+ID4gSG93IGFib3V0IHRoZSBmb2xsb3dpbmcgY29tbWVudD8NCj4gPiA+ID4gPiA+ID4g
PiA+ID4gLyoNCj4gPiA+ID4gPiA+ID4gPiA+ID4gICogSWYgdGhlICJ2YWx1ZSIgbGVzcyB0aGFu
IDEwLCB0aGlzIHdpbGwgb3ZlcmZsb3cuDQo+ID4gPiA+ID4gPiA+ID4gPiA+ICAqIEZyb20gYmVu
Y2htYXJrIHRlc3QsIHRoZSBkZWZhdWx0IHdhaXQgYml0IHdpbGwgbm90DQo+IGJlDQo+ID4gPiA+
ID4gPiA+ID4gPiA+IHNldCBsZXNzIHRoYW4NCj4gPiA+ID4gPiA+ID4gPiA+IDEwYml0Lg0KPiA+
ID4gPiA+ID4gPiA+ID4gPiAgKiBCZWNhdXNlIDEwIGJpdCBjb3JyZXNwb25kcyB0byB0aGUgd2Fp
dCBlbnRyeSB0aW1lIGlzDQo+ID4gPiA+ID4gPiA+ID4gPiA+IDQzOTM3NTU3MzQwMTk5OTYwOShu
cyksDQo+ID4gPiA+ID4gPiA+ID4gPiA+ICAqIGZvciB3YWl0LWVudHJ5LWlkbGUgdGltZSB0aGlz
IHZhbHVlIGxvb2tzIHRvbyBsb25nLA0KPiA+ID4gPiA+ID4gPiA+ID4gPiBhbmQgd2UgY2Fubm90
IHVzZSB0aG9zZQ0KPiA+ID4gPiA+ID4gPiA+ID4gPiAgKiAibG9uZyIgdGltZSBhcyBhIGRlZmF1
bHQgd2FpdC1lbnRyeSB0aW1lLiBTbw0KPiBvdmVyZmxvdw0KPiA+ID4gPiA+ID4gPiA+ID4gPiBj
b3VsZCBub3QgaGF2ZSBoYXBwZW5lZA0KPiA+ID4gPiA+ID4gPiA+ID4gPiAgKiBhbmQgd2UgdXNl
IHRoaXMgY2FsY3VsYXRpb24gbWV0aG9kIHRvIGdldA0KPiA+ID4gPiA+ID4gPiA+ID4gPiB3YWl0
LWVudHJ5LWlkbGUNCj4gPiA+ID4gdGltZS4NCj4gPiA+ID4gPiA+ID4gPiA+ID4gICovDQo+ID4g
PiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiA+ID4gSWYgdGhlcmUncyB0byBiZSBhIGxpbWl0
IG9uIHRoZSB0aW1lcyB3ZSBhY2NlcHQsIG1ha2UgaXQNCj4gPiA+ID4gZXhwbGljaXQuDQo+ID4g
PiA+ID4gPiA+ID4gPiBDaGVjayBmb3IgaXQgYmVmb3JlIGRvaW5nIGFueSBjb252ZXJzaW9ucywg
YW5kIHJldHVybiBhbg0KPiA+ID4gPiA+ID4gPiA+ID4gZXJyb3IgaWYgdXNlcnNwYWNlIHRyaWVz
IHRvIHNldCBpdC4NCj4gPiA+ID4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiA+ID4gVGhlIGJyYW5j
aCBvbmx5IHVzZSB0byByZWFkIGRlZmF1bHQgd2FpdC1lbnRyeS10aW1lLg0KPiA+ID4gPiA+ID4g
PiA+IFdlIGhhdmUgbm8gbGltaXQgdGhlIHVzZXIncyBpbnB1dCwgYW5kIHdlIGNhbid0IHJlc3Ry
aWN0Lg0KPiA+ID4gPiA+ID4gPiA+IE9uY2UgdGhlIHVzZXIgc2V0IHRoZSB3YWl0LWVudHJ5LXRp
bWUsIHRoZSBjb2RlIHdpbGwgZG8NCj4gPiBhbm90aGVyIGJyYW5jaC4NCj4gPiA+ID4gPiA+ID4g
Pg0KPiA+ID4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gPiBIaSBzY290dCwNCj4gPiA+ID4gPiA+ID4g
RG8geW91IGhhdmUgYW55IGNvbW1lbnRzIGFib3V0IHRoaXMgcGF0Y2g/DQo+ID4gPiA+ID4gPiA+
IEkgd2lsbCBhZGQgdGhlIGNvbW1lbnQgYW5kIHNlbmQgdGhpcyBwYXRjaCBhZ2Fpbi4NCj4gPiA+
ID4gPiA+DQo+ID4gPiA+ID4gPiBXaGF0IGRvIHlvdSBtZWFuIGJ5ICJhbmQgd2UgY2FuJ3QgcmVz
dHJpY3QiPyAgV2h5IG5vdD8NCj4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiBXaHkgaXMgaXQgb25s
eSB1c2VkIHRvIHJlYWQgdGhlIGRlZmF1bHQsIGFuZCBub3QgdGhlIGN1cnJlbnQNCj4gPiB2YWx1
ZT8NCj4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gV2UgYWxyZWFkeSBoYXZlIGEgdmFyaWFibGUgd2hp
Y2ggdmFsdWUgaXMgc2V0IGJ5IHRoZSB1c2VyLCBhcyB3ZQ0KPiA+ID4gPiA+IGhhdmUgZGlzY3Vz
c2VkIGJlZm9yZS4NCj4gPiA+ID4gPg0KPiA+ID4gPiA+IFdoZW4gdGhlIHN5c3RlbSBib290LXVw
LiBCZWZvcmUgdXNlciBzZXQgdGhlIHdhaXQtZW50cnktdGltZSwgd2UNCj4gPiA+ID4gPiBuZWVk
IHRvIHJldHVybiBhIGRlZmF1bHQgd2FpdC1lbnRyeS10aW1lLCBpZiB0aGUgdXNlciByZWFkIHRo
aXMNCj4gPiA+ID4gPiBzeXMtaW50ZXJmYWNlLiBUaGUgZGVmYXVsdCB3YWl0LWVudHJ5LXRpbWUg
aXMgY29udmVydGVkIGJ5IHdhaXQtDQo+IGJpdC4NCj4gPiA+ID4gPg0KPiA+ID4gPiA+IE9uY2Ug
dGhlIHVzZXIgc2V0IHRoZSBzeXMtaW50ZXJmYWNlLCBhIHZhcmlhYmxlIHdpbGwgYmUgdXNlZCB0
bw0KPiA+ID4gPiA+IHNhdmUgaXQuIEFuZCB3aGVuIHRoZSB1c2VyIHJlYWQgc3lzLWludGVyZmFj
ZSB3ZSB3aWxsIHJldHVybiBiYWNrDQo+ID4gPiA+ID4gdGhlDQo+ID4gPiA+IHZhcmlhYmxlLg0K
PiA+ID4gPg0KPiA+ID4gPiBXaGlsZSB3ZSBhcmUgbm90ICJyZXN0cmljdGluZyB1c2VyIGRlZmlu
ZWQgdmFsdWUiIG9yICJkZWZpbmUgc2FtZQ0KPiA+ID4gPiByZXN0cmljdGlvbiBmb3IgdXNlciBk
ZWZpbmVkIGFuZCBkZWZhdWx0IiwgY2FuIHdlIGhhdmUgb25seSBvbmUNCj4gZmxvdw0KPiA+ID4g
PiBvZiBjYWxjdWxhdGlvbiBhbmQgc2V0dGluZyByYXRoZXIgdGhhbiBjb25kaXRpb25hbCBiYXNl
ZCBvbiB1c2VyDQo+ID4gPiA+IGhhdmUgc2V0IG9yIG5vdCBzZXQ/DQo+ID4gPiA+DQo+ID4gPiBZ
ZXMsIHdlIGNhbiBkbyB0aGF0Lg0KPiA+ID4gSWYgd2Ugd2FudCB0byB1c2Ugb25lIGZsb3cgdG8g
aGFuZGxlIGl0LiBXZSBzaG91bGQgZG8gdGhlIGZvbGxvd2luZw0KPiA+IGNoYW5nZXM6DQo+ID4g
Pg0KPiA+ID4gI2lmZGVmIENPTkZJR19GU0xfU09DDQo+ID4gPiAjaW5jbHVkZSA8bGludXgvc2xh
Yi5oPg0KPiA+ID4gI2VuZGlmDQo+ID4NCj4gPiBEb24ndCBpZmRlZiBoZWFkZXJzLg0KPiA+DQo+
ID4gPiBzdGF0aWMgdTY0ICpwdzIwX3d0Ow0KPiA+ID4gc3RhdGljIHU2NCAqYWx0aXZlY19pZGxl
X3d0Ow0KPiA+ID4NCj4gPiA+IHN0YXRpYyBzc2l6ZV90IHNob3dfcHcyMF93YWl0X3RpbWUoc3Ry
dWN0IGRldmljZSAqZGV2LA0KPiA+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBz
dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhcg0KPiA+ID4gKmJ1Zikgew0KPiA+ID4g
CXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVsbHVcbiIsIHB3MjBfd3RbZGV2LT5pZF0pOyB9DQo+ID4g
Pg0KPiA+ID4gc3RhdGljIHNzaXplX3Qgc3RvcmVfcHcyMF93YWl0X3RpbWUoc3RydWN0IGRldmlj
ZSAqZGV2LA0KPiA+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgZGV2
aWNlX2F0dHJpYnV0ZSAqYXR0ciwNCj4gPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpIHsgLi4uDQo+ID4gPiBwdzIwX3d0W2Nw
dV0gPSB2YWx1ZTsNCj4gPiA+IC4uLg0KPiA+ID4gfQ0KPiA+ID4NCj4gPiA+IHN0YXRpYyBzc2l6
ZV90IHNob3dfYWx0aXZlY19pZGxlX3dhaXRfdGltZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+ID4g
PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRl
ICphdHRyLCBjaGFyDQo+ID4gPiAqYnVmKSB7DQo+ID4gPiAJcmV0dXJuIHNwcmludGYoYnVmLCAi
JWxsdVxuIiwgYWx0aXZlY19pZGxlX3d0W2Rldi0+aWRdKTsgfQ0KPiA+ID4NCj4gPiA+IHN0YXRp
YyBzc2l6ZV90IHN0b3JlX2FsdGl2ZWNfaWRsZV93YWl0X3RpbWUoc3RydWN0IGRldmljZSAqZGV2
LA0KPiA+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgZGV2aWNlX2F0
dHJpYnV0ZSAqYXR0ciwNCj4gPiA+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29u
c3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpIHsgLi4uDQo+ID4gPiBhbHRpdmVjX2lkbGVfd3Rb
Y3B1XSA9IHZhbHVlOw0KPiA+ID4gLi4uDQo+ID4gPiB9DQo+ID4gPg0KPiA+ID4gc3RhdGljIHZv
aWQgcmVnaXN0ZXJfY3B1X29ubGluZSh1bnNpZ25lZCBpbnQgY3B1KSB7IC4uLg0KPiA+ID4gI2lm
ZGVmIENPTkZJR19GU0xfU09DDQo+ID4gPiAgICAgICAgIHUzMiB2YWx1ZSwgcHcyMF92YWx1ZSwg
YWx0aXZlY192YWx1ZTsNCj4gPiA+ICAgICAgICAgdTY0IHRiX2N5Y2xlOw0KPiA+ID4gI2VuZGlm
DQo+ID4gPiAuLi4NCj4gPiA+ICNpZmRlZiBDT05GSUdfRlNMX1NPQw0KPiA+ID4gICAgICAgICBp
ZiAoUFZSX1ZFUihjdXJfY3B1X3NwZWMtPnB2cl92YWx1ZSkgPT0gUFZSX1ZFUl9FNjUwMCkgew0K
PiA+ID4gICAgICAgICAgICAgICAgIGRldmljZV9jcmVhdGVfZmlsZShzLCAmZGV2X2F0dHJfcHcy
MF9zdGF0ZSk7DQo+ID4gPiAgICAgICAgICAgICAgICAgZGV2aWNlX2NyZWF0ZV9maWxlKHMsICZk
ZXZfYXR0cl9wdzIwX3dhaXRfdGltZSk7DQo+ID4gPg0KPiA+ID4gICAgICAgICAgICAgICAgIGRl
dmljZV9jcmVhdGVfZmlsZShzLCAmZGV2X2F0dHJfYWx0aXZlY19pZGxlKTsNCj4gPiA+ICAgICAg
ICAgICAgICAgICBkZXZpY2VfY3JlYXRlX2ZpbGUocywNCj4gJmRldl9hdHRyX2FsdGl2ZWNfaWRs
ZV93YWl0X3RpbWUpOw0KPiA+ID4gICAgICAgICB9DQo+ID4gPg0KPiA+ID4gICAgICAgICBpZiAo
IXB3MjBfd3QpDQo+ID4gPiAgICAgICAgICAgICAgICAgcHcyMF93dCA9IGt6YWxsb2MobnJfY3B1
X2lkcyAqIHNpemVvZigqcHcyMF93dCksDQo+ID4gPiBHRlBfS0VSTkVMKTsNCj4gPiA+DQo+ID4g
PiAJICBpZiAoIWFsdGl2ZWNfaWRsZV93dCkNCj4gPiA+IAkJICAgIGFsdGl2ZWNfaWRsZV93dCA9
IGt6YWxsb2MobnJfY3B1X2lkcyAqDQo+ID4gc2l6ZW9mKCphbHRpdmVjX2lkbGVfd3QpLA0KPiA+
ID4gR0ZQX0tFUk5FTCk7DQo+ID4gPg0KPiA+ID4gICAgICAgICBzbXBfY2FsbF9mdW5jdGlvbl9z
aW5nbGUoY3B1LCBkb19zaG93X3B3cm1ndGNyMCwgJnZhbHVlLCAxKTsNCj4gPiA+DQo+ID4gPiAg
ICAgICAgIHB3MjBfdmFsdWUgPSAodmFsdWUgJiBQV1JNR1RDUjBfUFcyMF9FTlQpID4+DQo+ID4g
UFdSTUdUQ1IwX1BXMjBfRU5UX1NISUZUOw0KPiA+ID4gICAgICAgICB0Yl9jeWNsZSA9ICgxIDw8
IChNQVhfQklUIC0gcHcyMF92YWx1ZSkpICogMjsNCj4gPiA+ICAgICAgICAgcHcyMF93dFtjcHVd
ID0gZGl2X3U2NCh0Yl9jeWNsZSAqIDEwMDAsIHRiX3RpY2tzX3Blcl91c2VjKSAtDQo+ID4gPiAx
Ow0KPiA+ID4NCj4gPiA+ICAgICAgICAgYWx0aXZlY192YWx1ZSA9ICh2YWx1ZSAmIFBXUk1HVENS
MF9BVl9JRExFX0NOVCkgPj4NCj4gPiBQV1JNR1RDUjBfQVZfSURMRV9DTlRfU0hJRlQ7DQo+ID4g
PiAgICAgICAgIHRiX2N5Y2xlID0gKDEgPDwgKE1BWF9CSVQgLSBhbHRpdmVjX3ZhbHVlKSkgKiAy
Ow0KPiA+ID4gICAgICAgICBhbHRpdmVjX2lkbGVfd3RbY3B1XSA9IGRpdl91NjQodGJfY3ljbGUg
KiAxMDAwLA0KPiA+ID4gdGJfdGlja3NfcGVyX3VzZWMpIC0gMTsgI2VuZGlmIC4uLg0KPiA+ID4g
fQ0KPiA+DQo+ID4gTW92ZSB0aGlzIHN0dWZmIHRvIGl0cyBvd24gZnVuY3Rpb24uICBUaGUgb25s
eSBpZmRlZiBzaG91bGQgYmUgaW4gYQ0KPiA+IGhlYWRlciB0aGF0IHByb3ZpZGVzIGFuIGlubGlu
ZSBzdHViIHdoZW4gaXQncyBub3QgYXZhaWxhYmxlLg0KPiA+DQo+ID4gQ291bGQgeW91IGV4cGxh
aW4gd2hhdCB5b3UncmUgY2hhbmdpbmcgYW5kIHdoeT8gIEEgZGlmZiBmcm9tIHlvdXINCj4gPiBw
cmV2aW91cyBwYXRjaCB3b3VsZCBoZWxwLg0KPiA+DQo+IFRob3NlIGNvZGVzIGp1c3QgZm9yIGRp
c2N1c3Mgd2l0aCBCaGFyYXQuIEhlIHdhbnQgdG8gbWFrZSBvbmUgZmxvdyBhdA0KPiAic2hvd19w
dzIwX3dhaXRfdGltZSIvIiBzaG93X2FsdGl2ZWNfaWRsZV93YWl0X3RpbWUiIGZ1bmN0aW9uLiBJ
ZiB3ZSBkbw0KPiB0aGF0LCB3ZSBuZWVkIHRvIGluaXRpYWxpemUgcHcyMF93dC9hbHRpdmVjX2lk
bGVfd3QuDQo+IA0KSSB3aWxsIGtlZXAgdGhpcyBzdHVmZiBhdCAic2hvd19wdzIwX3dhaXRfdGlt
ZSIvInNob3dfYWx0aXZlY19pZGxlX3dhaXRfdGltZSIgYW5kIGFkZCBhIGNvbW1lbnQgYmVmb3Jl
IG91ciBkaXNjdXNzaW9uLg0KDQovKg0KICogSWYgdGhlICJ2YWx1ZSIgbGVzcyB0aGFuIDEwLCB0
aGlzIHdpbGwgb3ZlcmZsb3cuDQogKiBGcm9tIGJlbmNobWFyayB0ZXN0LCB0aGUgZGVmYXVsdCB3
YWl0IGJpdCB3aWxsIG5vdCBiZSBzZXQgbGVzcyB0aGFuIDEwYml0Lg0KICogQmVjYXVzZSAxMCBi
aXQgY29ycmVzcG9uZHMgdG8gdGhlIHdhaXQgZW50cnkgdGltZSBpcyA0MzkzNzU1NzM0MDE5OTk2
MDkobnMpLA0KICogZm9yIHdhaXQtZW50cnktaWRsZSB0aW1lIHRoaXMgdmFsdWUgbG9va3MgdG9v
IGxvbmcsIGFuZCB3ZSBjYW5ub3QgdXNlIHRob3NlDQogKiAibG9uZyIgdGltZSBhcyBhIGRlZmF1
bHQgd2FpdC1lbnRyeSB0aW1lLiBTbyBvdmVyZmxvdyBjb3VsZCBub3QgaGF2ZSBoYXBwZW5lZA0K
ICogYW5kIHdlIHVzZSB0aGlzIGNhbGN1bGF0aW9uIG1ldGhvZCB0byBnZXQgd2FpdC1lbnRyeS1p
ZGxlIHRpbWUuDQogKi8NCj4gLWRvbmdzaGVuZw0K

^ permalink raw reply

* [PATCH v6 0/4] Add dual-fifo mode support of i.MX ssi
From: Nicolin Chen @ 2013-11-11  4:00 UTC (permalink / raw)
  To: vinod.koul, dan.j.williams, s.hauer, timur, shawn.guo, broonie
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
	swarren, linux-kernel, rob.herring, dmaengine, ijc+devicetree,
	linuxppc-dev, linux-arm-kernel

 * ! This series of patches has a direct dependency between them. When
 * ! applying them, we need to apply to one single branch. Otherwise,
 * ! it would break currect branches.

Changelog
v6:
 * PATCH-1: Use goto err_firmware instead of return directly.
 *
 * Nothing changes for the other three ack-ed patches
v5:
 * PATCH-3: Add period size constraint when using dual fifo mode
 *
 * Nothing changes for the other three patches
v4:
 * PATCH-3: Drop useless register configuration.
 *
 * Nothing changes for the other three patches
v3:
 * PATCH-1: Add comments to indicate the end of v1 and v2 array.
 * PATCH-3: Use better way to keep watermark as even number.
 *
 * Nothing changes for PATCH-2 and PATCH-4
v2:
 * Instead of adding rogue scripts to current SDMA driver based on firmware
 * V1, we define the new SDMA firmware as version 2 and bisect the PATCH-1
 * to two patches: The first is to add version check code to the SDMA driver;
 * And the second is to add SSI dual FIFO DMATYPE.
 *
 * Nothing changes for the last two patches.
v1:
 * SSI can reduce hardware overrun/underrun possibility when using dual
 * fifo mode. To support this mode, we need to first update sdma sciprt
 * list, and then enable dual fifo BIT in SSI driver, and last update DT
 * bindings of i.MX series.

Nicolin Chen (4):
  dma: imx-sdma: Add sdma firmware version 2 support
  dma: imx-sdma: Add new dma type for ssi dual fifo script
  ASoC: fsl_ssi: Add dual fifo mode support
  ARM: dts: imx: use dual-fifo sdma script for ssi

 .../devicetree/bindings/dma/fsl-imx-sdma.txt       |  1 +
 arch/arm/boot/dts/imx51.dtsi                       |  4 ++--
 arch/arm/boot/dts/imx53.dtsi                       |  4 ++--
 arch/arm/boot/dts/imx6qdl.dtsi                     | 12 +++++-----
 arch/arm/boot/dts/imx6sl.dtsi                      | 12 +++++-----
 drivers/dma/imx-sdma.c                             | 19 ++++++++++++++-
 include/linux/platform_data/dma-imx-sdma.h         |  5 ++++
 include/linux/platform_data/dma-imx.h              |  1 +
 sound/soc/fsl/fsl_ssi.c                            | 27 +++++++++++++++++++++-
 9 files changed, 67 insertions(+), 18 deletions(-)

-- 
1.8.4

^ permalink raw reply

* [PATCH v6 1/4] dma: imx-sdma: Add sdma firmware version 2 support
From: Nicolin Chen @ 2013-11-11  4:00 UTC (permalink / raw)
  To: vinod.koul, dan.j.williams, s.hauer, timur, shawn.guo, broonie
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
	swarren, linux-kernel, rob.herring, dmaengine, ijc+devicetree,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <cover.1384136268.git.b42378@freescale.com>

On i.MX5/6 series, SDMA is using new version firmware to support SSI
dual FIFO feature and HDMI Audio (i.MX6Q/DL only). Thus add it.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 drivers/dma/imx-sdma.c                     | 15 ++++++++++++++-
 include/linux/platform_data/dma-imx-sdma.h |  5 +++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index fc43603..43a8441 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -323,6 +323,7 @@ struct sdma_engine {
 	struct clk			*clk_ipg;
 	struct clk			*clk_ahb;
 	spinlock_t			channel_0_lock;
+	u32				script_number;
 	struct sdma_script_start_addrs	*script_addrs;
 	const struct sdma_driver_data	*drvdata;
 };
@@ -1238,6 +1239,7 @@ static void sdma_issue_pending(struct dma_chan *chan)
 }
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2	38
 
 static void sdma_add_scripts(struct sdma_engine *sdma,
 		const struct sdma_script_start_addrs *addr)
@@ -1246,7 +1248,7 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
 	s32 *saddr_arr = (u32 *)sdma->script_addrs;
 	int i;
 
-	for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
+	for (i = 0; i < sdma->script_number; i++)
 		if (addr_arr[i] > 0)
 			saddr_arr[i] = addr_arr[i];
 }
@@ -1272,6 +1274,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
 		goto err_firmware;
 	if (header->ram_code_start + header->ram_code_size > fw->size)
 		goto err_firmware;
+	switch (header->version_major) {
+		case 1:
+			sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
+			break;
+		case 2:
+			sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
+			break;
+		default:
+			dev_err(sdma->dev, "unknown firmware version\n");
+			goto err_firmware;
+	}
 
 	addr = (void *)header + header->script_addrs_start;
 	ram_code = (void *)header + header->ram_code_start;
diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h
index 3a39428..eabac4e 100644
--- a/include/linux/platform_data/dma-imx-sdma.h
+++ b/include/linux/platform_data/dma-imx-sdma.h
@@ -43,6 +43,11 @@ struct sdma_script_start_addrs {
 	s32 dptc_dvfs_addr;
 	s32 utra_addr;
 	s32 ram_code_start_addr;
+	/* End of v1 array */
+	s32 mcu_2_ssish_addr;
+	s32 ssish_2_mcu_addr;
+	s32 hdmi_dma_addr;
+	/* End of v2 array */
 };
 
 /**
-- 
1.8.4

^ permalink raw reply related

* [PATCH v6 2/4] dma: imx-sdma: Add new dma type for ssi dual fifo script
From: Nicolin Chen @ 2013-11-11  4:00 UTC (permalink / raw)
  To: vinod.koul, dan.j.williams, s.hauer, timur, shawn.guo, broonie
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
	swarren, linux-kernel, rob.herring, dmaengine, ijc+devicetree,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <cover.1384136268.git.b42378@freescale.com>

This patch adds a new DMA_TYPE for SSI dual FIFO script, included
in SDMA firmware version 2. This script would allow SSI use dual
fifo mode to transimit/receive data without occasional hardware
underrun/overrun.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt | 1 +
 drivers/dma/imx-sdma.c                                 | 4 ++++
 include/linux/platform_data/dma-imx.h                  | 1 +
 3 files changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
index 4fa814d..68b83ec 100644
--- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -42,6 +42,7 @@ The full ID of peripheral types can be found below.
 	19	IPU Memory
 	20	ASRC
 	21	ESAI
+	22	SSI Dual FIFO	(needs firmware ver >= 2)
 
 The third cell specifies the transfer priority as below.
 
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 43a8441..efe9d6a 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -725,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
 		per_2_emi = sdma->script_addrs->app_2_mcu_addr;
 		emi_2_per = sdma->script_addrs->mcu_2_app_addr;
 		break;
+	case IMX_DMATYPE_SSI_DUAL:
+		per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
+		break;
 	case IMX_DMATYPE_SSI_SP:
 	case IMX_DMATYPE_MMC:
 	case IMX_DMATYPE_SDHC:
diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h
index beac6b8..bcbc6c3 100644
--- a/include/linux/platform_data/dma-imx.h
+++ b/include/linux/platform_data/dma-imx.h
@@ -39,6 +39,7 @@ enum sdma_peripheral_type {
 	IMX_DMATYPE_IPU_MEMORY,	/* IPU Memory */
 	IMX_DMATYPE_ASRC,	/* ASRC */
 	IMX_DMATYPE_ESAI,	/* ESAI */
+	IMX_DMATYPE_SSI_DUAL,	/* SSI Dual FIFO */
 };
 
 enum imx_dma_prio {
-- 
1.8.4

^ permalink raw reply related

* [PATCH v6 3/4] ASoC: fsl_ssi: Add dual fifo mode support
From: Nicolin Chen @ 2013-11-11  4:00 UTC (permalink / raw)
  To: vinod.koul, dan.j.williams, s.hauer, timur, shawn.guo, broonie
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
	swarren, linux-kernel, rob.herring, dmaengine, ijc+devicetree,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <cover.1384136268.git.b42378@freescale.com>

By enabling dual fifo mode, it would allow SSI enter a better performance
to transimit/receive data without occasional hardware underrun/overrun.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 sound/soc/fsl/fsl_ssi.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 6b81d0c..af6640c 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -143,6 +143,7 @@ struct fsl_ssi_private {
 	bool ssi_on_imx;
 	bool imx_ac97;
 	bool use_dma;
+	bool use_dual_fifo;
 	struct clk *clk;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -413,6 +414,12 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
 		write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
 	}
 
+	if (ssi_private->use_dual_fifo) {
+		write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
+		write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
+		write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
+	}
+
 	return 0;
 }
 
@@ -487,6 +494,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 		ssi_private->second_stream = substream;
 	}
 
+	/* When using dual fifo mode, it is safer to ensure an even period
+	 * size. If appearing to an odd number while DMA always starts its
+	 * task from fifo0, fifo1 would be neglected at the end of each
+	 * period. But SSI would still access fifo1 with an invalid data.
+	 */
+	if (ssi_private->use_dual_fifo)
+		snd_pcm_hw_constraint_step(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+
 	return 0;
 }
 
@@ -954,7 +970,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 		ssi_private->fifo_depth = 8;
 
 	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
-		u32 dma_events[2];
+		u32 dma_events[2], dmas[4];
 		ssi_private->ssi_on_imx = true;
 
 		ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
@@ -1008,6 +1024,15 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 			dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
 		imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
 			dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
+		if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
+				&& dmas[2] == IMX_DMATYPE_SSI_DUAL) {
+			ssi_private->use_dual_fifo = true;
+			/* When using dual fifo mode, we need to keep watermark
+			 * as even numbers due to dma script limitation.
+			 */
+			ssi_private->dma_params_tx.maxburst &= ~0x1;
+			ssi_private->dma_params_rx.maxburst &= ~0x1;
+		}
 	} else if (ssi_private->use_dma) {
 		/* The 'name' should not have any slashes in it. */
 		ret = devm_request_irq(&pdev->dev, ssi_private->irq,
-- 
1.8.4

^ permalink raw reply related

* [PATCH v6 4/4] ARM: dts: imx: use dual-fifo sdma script for ssi
From: Nicolin Chen @ 2013-11-11  4:00 UTC (permalink / raw)
  To: vinod.koul, dan.j.williams, s.hauer, timur, shawn.guo, broonie
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
	swarren, linux-kernel, rob.herring, dmaengine, ijc+devicetree,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <cover.1384136268.git.b42378@freescale.com>

Use dual-fifo sdma scripts instead of shared scripts for ssi on i.MX series.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 arch/arm/boot/dts/imx51.dtsi   |  4 ++--
 arch/arm/boot/dts/imx53.dtsi   |  4 ++--
 arch/arm/boot/dts/imx6qdl.dtsi | 12 ++++++------
 arch/arm/boot/dts/imx6sl.dtsi  | 12 ++++++------
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 54cee65..1a71eac 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -154,8 +154,8 @@
 					reg = <0x70014000 0x4000>;
 					interrupts = <30>;
 					clocks = <&clks 49>;
-					dmas = <&sdma 24 1 0>,
-					       <&sdma 25 1 0>;
+					dmas = <&sdma 24 22 0>,
+					       <&sdma 25 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 4307e80..7208fde 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -153,8 +153,8 @@
 					reg = <0x50014000 0x4000>;
 					interrupts = <30>;
 					clocks = <&clks 49>;
-					dmas = <&sdma 24 1 0>,
-					       <&sdma 25 1 0>;
+					dmas = <&sdma 24 22 0>,
+					       <&sdma 25 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 57e9c38..6e096ca 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -223,8 +223,8 @@
 					reg = <0x02028000 0x4000>;
 					interrupts = <0 46 0x04>;
 					clocks = <&clks 178>;
-					dmas = <&sdma 37 1 0>,
-					       <&sdma 38 1 0>;
+					dmas = <&sdma 37 22 0>,
+					       <&sdma 38 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					fsl,ssi-dma-events = <38 37>;
@@ -236,8 +236,8 @@
 					reg = <0x0202c000 0x4000>;
 					interrupts = <0 47 0x04>;
 					clocks = <&clks 179>;
-					dmas = <&sdma 41 1 0>,
-					       <&sdma 42 1 0>;
+					dmas = <&sdma 41 22 0>,
+					       <&sdma 42 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					fsl,ssi-dma-events = <42 41>;
@@ -249,8 +249,8 @@
 					reg = <0x02030000 0x4000>;
 					interrupts = <0 48 0x04>;
 					clocks = <&clks 180>;
-					dmas = <&sdma 45 1 0>,
-					       <&sdma 46 1 0>;
+					dmas = <&sdma 45 22 0>,
+					       <&sdma 46 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					fsl,ssi-dma-events = <46 45>;
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index c46651e..b32ba99 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -195,8 +195,8 @@
 					reg = <0x02028000 0x4000>;
 					interrupts = <0 46 0x04>;
 					clocks = <&clks IMX6SL_CLK_SSI1>;
-					dmas = <&sdma 37 1 0>,
-					       <&sdma 38 1 0>;
+					dmas = <&sdma 37 22 0>,
+					       <&sdma 38 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					status = "disabled";
@@ -207,8 +207,8 @@
 					reg = <0x0202c000 0x4000>;
 					interrupts = <0 47 0x04>;
 					clocks = <&clks IMX6SL_CLK_SSI2>;
-					dmas = <&sdma 41 1 0>,
-					       <&sdma 42 1 0>;
+					dmas = <&sdma 41 22 0>,
+					       <&sdma 42 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					status = "disabled";
@@ -219,8 +219,8 @@
 					reg = <0x02030000 0x4000>;
 					interrupts = <0 48 0x04>;
 					clocks = <&clks IMX6SL_CLK_SSI3>;
-					dmas = <&sdma 45 1 0>,
-					       <&sdma 46 1 0>;
+					dmas = <&sdma 45 22 0>,
+					       <&sdma 46 22 0>;
 					dma-names = "rx", "tx";
 					fsl,fifo-depth = <15>;
 					status = "disabled";
-- 
1.8.4

^ permalink raw reply related

* RE: [PATCH v5 4/4] powerpc/85xx: add sysfs for pw20 state and altivec idle
From: Bharat Bhushan @ 2013-11-11  4:11 UTC (permalink / raw)
  To: Dongsheng Wang, Scott Wood; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <ABB05CD9C9F68C46A5CEDC7F15439259010BF40C@039-SN2MPN1-021.039d.mgd.msft.net>

PiA+IFRob3NlIGNvZGVzIGp1c3QgZm9yIGRpc2N1c3Mgd2l0aCBCaGFyYXQuIEhlIHdhbnQgdG8g
bWFrZSBvbmUgZmxvdyBhdA0KPiA+ICJzaG93X3B3MjBfd2FpdF90aW1lIi8iIHNob3dfYWx0aXZl
Y19pZGxlX3dhaXRfdGltZSIgZnVuY3Rpb24uIElmIHdlDQo+ID4gZG8gdGhhdCwgd2UgbmVlZCB0
byBpbml0aWFsaXplIHB3MjBfd3QvYWx0aXZlY19pZGxlX3d0Lg0KPiA+DQo+IEkgd2lsbCBrZWVw
IHRoaXMgc3R1ZmYgYXQgInNob3dfcHcyMF93YWl0X3RpbWUiLyJzaG93X2FsdGl2ZWNfaWRsZV93
YWl0X3RpbWUiDQo+IGFuZCBhZGQgYSBjb21tZW50IGJlZm9yZSBvdXIgZGlzY3Vzc2lvbi4NCj4g
DQo+IC8qDQo+ICAqIElmIHRoZSAidmFsdWUiIGxlc3MgdGhhbiAxMCwgdGhpcyB3aWxsIG92ZXJm
bG93Lg0KPiAgKiBGcm9tIGJlbmNobWFyayB0ZXN0LCB0aGUgZGVmYXVsdCB3YWl0IGJpdCB3aWxs
IG5vdCBiZSBzZXQgbGVzcyB0aGFuIDEwYml0Lg0KPiAgKiBCZWNhdXNlIDEwIGJpdCBjb3JyZXNw
b25kcyB0byB0aGUgd2FpdCBlbnRyeSB0aW1lIGlzIDQzOTM3NTU3MzQwMTk5OTYwOShucyksDQo+
ICAqIGZvciB3YWl0LWVudHJ5LWlkbGUgdGltZSB0aGlzIHZhbHVlIGxvb2tzIHRvbyBsb25nLCBh
bmQgd2UgY2Fubm90IHVzZSB0aG9zZQ0KPiAgKiAibG9uZyIgdGltZSBhcyBhIGRlZmF1bHQgd2Fp
dC1lbnRyeSB0aW1lLiBTbyBvdmVyZmxvdyBjb3VsZCBub3QgaGF2ZSBoYXBwZW5lZA0KPiAgKiBh
bmQgd2UgdXNlIHRoaXMgY2FsY3VsYXRpb24gbWV0aG9kIHRvIGdldCB3YWl0LWVudHJ5LWlkbGUg
dGltZS4NCj4gICovDQoNCkkgdGhpbmsgbm93IHdlIHdpbGwgdXNlIHNhbWUgY2FsY3VsYXRpb24g
Y29kZSBmb3IgZGVmYXVsdCB2YWx1ZSBhbmQgdXNlciBzZXQgdmFsdWUsIHNvIGFkZGluZyB0aGUg
Y29tbWVudCBpcyBub3Qgc3VmZmljaWVudCwgd2Ugc2hvdWxkIGVycm9yIG91dCBmcm9tIHRoZSBj
b2RlIGlmIHZhbHVlIGlzIGxlc3MgdGhhbiAxMC4gQXMgZGVmYXVsdCB2YWx1ZSBpcyBub3QgbGVz
cyB0aGFuIDEwIHNvIHRoaXMgd2lsbCBhbHdheXMgd29yayB3aXRoIGRlZmF1bHQgdmFsdWUgYnV0
IGlmIHVzZXIgdHJpZXMgdG8gc2V0IGxlc3MgdGhhbiAxMCB0aGVuIGVycm9yIG91dCBhbmQgYXNr
IHVzZXIgdG8gdHJ5IG1vcmUgdGhhbiA5Lg0KDQotQmhhcmF0DQo=

^ permalink raw reply

* [PATCH 0/3] powerpc iommu: Remove hardcoded page sizes
From: Alistair Popple @ 2013-11-11  4:22 UTC (permalink / raw)
  To: linuxppc-dev

This patch series replaces the hardcoded iommu page sizes used by the iommu
backend with a dynamic page size initialised by each platform. This will make
it easier to use iommu page sizes other than 4K.

The series doesn't actually change the iommu page size as each platform continues to
initialise the iommu page size to a hardcoded value of 4K.

At this stage testing has only been carried out on a pSeries machine, other platforms
including cell have yet to be tested.

^ permalink raw reply

* [PATCH 1/3] powerpc iommu: Update constant names to reflect their hardcoded page size
From: Alistair Popple @ 2013-11-11  4:22 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple
In-Reply-To: <1384143729-14491-1-git-send-email-alistair@popple.id.au>

The powerpc iommu uses a hardcoded page size of 4K. This patch changes
the name of the IOMMU_PAGE_* macros to reflect the hardcoded values. A
future patch will use the existing names to support dynamic page
sizes.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/include/asm/iommu.h       |   10 ++--
 arch/powerpc/kernel/dma-iommu.c        |    4 +-
 arch/powerpc/kernel/iommu.c            |   80 ++++++++++++++++----------------
 arch/powerpc/kernel/vio.c              |   19 ++++----
 arch/powerpc/platforms/powernv/pci.c   |    2 +-
 arch/powerpc/platforms/pseries/iommu.c |    8 ++--
 arch/powerpc/platforms/pseries/setup.c |    4 +-
 drivers/net/ethernet/ibm/ibmveth.c     |    9 ++--
 8 files changed, 69 insertions(+), 67 deletions(-)

diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index c34656a..e53de39 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -30,10 +30,10 @@
 #include <asm/machdep.h>
 #include <asm/types.h>
 
-#define IOMMU_PAGE_SHIFT      12
-#define IOMMU_PAGE_SIZE       (ASM_CONST(1) << IOMMU_PAGE_SHIFT)
-#define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
-#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
+#define IOMMU_PAGE_SHIFT_4K      12
+#define IOMMU_PAGE_SIZE_4K       (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K)
+#define IOMMU_PAGE_MASK_4K       (~((1 << IOMMU_PAGE_SHIFT_4K) - 1))
+#define IOMMU_PAGE_ALIGN_4K(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE_4K)
 
 /* Boot time flags */
 extern int iommu_is_off;
@@ -42,7 +42,7 @@ extern int iommu_force_on;
 /* Pure 2^n version of get_order */
 static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
 {
-	return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
+	return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT_4K) + 1;
 }
 
 
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index e489752..5cfe3db 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -83,10 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
 		return 0;
 	}
 
-	if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT)) {
+	if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT_4K)) {
 		dev_info(dev, "Warning: IOMMU offset too big for device mask\n");
 		dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n",
-				mask, tbl->it_offset << IOMMU_PAGE_SHIFT);
+				mask, tbl->it_offset << IOMMU_PAGE_SHIFT_4K);
 		return 0;
 	} else
 		return 1;
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 572bb5b..6bc5d14 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -251,14 +251,14 @@ again:
 
 	if (dev)
 		boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
-				      1 << IOMMU_PAGE_SHIFT);
+				      1 << IOMMU_PAGE_SHIFT_4K);
 	else
-		boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT);
+		boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT_4K);
 	/* 4GB boundary for iseries_hv_alloc and iseries_hv_map */
 
 	n = iommu_area_alloc(tbl->it_map, limit, start, npages,
-			     tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT,
-			     align_mask);
+			tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT_4K,
+			align_mask);
 	if (n == -1) {
 		if (likely(pass == 0)) {
 			/* First try the pool from the start */
@@ -320,12 +320,12 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
 		return DMA_ERROR_CODE;
 
 	entry += tbl->it_offset;	/* Offset into real TCE table */
-	ret = entry << IOMMU_PAGE_SHIFT;	/* Set the return dma address */
+	ret = entry << IOMMU_PAGE_SHIFT_4K;	/* Set the return dma address */
 
 	/* Put the TCEs in the HW table */
 	build_fail = ppc_md.tce_build(tbl, entry, npages,
-	                              (unsigned long)page & IOMMU_PAGE_MASK,
-	                              direction, attrs);
+				(unsigned long)page & IOMMU_PAGE_MASK_4K,
+				direction, attrs);
 
 	/* ppc_md.tce_build() only returns non-zero for transient errors.
 	 * Clean up the table bitmap in this case and return
@@ -352,7 +352,7 @@ static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr,
 {
 	unsigned long entry, free_entry;
 
-	entry = dma_addr >> IOMMU_PAGE_SHIFT;
+	entry = dma_addr >> IOMMU_PAGE_SHIFT_4K;
 	free_entry = entry - tbl->it_offset;
 
 	if (((free_entry + npages) > tbl->it_size) ||
@@ -401,7 +401,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 	unsigned long flags;
 	struct iommu_pool *pool;
 
-	entry = dma_addr >> IOMMU_PAGE_SHIFT;
+	entry = dma_addr >> IOMMU_PAGE_SHIFT_4K;
 	free_entry = entry - tbl->it_offset;
 
 	pool = get_pool(tbl, free_entry);
@@ -468,13 +468,13 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 		}
 		/* Allocate iommu entries for that segment */
 		vaddr = (unsigned long) sg_virt(s);
-		npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE);
+		npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE_4K);
 		align = 0;
-		if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
+		if (IOMMU_PAGE_SHIFT_4K < PAGE_SHIFT && slen >= PAGE_SIZE &&
 		    (vaddr & ~PAGE_MASK) == 0)
-			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT_4K;
 		entry = iommu_range_alloc(dev, tbl, npages, &handle,
-					  mask >> IOMMU_PAGE_SHIFT, align);
+					  mask >> IOMMU_PAGE_SHIFT_4K, align);
 
 		DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
@@ -489,16 +489,16 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 
 		/* Convert entry to a dma_addr_t */
 		entry += tbl->it_offset;
-		dma_addr = entry << IOMMU_PAGE_SHIFT;
-		dma_addr |= (s->offset & ~IOMMU_PAGE_MASK);
+		dma_addr = entry << IOMMU_PAGE_SHIFT_4K;
+		dma_addr |= (s->offset & ~IOMMU_PAGE_MASK_4K);
 
 		DBG("  - %lu pages, entry: %lx, dma_addr: %lx\n",
 			    npages, entry, dma_addr);
 
 		/* Insert into HW table */
 		build_fail = ppc_md.tce_build(tbl, entry, npages,
-		                              vaddr & IOMMU_PAGE_MASK,
-		                              direction, attrs);
+					vaddr & IOMMU_PAGE_MASK_4K,
+					direction, attrs);
 		if(unlikely(build_fail))
 			goto failure;
 
@@ -559,9 +559,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 		if (s->dma_length != 0) {
 			unsigned long vaddr, npages;
 
-			vaddr = s->dma_address & IOMMU_PAGE_MASK;
+			vaddr = s->dma_address & IOMMU_PAGE_MASK_4K;
 			npages = iommu_num_pages(s->dma_address, s->dma_length,
-						 IOMMU_PAGE_SIZE);
+						 IOMMU_PAGE_SIZE_4K);
 			__iommu_free(tbl, vaddr, npages);
 			s->dma_address = DMA_ERROR_CODE;
 			s->dma_length = 0;
@@ -592,7 +592,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 		if (sg->dma_length == 0)
 			break;
 		npages = iommu_num_pages(dma_handle, sg->dma_length,
-					 IOMMU_PAGE_SIZE);
+					 IOMMU_PAGE_SIZE_4K);
 		__iommu_free(tbl, dma_handle, npages);
 		sg = sg_next(sg);
 	}
@@ -676,7 +676,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 		set_bit(0, tbl->it_map);
 
 	/* We only split the IOMMU table if we have 1GB or more of space */
-	if ((tbl->it_size << IOMMU_PAGE_SHIFT) >= (1UL * 1024 * 1024 * 1024))
+	if ((tbl->it_size << IOMMU_PAGE_SHIFT_4K) >= (1UL * 1024 * 1024 * 1024))
 		tbl->nr_pools = IOMMU_NR_POOLS;
 	else
 		tbl->nr_pools = 1;
@@ -768,16 +768,16 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 
 	vaddr = page_address(page) + offset;
 	uaddr = (unsigned long)vaddr;
-	npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE);
+	npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE_4K);
 
 	if (tbl) {
 		align = 0;
-		if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && size >= PAGE_SIZE &&
+		if (IOMMU_PAGE_SHIFT_4K < PAGE_SHIFT && size >= PAGE_SIZE &&
 		    ((unsigned long)vaddr & ~PAGE_MASK) == 0)
-			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT_4K;
 
 		dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
-					 mask >> IOMMU_PAGE_SHIFT, align,
+					 mask >> IOMMU_PAGE_SHIFT_4K, align,
 					 attrs);
 		if (dma_handle == DMA_ERROR_CODE) {
 			if (printk_ratelimit())  {
@@ -786,7 +786,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 					 npages);
 			}
 		} else
-			dma_handle |= (uaddr & ~IOMMU_PAGE_MASK);
+			dma_handle |= (uaddr & ~IOMMU_PAGE_MASK_4K);
 	}
 
 	return dma_handle;
@@ -801,7 +801,7 @@ void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
 	BUG_ON(direction == DMA_NONE);
 
 	if (tbl) {
-		npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE);
+		npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE_4K);
 		iommu_free(tbl, dma_handle, npages);
 	}
 }
@@ -845,10 +845,10 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
 	memset(ret, 0, size);
 
 	/* Set up tces to cover the allocated range */
-	nio_pages = size >> IOMMU_PAGE_SHIFT;
+	nio_pages = size >> IOMMU_PAGE_SHIFT_4K;
 	io_order = get_iommu_order(size);
 	mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
-			      mask >> IOMMU_PAGE_SHIFT, io_order, NULL);
+			      mask >> IOMMU_PAGE_SHIFT_4K, io_order, NULL);
 	if (mapping == DMA_ERROR_CODE) {
 		free_pages((unsigned long)ret, order);
 		return NULL;
@@ -864,7 +864,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 		unsigned int nio_pages;
 
 		size = PAGE_ALIGN(size);
-		nio_pages = size >> IOMMU_PAGE_SHIFT;
+		nio_pages = size >> IOMMU_PAGE_SHIFT_4K;
 		iommu_free(tbl, dma_handle, nio_pages);
 		size = PAGE_ALIGN(size);
 		free_pages((unsigned long)vaddr, get_order(size));
@@ -935,10 +935,10 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl,
 	if (tce_value)
 		return -EINVAL;
 
-	if (ioba & ~IOMMU_PAGE_MASK)
+	if (ioba & ~IOMMU_PAGE_MASK_4K)
 		return -EINVAL;
 
-	ioba >>= IOMMU_PAGE_SHIFT;
+	ioba >>= IOMMU_PAGE_SHIFT_4K;
 	if (ioba < tbl->it_offset)
 		return -EINVAL;
 
@@ -955,13 +955,13 @@ int iommu_tce_put_param_check(struct iommu_table *tbl,
 	if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ)))
 		return -EINVAL;
 
-	if (tce & ~(IOMMU_PAGE_MASK | TCE_PCI_WRITE | TCE_PCI_READ))
+	if (tce & ~(IOMMU_PAGE_MASK_4K | TCE_PCI_WRITE | TCE_PCI_READ))
 		return -EINVAL;
 
-	if (ioba & ~IOMMU_PAGE_MASK)
+	if (ioba & ~IOMMU_PAGE_MASK_4K)
 		return -EINVAL;
 
-	ioba >>= IOMMU_PAGE_SHIFT;
+	ioba >>= IOMMU_PAGE_SHIFT_4K;
 	if (ioba < tbl->it_offset)
 		return -EINVAL;
 
@@ -1037,7 +1037,7 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
 
 	/* if (unlikely(ret))
 		pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n",
-				__func__, hwaddr, entry << IOMMU_PAGE_SHIFT,
+				__func__, hwaddr, entry << IOMMU_PAGE_SHIFT_4K,
 				hwaddr, ret); */
 
 	return ret;
@@ -1049,14 +1049,14 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 {
 	int ret;
 	struct page *page = NULL;
-	unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK & ~PAGE_MASK;
+	unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK_4K & ~PAGE_MASK;
 	enum dma_data_direction direction = iommu_tce_direction(tce);
 
 	ret = get_user_pages_fast(tce & PAGE_MASK, 1,
 			direction != DMA_TO_DEVICE, &page);
 	if (unlikely(ret != 1)) {
 		/* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n",
-				tce, entry << IOMMU_PAGE_SHIFT, ret); */
+				tce, entry << IOMMU_PAGE_SHIFT_4K, ret); */
 		return -EFAULT;
 	}
 	hwaddr = (unsigned long) page_address(page) + offset;
@@ -1067,7 +1067,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 
 	if (ret < 0)
 		pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n",
-				__func__, entry << IOMMU_PAGE_SHIFT, tce, ret);
+			__func__, entry << IOMMU_PAGE_SHIFT_4K, tce, ret);
 
 	return ret;
 }
@@ -1164,7 +1164,7 @@ static int __init tce_iommu_init(void)
 {
 	struct pci_dev *pdev = NULL;
 
-	BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
+	BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE_4K);
 
 	for_each_pci_dev(pdev)
 		iommu_add_device(&pdev->dev);
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index d38cc08..a93e501 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -520,14 +520,14 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
 	struct vio_dev *viodev = to_vio_dev(dev);
 	dma_addr_t ret = DMA_ERROR_CODE;
 
-	if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE))) {
+	if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K))) {
 		atomic_inc(&viodev->cmo.allocs_failed);
 		return ret;
 	}
 
 	ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs);
 	if (unlikely(dma_mapping_error(dev, ret))) {
-		vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE));
+		vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K));
 		atomic_inc(&viodev->cmo.allocs_failed);
 	}
 
@@ -543,7 +543,7 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
 
 	dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs);
 
-	vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE));
+	vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K));
 }
 
 static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
@@ -556,7 +556,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 	size_t alloc_size = 0;
 
 	for (sgl = sglist; count < nelems; count++, sgl++)
-		alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE);
+		alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE_4K);
 
 	if (vio_cmo_alloc(viodev, alloc_size)) {
 		atomic_inc(&viodev->cmo.allocs_failed);
@@ -572,7 +572,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 	}
 
 	for (sgl = sglist, count = 0; count < ret; count++, sgl++)
-		alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE);
+		alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE_4K);
 	if (alloc_size)
 		vio_cmo_dealloc(viodev, alloc_size);
 
@@ -590,7 +590,7 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
 	int count = 0;
 
 	for (sgl = sglist; count < nelems; count++, sgl++)
-		alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE);
+		alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE_4K);
 
 	dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs);
 
@@ -736,7 +736,8 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
 			return -EINVAL;
 		}
 
-		viodev->cmo.desired = IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev));
+		viodev->cmo.desired =
+			IOMMU_PAGE_ALIGN_4K(viodrv->get_desired_dma(viodev));
 		if (viodev->cmo.desired < VIO_CMO_MIN_ENT)
 			viodev->cmo.desired = VIO_CMO_MIN_ENT;
 		size = VIO_CMO_MIN_ENT;
@@ -1170,9 +1171,9 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
 			    &tbl->it_index, &offset, &size);
 
 	/* TCE table size - measured in tce entries */
-	tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+	tbl->it_size = size >> IOMMU_PAGE_SHIFT_4K;
 	/* offset for VIO should always be 0 */
-	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
+	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT_4K;
 	tbl->it_busno = 0;
 	tbl->it_type = TCE_VB;
 	tbl->it_blocksize = 16;
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index a28d3b5..78b231c 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -452,7 +452,7 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
 {
 	tbl->it_blocksize = 16;
 	tbl->it_base = (unsigned long)tce_mem;
-	tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT;
+	tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT_4K;
 	tbl->it_index = 0;
 	tbl->it_size = tce_size >> 3;
 	tbl->it_busno = 0;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 0307901..007c21f 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -487,7 +487,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
 	tbl->it_busno = phb->bus->number;
 
 	/* Units of tce entries */
-	tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT;
+	tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT_4K;
 
 	/* Test if we are going over 2GB of DMA space */
 	if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
@@ -498,7 +498,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
 	phb->dma_window_base_cur += phb->dma_window_size;
 
 	/* Set the tce table size - measured in entries */
-	tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT;
+	tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT_4K;
 
 	tbl->it_index = 0;
 	tbl->it_blocksize = 16;
@@ -539,8 +539,8 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
 	tbl->it_base   = 0;
 	tbl->it_blocksize  = 16;
 	tbl->it_type = TCE_PCI;
-	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
-	tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_size = size >> IOMMU_PAGE_SHIFT_4K;
 }
 
 static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 1f97e2b..17d6f8a 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -72,7 +72,7 @@
 
 int CMO_PrPSP = -1;
 int CMO_SecPSP = -1;
-unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT);
+unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K);
 EXPORT_SYMBOL(CMO_PageSize);
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
@@ -543,7 +543,7 @@ void pSeries_cmo_feature_init(void)
 {
 	char *ptr, *key, *value, *end;
 	int call_status;
-	int page_order = IOMMU_PAGE_SHIFT;
+	int page_order = IOMMU_PAGE_SHIFT_4K;
 
 	pr_debug(" -> fw_cmo_feature_init()\n");
 	spin_lock(&rtas_data_buf_lock);
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 5d41aee..eef362d 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1282,24 +1282,25 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
 
 	/* netdev inits at probe time along with the structures we need below*/
 	if (netdev == NULL)
-		return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT);
+		return IOMMU_PAGE_ALIGN_4K(IBMVETH_IO_ENTITLEMENT_DEFAULT);
 
 	adapter = netdev_priv(netdev);
 
 	ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
-	ret += IOMMU_PAGE_ALIGN(netdev->mtu);
+	ret += IOMMU_PAGE_ALIGN_4K(netdev->mtu);
 
 	for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
 		/* add the size of the active receive buffers */
 		if (adapter->rx_buff_pool[i].active)
 			ret +=
 			    adapter->rx_buff_pool[i].size *
-			    IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].
+			    IOMMU_PAGE_ALIGN_4K(adapter->rx_buff_pool[i].
 			            buff_size);
 		rxqentries += adapter->rx_buff_pool[i].size;
 	}
 	/* add the size of the receive queue entries */
-	ret += IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry));
+	ret += IOMMU_PAGE_ALIGN_4K(
+		rxqentries * sizeof(struct ibmveth_rx_q_entry));
 
 	return ret;
 }
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 2/3] powerpc iommu: Add it_page_shift field to determine iommu page size
From: Alistair Popple @ 2013-11-11  4:22 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple
In-Reply-To: <1384143729-14491-1-git-send-email-alistair@popple.id.au>

This patch adds a it_page_shift field to struct iommu_table and
initiliases it to 4K for all platforms.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/include/asm/iommu.h       |    1 +
 arch/powerpc/kernel/vio.c              |    5 +++--
 arch/powerpc/platforms/cell/iommu.c    |   14 ++++++++------
 arch/powerpc/platforms/powernv/pci.c   |    3 ++-
 arch/powerpc/platforms/pseries/iommu.c |   10 ++++++----
 5 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index e53de39..706073a 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -76,6 +76,7 @@ struct iommu_table {
 	struct iommu_pool large_pool;
 	struct iommu_pool pools[IOMMU_NR_POOLS];
 	unsigned long *it_map;       /* A simple allocation bitmap for now */
+	unsigned long  it_page_shift;/* table iommu page size */
 #ifdef CONFIG_IOMMU_API
 	struct iommu_group *it_group;
 #endif
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a93e501..30c1cf5 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -1171,9 +1171,10 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
 			    &tbl->it_index, &offset, &size);
 
 	/* TCE table size - measured in tce entries */
-	tbl->it_size = size >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
+	tbl->it_size = size >> tbl->it_page_shift;
 	/* offset for VIO should always be 0 */
-	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_offset = offset >> tbl->it_page_shift;
 	tbl->it_busno = 0;
 	tbl->it_type = TCE_VB;
 	tbl->it_blocksize = 16;
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index b535606..2b90ff8 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -197,7 +197,7 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
 
 	io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
 
-	for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
+	for (i = 0; i < npages; i++, uaddr += tbl->it_page_shift)
 		io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask);
 
 	mb();
@@ -430,7 +430,7 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
 {
 	cell_iommu_setup_stab(iommu, base, size, 0, 0);
 	iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size, 0, 0,
-					    IOMMU_PAGE_SHIFT);
+					    IOMMU_PAGE_SHIFT_4K);
 	cell_iommu_enable_hardware(iommu);
 }
 
@@ -487,8 +487,10 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
 	window->table.it_blocksize = 16;
 	window->table.it_base = (unsigned long)iommu->ptab;
 	window->table.it_index = iommu->nid;
-	window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset;
-	window->table.it_size = size >> IOMMU_PAGE_SHIFT;
+	window->table.it_page_shift = IOMMU_PAGE_SHIFT_4K;
+	window->table.it_offset =
+		(offset >> window->table.it_page_shift) + pte_offset;
+	window->table.it_size = size >> window->table.it_page_shift;
 
 	iommu_init_table(&window->table, iommu->nid);
 
@@ -773,7 +775,7 @@ static void __init cell_iommu_init_one(struct device_node *np,
 
 	/* Setup the iommu_table */
 	cell_iommu_setup_window(iommu, np, base, size,
-				offset >> IOMMU_PAGE_SHIFT);
+				offset >> IOMMU_PAGE_SHIFT_4K);
 }
 
 static void __init cell_disable_iommus(void)
@@ -1122,7 +1124,7 @@ static int __init cell_iommu_fixed_mapping_init(void)
 
 		cell_iommu_setup_stab(iommu, dbase, dsize, fbase, fsize);
 		iommu->ptab = cell_iommu_alloc_ptab(iommu, dbase, dsize, 0, 0,
-						    IOMMU_PAGE_SHIFT);
+						    IOMMU_PAGE_SHIFT_4K);
 		cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize,
 					     fbase, fsize);
 		cell_iommu_enable_hardware(iommu);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 78b231c..cfab147 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -452,7 +452,8 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
 {
 	tbl->it_blocksize = 16;
 	tbl->it_base = (unsigned long)tce_mem;
-	tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
+	tbl->it_offset = dma_offset >> tbl->it_page_shift;
 	tbl->it_index = 0;
 	tbl->it_size = tce_size >> 3;
 	tbl->it_busno = 0;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 007c21f..6a43f2d 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -485,9 +485,10 @@ static void iommu_table_setparms(struct pci_controller *phb,
 		memset((void *)tbl->it_base, 0, *sizep);
 
 	tbl->it_busno = phb->bus->number;
+	tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
 
 	/* Units of tce entries */
-	tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_offset = phb->dma_window_base_cur >> tbl->it_page_shift;
 
 	/* Test if we are going over 2GB of DMA space */
 	if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
@@ -498,7 +499,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
 	phb->dma_window_base_cur += phb->dma_window_size;
 
 	/* Set the tce table size - measured in entries */
-	tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_size = phb->dma_window_size >> tbl->it_page_shift;
 
 	tbl->it_index = 0;
 	tbl->it_blocksize = 16;
@@ -536,11 +537,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
 	of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
 
 	tbl->it_busno = phb->bus->number;
+	tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
 	tbl->it_base   = 0;
 	tbl->it_blocksize  = 16;
 	tbl->it_type = TCE_PCI;
-	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT_4K;
-	tbl->it_size = size >> IOMMU_PAGE_SHIFT_4K;
+	tbl->it_offset = offset >> tbl->it_page_shift;
+	tbl->it_size = size >> tbl->it_page_shift;
 }
 
 static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 3/3] powerpc iommu: Update the generic code to use dynamic iommu page sizes
From: Alistair Popple @ 2013-11-11  4:22 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple
In-Reply-To: <1384143729-14491-1-git-send-email-alistair@popple.id.au>

This patch updates the generic iommu backend code to use the
it_page_shift field to determine the iommu page size instead of
using hardcoded values.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/include/asm/iommu.h   |   19 +++++---
 arch/powerpc/kernel/dma-iommu.c    |    4 +-
 arch/powerpc/kernel/iommu.c        |   90 +++++++++++++++++++-----------------
 arch/powerpc/kernel/vio.c          |   25 +++++++---
 drivers/net/ethernet/ibm/ibmveth.c |   15 +++---
 5 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 706073a..8032c71 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -35,17 +35,14 @@
 #define IOMMU_PAGE_MASK_4K       (~((1 << IOMMU_PAGE_SHIFT_4K) - 1))
 #define IOMMU_PAGE_ALIGN_4K(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE_4K)
 
+#define IOMMU_PAGE_SIZE(tblptr) (ASM_CONST(1) << (tblptr)->it_page_shift)
+#define IOMMU_PAGE_MASK(tblptr) (~((1 << (tblptr)->it_page_shift) - 1))
+#define IOMMU_PAGE_ALIGN(addr, tblptr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE(tblptr))
+
 /* Boot time flags */
 extern int iommu_is_off;
 extern int iommu_force_on;
 
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
-{
-	return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT_4K) + 1;
-}
-
-
 /*
  * IOMAP_MAX_ORDER defines the largest contiguous block
  * of dma space we can get.  IOMAP_MAX_ORDER = 13
@@ -82,6 +79,14 @@ struct iommu_table {
 #endif
 };
 
+/* Pure 2^n version of get_order */
+static inline __attribute_const__
+int get_iommu_order(unsigned long size, struct iommu_table *tbl)
+{
+	return __ilog2((size - 1) >> tbl->it_page_shift) + 1;
+}
+
+
 struct scatterlist;
 
 static inline void set_iommu_table_base(struct device *dev, void *base)
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index 5cfe3db..54d0116 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -83,10 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
 		return 0;
 	}
 
-	if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT_4K)) {
+	if (tbl->it_offset > (mask >> tbl->it_page_shift)) {
 		dev_info(dev, "Warning: IOMMU offset too big for device mask\n");
 		dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n",
-				mask, tbl->it_offset << IOMMU_PAGE_SHIFT_4K);
+				mask, tbl->it_offset << tbl->it_page_shift);
 		return 0;
 	} else
 		return 1;
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 6bc5d14..10dc7c5 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -251,14 +251,13 @@ again:
 
 	if (dev)
 		boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
-				      1 << IOMMU_PAGE_SHIFT_4K);
+				      1 << tbl->it_page_shift);
 	else
-		boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT_4K);
+		boundary_size = ALIGN(1UL << 32, 1 << tbl->it_page_shift);
 	/* 4GB boundary for iseries_hv_alloc and iseries_hv_map */
 
-	n = iommu_area_alloc(tbl->it_map, limit, start, npages,
-			tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT_4K,
-			align_mask);
+	n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset,
+			     boundary_size >> tbl->it_page_shift, align_mask);
 	if (n == -1) {
 		if (likely(pass == 0)) {
 			/* First try the pool from the start */
@@ -320,12 +319,12 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
 		return DMA_ERROR_CODE;
 
 	entry += tbl->it_offset;	/* Offset into real TCE table */
-	ret = entry << IOMMU_PAGE_SHIFT_4K;	/* Set the return dma address */
+	ret = entry << tbl->it_page_shift;	/* Set the return dma address */
 
 	/* Put the TCEs in the HW table */
 	build_fail = ppc_md.tce_build(tbl, entry, npages,
-				(unsigned long)page & IOMMU_PAGE_MASK_4K,
-				direction, attrs);
+				      (unsigned long)page &
+				      IOMMU_PAGE_MASK(tbl), direction, attrs);
 
 	/* ppc_md.tce_build() only returns non-zero for transient errors.
 	 * Clean up the table bitmap in this case and return
@@ -352,7 +351,7 @@ static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr,
 {
 	unsigned long entry, free_entry;
 
-	entry = dma_addr >> IOMMU_PAGE_SHIFT_4K;
+	entry = dma_addr >> tbl->it_page_shift;
 	free_entry = entry - tbl->it_offset;
 
 	if (((free_entry + npages) > tbl->it_size) ||
@@ -401,7 +400,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 	unsigned long flags;
 	struct iommu_pool *pool;
 
-	entry = dma_addr >> IOMMU_PAGE_SHIFT_4K;
+	entry = dma_addr >> tbl->it_page_shift;
 	free_entry = entry - tbl->it_offset;
 
 	pool = get_pool(tbl, free_entry);
@@ -468,13 +467,13 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 		}
 		/* Allocate iommu entries for that segment */
 		vaddr = (unsigned long) sg_virt(s);
-		npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE_4K);
+		npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE(tbl));
 		align = 0;
-		if (IOMMU_PAGE_SHIFT_4K < PAGE_SHIFT && slen >= PAGE_SIZE &&
+		if (tbl->it_page_shift < PAGE_SHIFT && slen >= PAGE_SIZE &&
 		    (vaddr & ~PAGE_MASK) == 0)
-			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT_4K;
+			align = PAGE_SHIFT - tbl->it_page_shift;
 		entry = iommu_range_alloc(dev, tbl, npages, &handle,
-					  mask >> IOMMU_PAGE_SHIFT_4K, align);
+					  mask >> tbl->it_page_shift, align);
 
 		DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
@@ -489,16 +488,16 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 
 		/* Convert entry to a dma_addr_t */
 		entry += tbl->it_offset;
-		dma_addr = entry << IOMMU_PAGE_SHIFT_4K;
-		dma_addr |= (s->offset & ~IOMMU_PAGE_MASK_4K);
+		dma_addr = entry << tbl->it_page_shift;
+		dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl));
 
 		DBG("  - %lu pages, entry: %lx, dma_addr: %lx\n",
 			    npages, entry, dma_addr);
 
 		/* Insert into HW table */
 		build_fail = ppc_md.tce_build(tbl, entry, npages,
-					vaddr & IOMMU_PAGE_MASK_4K,
-					direction, attrs);
+					      vaddr & IOMMU_PAGE_MASK(tbl),
+					      direction, attrs);
 		if(unlikely(build_fail))
 			goto failure;
 
@@ -559,9 +558,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 		if (s->dma_length != 0) {
 			unsigned long vaddr, npages;
 
-			vaddr = s->dma_address & IOMMU_PAGE_MASK_4K;
+			vaddr = s->dma_address & IOMMU_PAGE_MASK(tbl);
 			npages = iommu_num_pages(s->dma_address, s->dma_length,
-						 IOMMU_PAGE_SIZE_4K);
+						 IOMMU_PAGE_SIZE(tbl));
 			__iommu_free(tbl, vaddr, npages);
 			s->dma_address = DMA_ERROR_CODE;
 			s->dma_length = 0;
@@ -592,7 +591,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 		if (sg->dma_length == 0)
 			break;
 		npages = iommu_num_pages(dma_handle, sg->dma_length,
-					 IOMMU_PAGE_SIZE_4K);
+					 IOMMU_PAGE_SIZE(tbl));
 		__iommu_free(tbl, dma_handle, npages);
 		sg = sg_next(sg);
 	}
@@ -676,7 +675,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 		set_bit(0, tbl->it_map);
 
 	/* We only split the IOMMU table if we have 1GB or more of space */
-	if ((tbl->it_size << IOMMU_PAGE_SHIFT_4K) >= (1UL * 1024 * 1024 * 1024))
+	if ((tbl->it_size << tbl->it_page_shift) >= (1UL * 1024 * 1024 * 1024))
 		tbl->nr_pools = IOMMU_NR_POOLS;
 	else
 		tbl->nr_pools = 1;
@@ -768,16 +767,16 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 
 	vaddr = page_address(page) + offset;
 	uaddr = (unsigned long)vaddr;
-	npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE_4K);
+	npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl));
 
 	if (tbl) {
 		align = 0;
-		if (IOMMU_PAGE_SHIFT_4K < PAGE_SHIFT && size >= PAGE_SIZE &&
+		if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE &&
 		    ((unsigned long)vaddr & ~PAGE_MASK) == 0)
-			align = PAGE_SHIFT - IOMMU_PAGE_SHIFT_4K;
+			align = PAGE_SHIFT - tbl->it_page_shift;
 
 		dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
-					 mask >> IOMMU_PAGE_SHIFT_4K, align,
+					 mask >> tbl->it_page_shift, align,
 					 attrs);
 		if (dma_handle == DMA_ERROR_CODE) {
 			if (printk_ratelimit())  {
@@ -786,7 +785,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 					 npages);
 			}
 		} else
-			dma_handle |= (uaddr & ~IOMMU_PAGE_MASK_4K);
+			dma_handle |= (uaddr & ~IOMMU_PAGE_MASK(tbl));
 	}
 
 	return dma_handle;
@@ -801,7 +800,8 @@ void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
 	BUG_ON(direction == DMA_NONE);
 
 	if (tbl) {
-		npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE_4K);
+		npages = iommu_num_pages(dma_handle, size,
+					 IOMMU_PAGE_SIZE(tbl));
 		iommu_free(tbl, dma_handle, npages);
 	}
 }
@@ -845,10 +845,10 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
 	memset(ret, 0, size);
 
 	/* Set up tces to cover the allocated range */
-	nio_pages = size >> IOMMU_PAGE_SHIFT_4K;
-	io_order = get_iommu_order(size);
+	nio_pages = size >> tbl->it_page_shift;
+	io_order = get_iommu_order(size, tbl);
 	mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
-			      mask >> IOMMU_PAGE_SHIFT_4K, io_order, NULL);
+			      mask >> tbl->it_page_shift, io_order, NULL);
 	if (mapping == DMA_ERROR_CODE) {
 		free_pages((unsigned long)ret, order);
 		return NULL;
@@ -864,7 +864,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 		unsigned int nio_pages;
 
 		size = PAGE_ALIGN(size);
-		nio_pages = size >> IOMMU_PAGE_SHIFT_4K;
+		nio_pages = size >> tbl->it_page_shift;
 		iommu_free(tbl, dma_handle, nio_pages);
 		size = PAGE_ALIGN(size);
 		free_pages((unsigned long)vaddr, get_order(size));
@@ -935,10 +935,10 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl,
 	if (tce_value)
 		return -EINVAL;
 
-	if (ioba & ~IOMMU_PAGE_MASK_4K)
+	if (ioba & ~IOMMU_PAGE_MASK(tbl))
 		return -EINVAL;
 
-	ioba >>= IOMMU_PAGE_SHIFT_4K;
+	ioba >>= tbl->it_page_shift;
 	if (ioba < tbl->it_offset)
 		return -EINVAL;
 
@@ -955,13 +955,13 @@ int iommu_tce_put_param_check(struct iommu_table *tbl,
 	if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ)))
 		return -EINVAL;
 
-	if (tce & ~(IOMMU_PAGE_MASK_4K | TCE_PCI_WRITE | TCE_PCI_READ))
+	if (tce & ~(IOMMU_PAGE_MASK(tbl) | TCE_PCI_WRITE | TCE_PCI_READ))
 		return -EINVAL;
 
-	if (ioba & ~IOMMU_PAGE_MASK_4K)
+	if (ioba & ~IOMMU_PAGE_MASK(tbl))
 		return -EINVAL;
 
-	ioba >>= IOMMU_PAGE_SHIFT_4K;
+	ioba >>= tbl->it_page_shift;
 	if (ioba < tbl->it_offset)
 		return -EINVAL;
 
@@ -1037,7 +1037,7 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
 
 	/* if (unlikely(ret))
 		pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n",
-				__func__, hwaddr, entry << IOMMU_PAGE_SHIFT_4K,
+			__func__, hwaddr, entry << IOMMU_PAGE_SHIFT(tbl),
 				hwaddr, ret); */
 
 	return ret;
@@ -1049,14 +1049,14 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 {
 	int ret;
 	struct page *page = NULL;
-	unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK_4K & ~PAGE_MASK;
+	unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
 	enum dma_data_direction direction = iommu_tce_direction(tce);
 
 	ret = get_user_pages_fast(tce & PAGE_MASK, 1,
 			direction != DMA_TO_DEVICE, &page);
 	if (unlikely(ret != 1)) {
 		/* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n",
-				tce, entry << IOMMU_PAGE_SHIFT_4K, ret); */
+				tce, entry << IOMMU_PAGE_SHIFT(tbl), ret); */
 		return -EFAULT;
 	}
 	hwaddr = (unsigned long) page_address(page) + offset;
@@ -1067,7 +1067,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 
 	if (ret < 0)
 		pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n",
-			__func__, entry << IOMMU_PAGE_SHIFT_4K, tce, ret);
+			__func__, entry << tbl->it_page_shift, tce, ret);
 
 	return ret;
 }
@@ -1127,6 +1127,12 @@ static int iommu_add_device(struct device *dev)
 	pr_debug("iommu_tce: adding %s to iommu group %d\n",
 			dev_name(dev), iommu_group_id(tbl->it_group));
 
+	if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) {
+		pr_err("iommu_tce: unsupported iommu page size.");
+		pr_err("%s has not been added\n", dev_name(dev));
+		return -EINVAL;
+	}
+
 	ret = iommu_group_add_device(tbl->it_group, dev);
 	if (ret < 0)
 		pr_err("iommu_tce: %s has not been added, ret=%d\n",
@@ -1164,8 +1170,6 @@ static int __init tce_iommu_init(void)
 {
 	struct pci_dev *pdev = NULL;
 
-	BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE_4K);
-
 	for_each_pci_dev(pdev)
 		iommu_add_device(&pdev->dev);
 
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 30c1cf5..9d70402 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -518,16 +518,18 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
                                          struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
+	struct iommu_table *tbl;
 	dma_addr_t ret = DMA_ERROR_CODE;
 
-	if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K))) {
+	tbl = get_iommu_table_base(dev);
+	if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) {
 		atomic_inc(&viodev->cmo.allocs_failed);
 		return ret;
 	}
 
 	ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs);
 	if (unlikely(dma_mapping_error(dev, ret))) {
-		vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K));
+		vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
 		atomic_inc(&viodev->cmo.allocs_failed);
 	}
 
@@ -540,10 +542,12 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
 				     struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
+	struct iommu_table *tbl;
 
+	tbl = get_iommu_table_base(dev);
 	dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs);
 
-	vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE_4K));
+	vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
 }
 
 static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
@@ -551,12 +555,14 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                                 struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
+	struct iommu_table *tbl;
 	struct scatterlist *sgl;
 	int ret, count = 0;
 	size_t alloc_size = 0;
 
+	tbl = get_iommu_table_base(dev);
 	for (sgl = sglist; count < nelems; count++, sgl++)
-		alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE_4K);
+		alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl));
 
 	if (vio_cmo_alloc(viodev, alloc_size)) {
 		atomic_inc(&viodev->cmo.allocs_failed);
@@ -572,7 +578,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 	}
 
 	for (sgl = sglist, count = 0; count < ret; count++, sgl++)
-		alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE_4K);
+		alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
 	if (alloc_size)
 		vio_cmo_dealloc(viodev, alloc_size);
 
@@ -585,12 +591,14 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
 		struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
+	struct iommu_table *tbl;
 	struct scatterlist *sgl;
 	size_t alloc_size = 0;
 	int count = 0;
 
+	tbl = get_iommu_table_base(dev);
 	for (sgl = sglist; count < nelems; count++, sgl++)
-		alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE_4K);
+		alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
 
 	dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs);
 
@@ -706,11 +714,14 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
 {
 	struct vio_cmo_dev_entry *dev_ent;
 	struct device *dev = &viodev->dev;
+	struct iommu_table *tbl;
 	struct vio_driver *viodrv = to_vio_driver(dev->driver);
 	unsigned long flags;
 	size_t size;
 	bool dma_capable = false;
 
+	tbl = get_iommu_table_base(dev);
+
 	/* A device requires entitlement if it has a DMA window property */
 	switch (viodev->family) {
 	case VDEVICE:
@@ -737,7 +748,7 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
 		}
 
 		viodev->cmo.desired =
-			IOMMU_PAGE_ALIGN_4K(viodrv->get_desired_dma(viodev));
+			IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev), tbl);
 		if (viodev->cmo.desired < VIO_CMO_MIN_ENT)
 			viodev->cmo.desired = VIO_CMO_MIN_ENT;
 		size = VIO_CMO_MIN_ENT;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index eef362d..e7dfb81 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1276,31 +1276,34 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
 {
 	struct net_device *netdev = dev_get_drvdata(&vdev->dev);
 	struct ibmveth_adapter *adapter;
+	struct iommu_table *tbl;
 	unsigned long ret;
 	int i;
 	int rxqentries = 1;
 
+	tbl = get_iommu_table_base(&vdev->dev);
+
 	/* netdev inits at probe time along with the structures we need below*/
 	if (netdev == NULL)
-		return IOMMU_PAGE_ALIGN_4K(IBMVETH_IO_ENTITLEMENT_DEFAULT);
+		return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT, tbl);
 
 	adapter = netdev_priv(netdev);
 
 	ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
-	ret += IOMMU_PAGE_ALIGN_4K(netdev->mtu);
+	ret += IOMMU_PAGE_ALIGN(netdev->mtu, tbl);
 
 	for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
 		/* add the size of the active receive buffers */
 		if (adapter->rx_buff_pool[i].active)
 			ret +=
 			    adapter->rx_buff_pool[i].size *
-			    IOMMU_PAGE_ALIGN_4K(adapter->rx_buff_pool[i].
-			            buff_size);
+			    IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].
+					     buff_size, tbl);
 		rxqentries += adapter->rx_buff_pool[i].size;
 	}
 	/* add the size of the receive queue entries */
-	ret += IOMMU_PAGE_ALIGN_4K(
-		rxqentries * sizeof(struct ibmveth_rx_q_entry));
+	ret += IOMMU_PAGE_ALIGN(
+		rxqentries * sizeof(struct ibmveth_rx_q_entry), tbl);
 
 	return ret;
 }
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v8 0/7] POWER/cpuidle: Generic POWERPC-BOOK3S cpuidle driver enabled for PSERIES and POWERNV platforms
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood

This patch series consolidates the backend cpuidle driver for pSeries
and powernv platforms with minimal code duplication.

Current existing backend driver for pseries has been moved to drivers/cpuidle 
and has been extended to accommodate powernv idle power mgmt states. 
As seen in V1 of this patch series, having a separate powernv backend driver 
results in too much code duplication, which is less elegant and can pose 
maintenance problems going further.

Using the cpuidle framework to exploit platform low power idle states
management can take advantage of advanced heuristics, tunables and features 
provided by framework. The statistics and tracing infrastructure provided 
by the cpuidle framework also helps in enabling power management 
related tools and help tune the system and applications.

Earlier in 3.3 kernel, pSeries idle state management was modified to 
exploit the cpuidle framework and the end goal of this patch is to have powernv
platform also to hook its idle states into cpuidle framework with minimal 
code duplication between both platforms.  

This series aims to maintain compatibility and functionality to existing pseries 
and powernv idle cpu management code. There are no new functions or idle 
states added as part of this series. This can be extended by adding more 
states to this existing framework.

With this patch series, the powernv cpuidle functionalities are on-par with 
pSeries idle management.  

V1 -> http://lkml.org/lkml/2013/7/23/143
V2 -> https://lkml.org/lkml/2013/7/30/872
V3 -> http://comments.gmane.org/gmane.linux.ports.ppc.embedded/63093 
V4 -> https://lkml.org/lkml/2013/8/22/25
V5 -> http://lkml.org/lkml/2013/8/22/184
V6 -> https://lkml.org/lkml/2013/8/27/432 
v7 -> https://lkml.org/lkml/2013/10/29/216

Changes in V8:
============
* Renaming driver and related files from
  ibm-power-idle to powerpc-book3s-idle
  for clarity and to avoid confusing between ibm-power
  systems and power mgmt.

Changes in V7:
============
* Rebased to the latest kernel 3.12-rc7

* Default idle routine to be called on POWERNV
  is power7_idle() instead of HMT_low() routines.

Changes in V6:
=============
* Made changes in Patch3: Generic POWER cpuidle driver in V5 by
  breaking down to multiple patches, as there were multiple changes
  including moving the file location.

* Remove MAX_IDLE_STATE macro and kernel command line for
  IBM-POWER systems.

* Make backend driver a built-in, instead of a module.
  As building this as a module is currently not possible. 

* Generic backend driver minor cleanups.

* First two patches in V5 are not a part of the series, as
  they are generic cleanups, already pushed into the tree.

Changes in V5:
=============

* As per the discussions in the community, this patch series
  enables cpuidle backend driver only for IBM-POWER 
  platforms. File is re-named from drivers/cpuidle/cpuidle-powerpc.c
  to drivers/cpuidle/cpuildle-ibm-power.c
  New back-end cpuidle driver is called IBM-POWER-Idle.

* General cleanups on the accessors front that was introduced in 
  previous version.

Changes in V4:
=============

* This patch series includes generic backend driver cpuidle cleanups 
  including, replacing the driver and device initialisation
  routines with cpuidle_register function.

* Enable CPUIDLE framework only for POWER and POWERNV platforms.

Changes in V3:
=============

* This patch series does not include smt-snooze-delay fixes. 
  This will be taken up later on.

* Integrated POWERPC driver in drivers/cpuidle.  Enabled for all of 
  POWERPC platform.  Currently has PSERIES and POWERNV support.
  No compile time flags in .c file. This  will be one consolidated 
  binary that does a run time detection based on platform and take 
  decisions accordingly.

* Enabled CPUIDLE framwork for all of PPC64.

Changes in V2:
=============

* Merged the backend driver posted out for powernv in V1 with
  pSeries to create a single powerpc driver but this had compile
  time flags.

 Deepthi Dharwar (7):
      pseries/cpuidle: Move processor_idle.c to drivers/cpuidle.
      pseries/cpuidle: Use cpuidle_register() for initialisation.
      pseries/cpuidle: Make pseries_idle backend driver a  non-module.
      pseries/cpuidle: Remove MAX_IDLE_STATE macro.
      POWER/cpuidle: Generic POWERPC-BOOK3S CPUIDLE driver supporting PSERIES.
      POWER/cpuidle: Enable powernv cpuidle support.
      powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.


 arch/powerpc/include/asm/processor.h            |    2 
 arch/powerpc/platforms/powernv/setup.c          |   13 +
 arch/powerpc/platforms/pseries/Kconfig          |    9 -
 arch/powerpc/platforms/pseries/Makefile         |    1 
 arch/powerpc/platforms/pseries/processor_idle.c |  364 -----------------------
 drivers/cpuidle/Kconfig                         |    5 
 drivers/cpuidle/Kconfig.powerpc                 |   10 +
 drivers/cpuidle/Makefile                        |    4 
 drivers/cpuidle/cpuidle-powerpc-book3s.c        |  320 ++++++++++++++++++++
 9 files changed, 352 insertions(+), 376 deletions(-)
 delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
 create mode 100644 drivers/cpuidle/Kconfig.powerpc
 create mode 100644 drivers/cpuidle/cpuidle-powerpc-book3s.c


-- Deepthi

^ permalink raw reply

* [PATCH v8 1/7] pseries/cpuidle: Move processor_idle.c to drivers/cpuidle.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

Move the file from arch specific pseries/processor_idle.c
to drivers/cpuidle/cpuidle-powerpc-book3s.c
Make the relevant Makefile and Kconfig changes.
This will enable having a common backend cpuidle driver
for POWERPC-BOOK3S platform going forward.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 arch/powerpc/include/asm/processor.h            |    2 
 arch/powerpc/platforms/pseries/Kconfig          |    9 -
 arch/powerpc/platforms/pseries/Makefile         |    1 
 arch/powerpc/platforms/pseries/processor_idle.c |  364 -----------------------
 drivers/cpuidle/Kconfig                         |    5 
 drivers/cpuidle/Kconfig.powerpc                 |   10 +
 drivers/cpuidle/Makefile                        |    4 
 drivers/cpuidle/cpuidle-powerpc-book3s.c        |  364 +++++++++++++++++++++++
 8 files changed, 384 insertions(+), 375 deletions(-)
 delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
 create mode 100644 drivers/cpuidle/Kconfig.powerpc
 create mode 100644 drivers/cpuidle/cpuidle-powerpc-book3s.c

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index ce4de5a..826360c 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -428,7 +428,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
 extern int powersave_nap;	/* set if nap mode can be used in idle loop */
 extern void power7_nap(void);
 
-#ifdef CONFIG_PSERIES_IDLE
+#ifdef CONFIG_CPU_IDLE_POWERPC_BOOK3S
 extern void update_smt_snooze_delay(int cpu, int residency);
 #else
 static inline void update_smt_snooze_delay(int cpu, int residency) {}
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 62b4f80..bb59bb0 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -119,12 +119,3 @@ config DTL
 	  which are accessible through a debugfs file.
 
 	  Say N if you are unsure.
-
-config PSERIES_IDLE
-	bool "Cpuidle driver for pSeries platforms"
-	depends on CPU_IDLE
-	depends on PPC_PSERIES
-	default y
-	help
-	  Select this option to enable processor idle state management
-	  through cpuidle subsystem.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 6c61ec5..6f2500b 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
 obj-$(CONFIG_CMM)		+= cmm.o
 obj-$(CONFIG_DTL)		+= dtl.o
 obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o
-obj-$(CONFIG_PSERIES_IDLE)	+= processor_idle.o
 obj-$(CONFIG_LPARCFG)		+= lparcfg.o
 
 ifeq ($(CONFIG_PPC_PSERIES),y)
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
deleted file mode 100644
index a166e38..0000000
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- *  processor_idle - idle state cpuidle driver.
- *  Adapted from drivers/idle/intel_idle.c and
- *  drivers/acpi/processor_idle.c
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/cpuidle.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-
-#include <asm/paca.h>
-#include <asm/reg.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/runlatch.h>
-#include <asm/plpar_wrappers.h>
-
-struct cpuidle_driver pseries_idle_driver = {
-	.name             = "pseries_idle",
-	.owner            = THIS_MODULE,
-};
-
-#define MAX_IDLE_STATE_COUNT	2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
-static struct cpuidle_device __percpu *pseries_cpuidle_devices;
-static struct cpuidle_state *cpuidle_state_table;
-
-static inline void idle_loop_prolog(unsigned long *in_purr)
-{
-	*in_purr = mfspr(SPRN_PURR);
-	/*
-	 * Indicate to the HV that we are idle. Now would be
-	 * a good time to find other work to dispatch.
-	 */
-	get_lppaca()->idle = 1;
-}
-
-static inline void idle_loop_epilog(unsigned long in_purr)
-{
-	u64 wait_cycles;
-
-	wait_cycles = be64_to_cpu(get_lppaca()->wait_state_cycles);
-	wait_cycles += mfspr(SPRN_PURR) - in_purr;
-	get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles);
-	get_lppaca()->idle = 0;
-}
-
-static int snooze_loop(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-			int index)
-{
-	unsigned long in_purr;
-	int cpu = dev->cpu;
-
-	idle_loop_prolog(&in_purr);
-	local_irq_enable();
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
-	while ((!need_resched()) && cpu_online(cpu)) {
-		ppc64_runlatch_off();
-		HMT_low();
-		HMT_very_low();
-	}
-
-	HMT_medium();
-	clear_thread_flag(TIF_POLLING_NRFLAG);
-	smp_mb();
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-static void check_and_cede_processor(void)
-{
-	/*
-	 * Ensure our interrupt state is properly tracked,
-	 * also checks if no interrupt has occurred while we
-	 * were soft-disabled
-	 */
-	if (prep_irq_for_idle()) {
-		cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
-		/* Ensure that H_CEDE returns with IRQs on */
-		if (WARN_ON(!(mfmsr() & MSR_EE)))
-			__hard_irq_enable();
-#endif
-	}
-}
-
-static int dedicated_cede_loop(struct cpuidle_device *dev,
-				struct cpuidle_driver *drv,
-				int index)
-{
-	unsigned long in_purr;
-
-	idle_loop_prolog(&in_purr);
-	get_lppaca()->donate_dedicated_cpu = 1;
-
-	ppc64_runlatch_off();
-	HMT_medium();
-	check_and_cede_processor();
-
-	get_lppaca()->donate_dedicated_cpu = 0;
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-static int shared_cede_loop(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-			int index)
-{
-	unsigned long in_purr;
-
-	idle_loop_prolog(&in_purr);
-
-	/*
-	 * Yield the processor to the hypervisor.  We return if
-	 * an external interrupt occurs (which are driven prior
-	 * to returning here) or if a prod occurs from another
-	 * processor. When returning here, external interrupts
-	 * are enabled.
-	 */
-	check_and_cede_processor();
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-/*
- * States for dedicated partition case.
- */
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
-	{ /* Snooze */
-		.name = "snooze",
-		.desc = "snooze",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 0,
-		.target_residency = 0,
-		.enter = &snooze_loop },
-	{ /* CEDE */
-		.name = "CEDE",
-		.desc = "CEDE",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 10,
-		.target_residency = 100,
-		.enter = &dedicated_cede_loop },
-};
-
-/*
- * States for shared partition case.
- */
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
-	{ /* Shared Cede */
-		.name = "Shared Cede",
-		.desc = "Shared Cede",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 0,
-		.target_residency = 0,
-		.enter = &shared_cede_loop },
-};
-
-void update_smt_snooze_delay(int cpu, int residency)
-{
-	struct cpuidle_driver *drv = cpuidle_get_driver();
-	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
-
-	if (cpuidle_state_table != dedicated_states)
-		return;
-
-	if (residency < 0) {
-		/* Disable the Nap state on that cpu */
-		if (dev)
-			dev->states_usage[1].disable = 1;
-	} else
-		if (drv)
-			drv->states[1].target_residency = residency;
-}
-
-static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
-			unsigned long action, void *hcpu)
-{
-	int hotcpu = (unsigned long)hcpu;
-	struct cpuidle_device *dev =
-			per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
-
-	if (dev && cpuidle_get_driver()) {
-		switch (action) {
-		case CPU_ONLINE:
-		case CPU_ONLINE_FROZEN:
-			cpuidle_pause_and_lock();
-			cpuidle_enable_device(dev);
-			cpuidle_resume_and_unlock();
-			break;
-
-		case CPU_DEAD:
-		case CPU_DEAD_FROZEN:
-			cpuidle_pause_and_lock();
-			cpuidle_disable_device(dev);
-			cpuidle_resume_and_unlock();
-			break;
-
-		default:
-			return NOTIFY_DONE;
-		}
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block setup_hotplug_notifier = {
-	.notifier_call = pseries_cpuidle_add_cpu_notifier,
-};
-
-/*
- * pseries_cpuidle_driver_init()
- */
-static int pseries_cpuidle_driver_init(void)
-{
-	int idle_state;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
-
-	drv->state_count = 0;
-
-	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
-
-		if (idle_state > max_idle_state)
-			break;
-
-		/* is the state not enabled? */
-		if (cpuidle_state_table[idle_state].enter == NULL)
-			continue;
-
-		drv->states[drv->state_count] =	/* structure copy */
-			cpuidle_state_table[idle_state];
-
-		drv->state_count += 1;
-	}
-
-	return 0;
-}
-
-/* pseries_idle_devices_uninit(void)
- * unregister cpuidle devices and de-allocate memory
- */
-static void pseries_idle_devices_uninit(void)
-{
-	int i;
-	struct cpuidle_device *dev;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		cpuidle_unregister_device(dev);
-	}
-
-	free_percpu(pseries_cpuidle_devices);
-	return;
-}
-
-/* pseries_idle_devices_init()
- * allocate, initialize and register cpuidle device
- */
-static int pseries_idle_devices_init(void)
-{
-	int i;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
-	struct cpuidle_device *dev;
-
-	pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
-	if (pseries_cpuidle_devices == NULL)
-		return -ENOMEM;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		dev->state_count = drv->state_count;
-		dev->cpu = i;
-		if (cpuidle_register_device(dev)) {
-			printk(KERN_DEBUG \
-				"cpuidle_register_device %d failed!\n", i);
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * pseries_idle_probe()
- * Choose state table for shared versus dedicated partition
- */
-static int pseries_idle_probe(void)
-{
-
-	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
-		return -ENODEV;
-
-	if (cpuidle_disable != IDLE_NO_OVERRIDE)
-		return -ENODEV;
-
-	if (max_idle_state == 0) {
-		printk(KERN_DEBUG "pseries processor idle disabled.\n");
-		return -EPERM;
-	}
-
-	if (lppaca_shared_proc(get_lppaca()))
-		cpuidle_state_table = shared_states;
-	else
-		cpuidle_state_table = dedicated_states;
-
-	return 0;
-}
-
-static int __init pseries_processor_idle_init(void)
-{
-	int retval;
-
-	retval = pseries_idle_probe();
-	if (retval)
-		return retval;
-
-	pseries_cpuidle_driver_init();
-	retval = cpuidle_register_driver(&pseries_idle_driver);
-	if (retval) {
-		printk(KERN_DEBUG "Registration of pseries driver failed.\n");
-		return retval;
-	}
-
-	retval = pseries_idle_devices_init();
-	if (retval) {
-		pseries_idle_devices_uninit();
-		cpuidle_unregister_driver(&pseries_idle_driver);
-		return retval;
-	}
-
-	register_cpu_notifier(&setup_hotplug_notifier);
-	printk(KERN_DEBUG "pseries_idle_driver registered\n");
-
-	return 0;
-}
-
-static void __exit pseries_processor_idle_exit(void)
-{
-
-	unregister_cpu_notifier(&setup_hotplug_notifier);
-	pseries_idle_devices_uninit();
-	cpuidle_unregister_driver(&pseries_idle_driver);
-
-	return;
-}
-
-module_init(pseries_processor_idle_init);
-module_exit(pseries_processor_idle_exit);
-
-MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("Cpuidle driver for POWER");
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index b3fb81d..f04e25f 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -35,6 +35,11 @@ depends on ARM
 source "drivers/cpuidle/Kconfig.arm"
 endmenu
 
+menu "POWERPC CPU Idle Drivers"
+depends on PPC
+source "drivers/cpuidle/Kconfig.powerpc"
+endmenu
+
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
new file mode 100644
index 0000000..689c0d4
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.powerpc
@@ -0,0 +1,10 @@
+#
+# POWERPC CPU Idle Drivers
+#
+config CPU_IDLE_POWERPC_BOOK3S
+	bool "CPU Idle driver for POWERPC-BOOK3S platforms"
+	depends on PPC_PSERIES
+	default y
+	help
+	Select this option to enable processor idle state management
+	on POWERPC-BOOK3S platform.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index cea5ef5..6adb81c 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -12,3 +12,7 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
 obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_CPU_IDLE_BIG_LITTLE)	+= cpuidle-big_little.o
+
+###############################################################################
+# POWERPC drivers
+obj-$(CONFIG_CPU_IDLE_POWERPC_BOOK3S) += cpuidle-powerpc-book3s.o
diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
new file mode 100644
index 0000000..a166e38
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -0,0 +1,364 @@
+/*
+ *  processor_idle - idle state cpuidle driver.
+ *  Adapted from drivers/idle/intel_idle.c and
+ *  drivers/acpi/processor_idle.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+
+#include <asm/paca.h>
+#include <asm/reg.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/runlatch.h>
+#include <asm/plpar_wrappers.h>
+
+struct cpuidle_driver pseries_idle_driver = {
+	.name             = "pseries_idle",
+	.owner            = THIS_MODULE,
+};
+
+#define MAX_IDLE_STATE_COUNT	2
+
+static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static struct cpuidle_device __percpu *pseries_cpuidle_devices;
+static struct cpuidle_state *cpuidle_state_table;
+
+static inline void idle_loop_prolog(unsigned long *in_purr)
+{
+	*in_purr = mfspr(SPRN_PURR);
+	/*
+	 * Indicate to the HV that we are idle. Now would be
+	 * a good time to find other work to dispatch.
+	 */
+	get_lppaca()->idle = 1;
+}
+
+static inline void idle_loop_epilog(unsigned long in_purr)
+{
+	u64 wait_cycles;
+
+	wait_cycles = be64_to_cpu(get_lppaca()->wait_state_cycles);
+	wait_cycles += mfspr(SPRN_PURR) - in_purr;
+	get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles);
+	get_lppaca()->idle = 0;
+}
+
+static int snooze_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	unsigned long in_purr;
+	int cpu = dev->cpu;
+
+	idle_loop_prolog(&in_purr);
+	local_irq_enable();
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
+	while ((!need_resched()) && cpu_online(cpu)) {
+		ppc64_runlatch_off();
+		HMT_low();
+		HMT_very_low();
+	}
+
+	HMT_medium();
+	clear_thread_flag(TIF_POLLING_NRFLAG);
+	smp_mb();
+
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+static void check_and_cede_processor(void)
+{
+	/*
+	 * Ensure our interrupt state is properly tracked,
+	 * also checks if no interrupt has occurred while we
+	 * were soft-disabled
+	 */
+	if (prep_irq_for_idle()) {
+		cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+		/* Ensure that H_CEDE returns with IRQs on */
+		if (WARN_ON(!(mfmsr() & MSR_EE)))
+			__hard_irq_enable();
+#endif
+	}
+}
+
+static int dedicated_cede_loop(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	unsigned long in_purr;
+
+	idle_loop_prolog(&in_purr);
+	get_lppaca()->donate_dedicated_cpu = 1;
+
+	ppc64_runlatch_off();
+	HMT_medium();
+	check_and_cede_processor();
+
+	get_lppaca()->donate_dedicated_cpu = 0;
+
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+static int shared_cede_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	unsigned long in_purr;
+
+	idle_loop_prolog(&in_purr);
+
+	/*
+	 * Yield the processor to the hypervisor.  We return if
+	 * an external interrupt occurs (which are driven prior
+	 * to returning here) or if a prod occurs from another
+	 * processor. When returning here, external interrupts
+	 * are enabled.
+	 */
+	check_and_cede_processor();
+
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+/*
+ * States for dedicated partition case.
+ */
+static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+	{ /* Snooze */
+		.name = "snooze",
+		.desc = "snooze",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &snooze_loop },
+	{ /* CEDE */
+		.name = "CEDE",
+		.desc = "CEDE",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 100,
+		.enter = &dedicated_cede_loop },
+};
+
+/*
+ * States for shared partition case.
+ */
+static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+	{ /* Shared Cede */
+		.name = "Shared Cede",
+		.desc = "Shared Cede",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &shared_cede_loop },
+};
+
+void update_smt_snooze_delay(int cpu, int residency)
+{
+	struct cpuidle_driver *drv = cpuidle_get_driver();
+	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
+
+	if (cpuidle_state_table != dedicated_states)
+		return;
+
+	if (residency < 0) {
+		/* Disable the Nap state on that cpu */
+		if (dev)
+			dev->states_usage[1].disable = 1;
+	} else
+		if (drv)
+			drv->states[1].target_residency = residency;
+}
+
+static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
+			unsigned long action, void *hcpu)
+{
+	int hotcpu = (unsigned long)hcpu;
+	struct cpuidle_device *dev =
+			per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
+
+	if (dev && cpuidle_get_driver()) {
+		switch (action) {
+		case CPU_ONLINE:
+		case CPU_ONLINE_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_enable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		case CPU_DEAD:
+		case CPU_DEAD_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_disable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		default:
+			return NOTIFY_DONE;
+		}
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block setup_hotplug_notifier = {
+	.notifier_call = pseries_cpuidle_add_cpu_notifier,
+};
+
+/*
+ * pseries_cpuidle_driver_init()
+ */
+static int pseries_cpuidle_driver_init(void)
+{
+	int idle_state;
+	struct cpuidle_driver *drv = &pseries_idle_driver;
+
+	drv->state_count = 0;
+
+	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
+
+		if (idle_state > max_idle_state)
+			break;
+
+		/* is the state not enabled? */
+		if (cpuidle_state_table[idle_state].enter == NULL)
+			continue;
+
+		drv->states[drv->state_count] =	/* structure copy */
+			cpuidle_state_table[idle_state];
+
+		drv->state_count += 1;
+	}
+
+	return 0;
+}
+
+/* pseries_idle_devices_uninit(void)
+ * unregister cpuidle devices and de-allocate memory
+ */
+static void pseries_idle_devices_uninit(void)
+{
+	int i;
+	struct cpuidle_device *dev;
+
+	for_each_possible_cpu(i) {
+		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
+		cpuidle_unregister_device(dev);
+	}
+
+	free_percpu(pseries_cpuidle_devices);
+	return;
+}
+
+/* pseries_idle_devices_init()
+ * allocate, initialize and register cpuidle device
+ */
+static int pseries_idle_devices_init(void)
+{
+	int i;
+	struct cpuidle_driver *drv = &pseries_idle_driver;
+	struct cpuidle_device *dev;
+
+	pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+	if (pseries_cpuidle_devices == NULL)
+		return -ENOMEM;
+
+	for_each_possible_cpu(i) {
+		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
+		dev->state_count = drv->state_count;
+		dev->cpu = i;
+		if (cpuidle_register_device(dev)) {
+			printk(KERN_DEBUG \
+				"cpuidle_register_device %d failed!\n", i);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * pseries_idle_probe()
+ * Choose state table for shared versus dedicated partition
+ */
+static int pseries_idle_probe(void)
+{
+
+	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+		return -ENODEV;
+
+	if (cpuidle_disable != IDLE_NO_OVERRIDE)
+		return -ENODEV;
+
+	if (max_idle_state == 0) {
+		printk(KERN_DEBUG "pseries processor idle disabled.\n");
+		return -EPERM;
+	}
+
+	if (lppaca_shared_proc(get_lppaca()))
+		cpuidle_state_table = shared_states;
+	else
+		cpuidle_state_table = dedicated_states;
+
+	return 0;
+}
+
+static int __init pseries_processor_idle_init(void)
+{
+	int retval;
+
+	retval = pseries_idle_probe();
+	if (retval)
+		return retval;
+
+	pseries_cpuidle_driver_init();
+	retval = cpuidle_register_driver(&pseries_idle_driver);
+	if (retval) {
+		printk(KERN_DEBUG "Registration of pseries driver failed.\n");
+		return retval;
+	}
+
+	retval = pseries_idle_devices_init();
+	if (retval) {
+		pseries_idle_devices_uninit();
+		cpuidle_unregister_driver(&pseries_idle_driver);
+		return retval;
+	}
+
+	register_cpu_notifier(&setup_hotplug_notifier);
+	printk(KERN_DEBUG "pseries_idle_driver registered\n");
+
+	return 0;
+}
+
+static void __exit pseries_processor_idle_exit(void)
+{
+
+	unregister_cpu_notifier(&setup_hotplug_notifier);
+	pseries_idle_devices_uninit();
+	cpuidle_unregister_driver(&pseries_idle_driver);
+
+	return;
+}
+
+module_init(pseries_processor_idle_init);
+module_exit(pseries_processor_idle_exit);
+
+MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Cpuidle driver for POWER");
+MODULE_LICENSE("GPL");

^ permalink raw reply related

* [PATCH v8 2/7] pseries/cpuidle: Use cpuidle_register() for initialisation.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

This patch replaces the cpuidle driver and devices initialisation
calls with a single generic cpuidle_register() call
and also includes minor refactoring of the code around it.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/cpuidle/cpuidle-powerpc-book3s.c |   80 +++++-------------------------
 1 file changed, 12 insertions(+), 68 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
index a166e38..51f6cda 100644
--- a/drivers/cpuidle/cpuidle-powerpc-book3s.c
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -1,5 +1,5 @@
 /*
- *  processor_idle - idle state cpuidle driver.
+ *  cpuidle-powerpc-book3s - idle state cpuidle driver.
  *  Adapted from drivers/idle/intel_idle.c and
  *  drivers/acpi/processor_idle.c
  *
@@ -28,7 +28,6 @@ struct cpuidle_driver pseries_idle_driver = {
 #define MAX_IDLE_STATE_COUNT	2
 
 static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
-static struct cpuidle_device __percpu *pseries_cpuidle_devices;
 static struct cpuidle_state *cpuidle_state_table;
 
 static inline void idle_loop_prolog(unsigned long *in_purr)
@@ -56,13 +55,12 @@ static int snooze_loop(struct cpuidle_device *dev,
 			int index)
 {
 	unsigned long in_purr;
-	int cpu = dev->cpu;
 
 	idle_loop_prolog(&in_purr);
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
-	while ((!need_resched()) && cpu_online(cpu)) {
+	while (!need_resched()) {
 		ppc64_runlatch_off();
 		HMT_low();
 		HMT_very_low();
@@ -191,7 +189,7 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
 {
 	int hotcpu = (unsigned long)hcpu;
 	struct cpuidle_device *dev =
-			per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
+			per_cpu(cpuidle_devices, hotcpu);
 
 	if (dev && cpuidle_get_driver()) {
 		switch (action) {
@@ -248,50 +246,6 @@ static int pseries_cpuidle_driver_init(void)
 	return 0;
 }
 
-/* pseries_idle_devices_uninit(void)
- * unregister cpuidle devices and de-allocate memory
- */
-static void pseries_idle_devices_uninit(void)
-{
-	int i;
-	struct cpuidle_device *dev;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		cpuidle_unregister_device(dev);
-	}
-
-	free_percpu(pseries_cpuidle_devices);
-	return;
-}
-
-/* pseries_idle_devices_init()
- * allocate, initialize and register cpuidle device
- */
-static int pseries_idle_devices_init(void)
-{
-	int i;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
-	struct cpuidle_device *dev;
-
-	pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
-	if (pseries_cpuidle_devices == NULL)
-		return -ENOMEM;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		dev->state_count = drv->state_count;
-		dev->cpu = i;
-		if (cpuidle_register_device(dev)) {
-			printk(KERN_DEBUG \
-				"cpuidle_register_device %d failed!\n", i);
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
 /*
  * pseries_idle_probe()
  * Choose state table for shared versus dedicated partition
@@ -299,9 +253,6 @@ static int pseries_idle_devices_init(void)
 static int pseries_idle_probe(void)
 {
 
-	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
-		return -ENODEV;
-
 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
 		return -ENODEV;
 
@@ -310,10 +261,13 @@ static int pseries_idle_probe(void)
 		return -EPERM;
 	}
 
-	if (lppaca_shared_proc(get_lppaca()))
-		cpuidle_state_table = shared_states;
-	else
-		cpuidle_state_table = dedicated_states;
+	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+		if (lppaca_shared_proc(get_lppaca()))
+			cpuidle_state_table = shared_states;
+		else
+			cpuidle_state_table = dedicated_states;
+	} else
+		return -ENODEV;
 
 	return 0;
 }
@@ -327,22 +281,14 @@ static int __init pseries_processor_idle_init(void)
 		return retval;
 
 	pseries_cpuidle_driver_init();
-	retval = cpuidle_register_driver(&pseries_idle_driver);
+	retval = cpuidle_register(&pseries_idle_driver, NULL);
 	if (retval) {
 		printk(KERN_DEBUG "Registration of pseries driver failed.\n");
 		return retval;
 	}
 
-	retval = pseries_idle_devices_init();
-	if (retval) {
-		pseries_idle_devices_uninit();
-		cpuidle_unregister_driver(&pseries_idle_driver);
-		return retval;
-	}
-
 	register_cpu_notifier(&setup_hotplug_notifier);
 	printk(KERN_DEBUG "pseries_idle_driver registered\n");
-
 	return 0;
 }
 
@@ -350,9 +296,7 @@ static void __exit pseries_processor_idle_exit(void)
 {
 
 	unregister_cpu_notifier(&setup_hotplug_notifier);
-	pseries_idle_devices_uninit();
-	cpuidle_unregister_driver(&pseries_idle_driver);
-
+	cpuidle_unregister(&pseries_idle_driver);
 	return;
 }
 

^ permalink raw reply related

* [PATCH v8 3/7] pseries/cpuidle: Make pseries_idle backend driver a non-module.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

Currently pseries_idle cpuidle backend driver cannot be
built as a module due to dependencies. Therefore the driver has
to be built in. The dependency is around update_snooze_delay() defined
in cpuidle driver and called from kernel/sysfs.c.
This patch is removes all the module related code.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/cpuidle/cpuidle-powerpc-book3s.c |   15 +--------------
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
index 51f6cda..82c9e15 100644
--- a/drivers/cpuidle/cpuidle-powerpc-book3s.c
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -292,17 +292,4 @@ static int __init pseries_processor_idle_init(void)
 	return 0;
 }
 
-static void __exit pseries_processor_idle_exit(void)
-{
-
-	unregister_cpu_notifier(&setup_hotplug_notifier);
-	cpuidle_unregister(&pseries_idle_driver);
-	return;
-}
-
-module_init(pseries_processor_idle_init);
-module_exit(pseries_processor_idle_exit);
-
-MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("Cpuidle driver for POWER");
-MODULE_LICENSE("GPL");
+device_initcall(pseries_processor_idle_init);

^ permalink raw reply related

* [PATCH] powerpc: add explicit OF includes for ppc4xx
From: Rob Herring @ 2013-11-11  5:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Herbert Xu, Vinod Koul, Rob Herring, linux-ide, Paul Mackerras,
	linux-crypto, Matt Mackall, Tejun Heo, Dan Williams, linuxppc-dev,
	David S. Miller

From: Rob Herring <rob.herring@calxeda.com>

Commit b5b4bb3f6a11f9 (of: only include prom.h on sparc) removed implicit
includes of of_*.h headers by powerpc's prom.h. Some PPC4xx components
were missed in initial clean-up patch, so add the necessary includes
to fix ppc4xx builds.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-ide@vger.kernel.org
Cc: linux-crypto@vger.kernel.org
---
I intend to send this patch to Linus with the rest of the DT clean-up
series.

Rob

 arch/powerpc/sysdev/ppc4xx_ocm.c     | 1 +
 arch/powerpc/sysdev/xilinx_intc.c    | 1 +
 drivers/ata/sata_dwc_460ex.c         | 2 ++
 drivers/char/hw_random/ppc4xx-rng.c  | 1 +
 drivers/crypto/amcc/crypto4xx_core.c | 3 +++
 drivers/dma/ppc4xx/adma.c            | 2 ++
 6 files changed, 10 insertions(+)

diff --git a/arch/powerpc/sysdev/ppc4xx_ocm.c b/arch/powerpc/sysdev/ppc4xx_ocm.c
index 1b15f93..b7c4345 100644
--- a/arch/powerpc/sysdev/ppc4xx_ocm.c
+++ b/arch/powerpc/sysdev/ppc4xx_ocm.c
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <asm/rheap.h>
 #include <asm/ppc4xx_ocm.h>
 #include <linux/slab.h>
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index f4fdc94..83f943a 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -24,6 +24,7 @@
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/i8259.h>
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 2e39173..523524b 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -31,6 +31,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/libata.h>
diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c
index 732c330..521f76b 100644
--- a/drivers/char/hw_random/ppc4xx-rng.c
+++ b/drivers/char/hw_random/ppc4xx-rng.c
@@ -13,6 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
 #include <linux/delay.h>
+#include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <asm/io.h>
 
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index f88e3d8..efaf630 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -27,6 +27,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 #include <asm/dcr.h>
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 370ff82..e24b5ef 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -42,6 +42,8 @@
 #include <linux/uaccess.h>
 #include <linux/proc_fs.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v8 4/7] pseries/cpuidle: Remove MAX_IDLE_STATE macro.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

This patch removes the usage of MAX_IDLE_STATE macro
and dead code around it. The number of states
are determined at run time based on the cpuidle
state table selected on a given platform

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/cpuidle/cpuidle-powerpc-book3s.c |   26 +++++++++-----------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
index 82c9e15..fe8ea0c 100644
--- a/drivers/cpuidle/cpuidle-powerpc-book3s.c
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -25,9 +25,7 @@ struct cpuidle_driver pseries_idle_driver = {
 	.owner            = THIS_MODULE,
 };
 
-#define MAX_IDLE_STATE_COUNT	2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static int max_idle_state;
 static struct cpuidle_state *cpuidle_state_table;
 
 static inline void idle_loop_prolog(unsigned long *in_purr)
@@ -137,7 +135,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
 /*
  * States for dedicated partition case.
  */
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state dedicated_states[] = {
 	{ /* Snooze */
 		.name = "snooze",
 		.desc = "snooze",
@@ -157,7 +155,7 @@ static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
 /*
  * States for shared partition case.
  */
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state shared_states[] = {
 	{ /* Shared Cede */
 		.name = "Shared Cede",
 		.desc = "Shared Cede",
@@ -227,11 +225,7 @@ static int pseries_cpuidle_driver_init(void)
 	struct cpuidle_driver *drv = &pseries_idle_driver;
 
 	drv->state_count = 0;
-
-	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
-
-		if (idle_state > max_idle_state)
-			break;
+	for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
 
 		/* is the state not enabled? */
 		if (cpuidle_state_table[idle_state].enter == NULL)
@@ -256,16 +250,14 @@ static int pseries_idle_probe(void)
 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
 		return -ENODEV;
 
-	if (max_idle_state == 0) {
-		printk(KERN_DEBUG "pseries processor idle disabled.\n");
-		return -EPERM;
-	}
-
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
-		if (lppaca_shared_proc(get_lppaca()))
+		if (lppaca_shared_proc(get_lppaca())) {
 			cpuidle_state_table = shared_states;
-		else
+			max_idle_state = ARRAY_SIZE(shared_states);
+		} else {
 			cpuidle_state_table = dedicated_states;
+			max_idle_state = ARRAY_SIZE(dedicated_states);
+		}
 	} else
 		return -ENODEV;
 

^ permalink raw reply related

* [PATCH v8 5/7] POWER/cpuidle: Generic POWERPC-BOOK3S CPUIDLE driver supporting PSERIES.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

This patch includes cleanup and refactoring of the
existing code to make the driver POWERPC-BOOK3S generic.
* Re-naming the functions from pseries to generic powerpc-book3s.
* Re-naming the backend driver from pseries_idle to
  powerpc_book3s_idle.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/cpuidle/cpuidle-powerpc-book3s.c |   32 +++++++++++++++---------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
index fe8ea0c..7b785ff 100644
--- a/drivers/cpuidle/cpuidle-powerpc-book3s.c
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -20,8 +20,8 @@
 #include <asm/runlatch.h>
 #include <asm/plpar_wrappers.h>
 
-struct cpuidle_driver pseries_idle_driver = {
-	.name             = "pseries_idle",
+struct cpuidle_driver powerpc_book3s_idle_driver = {
+	.name             = "powerpc_book3s_idle",
 	.owner            = THIS_MODULE,
 };
 
@@ -182,7 +182,7 @@ void update_smt_snooze_delay(int cpu, int residency)
 			drv->states[1].target_residency = residency;
 }
 
-static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
+static int powerpc_book3s_cpuidle_add_cpu_notifier(struct notifier_block *n,
 			unsigned long action, void *hcpu)
 {
 	int hotcpu = (unsigned long)hcpu;
@@ -213,16 +213,16 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
 }
 
 static struct notifier_block setup_hotplug_notifier = {
-	.notifier_call = pseries_cpuidle_add_cpu_notifier,
+	.notifier_call = powerpc_book3s_cpuidle_add_cpu_notifier,
 };
 
 /*
- * pseries_cpuidle_driver_init()
+ * powerpc_book3s_cpuidle_driver_init()
  */
-static int pseries_cpuidle_driver_init(void)
+static int powerpc_book3s_cpuidle_driver_init(void)
 {
 	int idle_state;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
+	struct cpuidle_driver *drv = &powerpc_book3s_idle_driver;
 
 	drv->state_count = 0;
 	for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
@@ -241,10 +241,10 @@ static int pseries_cpuidle_driver_init(void)
 }
 
 /*
- * pseries_idle_probe()
+ * powerpc_book3s_idle_probe()
  * Choose state table for shared versus dedicated partition
  */
-static int pseries_idle_probe(void)
+static int powerpc_book3s_idle_probe(void)
 {
 
 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
@@ -264,24 +264,24 @@ static int pseries_idle_probe(void)
 	return 0;
 }
 
-static int __init pseries_processor_idle_init(void)
+static int __init powerpc_book3s_processor_idle_init(void)
 {
 	int retval;
 
-	retval = pseries_idle_probe();
+	retval = powerpc_book3s_idle_probe();
 	if (retval)
 		return retval;
 
-	pseries_cpuidle_driver_init();
-	retval = cpuidle_register(&pseries_idle_driver, NULL);
+	powerpc_book3s_cpuidle_driver_init();
+	retval = cpuidle_register(&powerpc_book3s_idle_driver, NULL);
 	if (retval) {
-		printk(KERN_DEBUG "Registration of pseries driver failed.\n");
+		printk(KERN_DEBUG "Registration of powerpc_book3s_idle driver failed.\n");
 		return retval;
 	}
 
 	register_cpu_notifier(&setup_hotplug_notifier);
-	printk(KERN_DEBUG "pseries_idle_driver registered\n");
+	printk(KERN_DEBUG "powerpc_book3s_idle registered\n");
 	return 0;
 }
 
-device_initcall(pseries_processor_idle_init);
+device_initcall(powerpc_book3s_processor_idle_init);

^ permalink raw reply related

* [PATCH v8 6/7] POWER/cpuidle: Enable powernv cpuidle support.
From: Deepthi Dharwar @ 2013-11-11  5:35 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

The following patch extends the current powerpc-book3s backend
idle driver to the powernv platform.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/cpuidle/cpuidle-powerpc-book3s.c |   39 ++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc-book3s.c b/drivers/cpuidle/cpuidle-powerpc-book3s.c
index 7b785ff..25e8a99 100644
--- a/drivers/cpuidle/cpuidle-powerpc-book3s.c
+++ b/drivers/cpuidle/cpuidle-powerpc-book3s.c
@@ -52,9 +52,10 @@ static int snooze_loop(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			int index)
 {
-	unsigned long in_purr;
+	unsigned long in_purr = 0;
 
-	idle_loop_prolog(&in_purr);
+	if (firmware_has_feature(FW_FEATURE_SPLPAR))
+		idle_loop_prolog(&in_purr);
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
@@ -68,7 +69,8 @@ static int snooze_loop(struct cpuidle_device *dev,
 	clear_thread_flag(TIF_POLLING_NRFLAG);
 	smp_mb();
 
-	idle_loop_epilog(in_purr);
+	if (firmware_has_feature(FW_FEATURE_SPLPAR))
+		idle_loop_epilog(in_purr);
 
 	return index;
 }
@@ -132,6 +134,15 @@ static int shared_cede_loop(struct cpuidle_device *dev,
 	return index;
 }
 
+static int nap_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	ppc64_runlatch_off();
+	power7_idle();
+	return index;
+}
+
 /*
  * States for dedicated partition case.
  */
@@ -165,6 +176,23 @@ static struct cpuidle_state shared_states[] = {
 		.enter = &shared_cede_loop },
 };
 
+static struct cpuidle_state powernv_states[] = {
+	{ /* Snooze */
+		.name = "snooze",
+		.desc = "snooze",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &snooze_loop },
+	{ /* NAP */
+		.name = "NAP",
+		.desc = "NAP",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 100,
+		.enter = &nap_loop },
+};
+
 void update_smt_snooze_delay(int cpu, int residency)
 {
 	struct cpuidle_driver *drv = cpuidle_get_driver();
@@ -258,6 +286,11 @@ static int powerpc_book3s_idle_probe(void)
 			cpuidle_state_table = dedicated_states;
 			max_idle_state = ARRAY_SIZE(dedicated_states);
 		}
+
+	} else if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+		cpuidle_state_table = powernv_states;
+		max_idle_state = ARRAY_SIZE(powernv_states);
+
 	} else
 		return -ENODEV;
 

^ permalink raw reply related

* [PATCH v8 7/7] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
From: Deepthi Dharwar @ 2013-11-11  5:36 UTC (permalink / raw)
  To: benh, linux-pm, linuxppc-dev, linux-kernel
  Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
	srivatsa.bhat, scottwood
In-Reply-To: <20131111053450.14797.75544.stgit@deepthi.in.ibm.com>

This patch enables idle cpu on the powernv platform  to hook on to the cpuidle
framework, if available, else call on to default idle platform
code.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 arch/powerpc/platforms/powernv/setup.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index e239dcf..42a6ba0 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/interrupt.h>
 #include <linux/bug.h>
+#include <linux/cpuidle.h>
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
@@ -192,6 +193,16 @@ static void __init pnv_setup_machdep_rtas(void)
 }
 #endif /* CONFIG_PPC_POWERNV_RTAS */
 
+void powernv_idle(void)
+{
+	/* Hook to cpuidle framework if available, else
+	 * call on default platform idle code
+	 */
+	if (cpuidle_idle_call()) {
+		power7_idle();
+	}
+}
+
 static int __init pnv_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
@@ -222,7 +233,7 @@ define_machine(powernv) {
 	.show_cpuinfo		= pnv_show_cpuinfo,
 	.progress		= pnv_progress,
 	.machine_shutdown	= pnv_shutdown,
-	.power_save             = power7_idle,
+	.power_save             = powernv_idle,
 	.calibrate_decr		= generic_calibrate_decr,
 #ifdef CONFIG_KEXEC
 	.kexec_cpu_down		= pnv_kexec_cpu_down,

^ permalink raw reply related

* Re: BookE "branch taken" behavior vis-a-vis updating the NIP register
From: pegasus @ 2013-11-11  7:51 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <alpine.LRH.2.00.1311101509570.9815@ra8135-ec1.am.freescale.net>

Thanks James.

So it means that, the NIP that I am seeing in the printks is indeed correct.
Right? And this is due to the pipelining feature that is inherent in all
processors. So it basically means that after having executed the branch, the
NIP has already progressed to the next instruction it is about to execute
(just after the branch or rather the branch target). The NIP hence basically
contains the address of the branch target. And this is how it is (and
perhaps I have been thinking about this in the wrong way).

But I still have a question about how one would then be able to signal to
the userspace who might be interpreting this information differently? I mean
if SRR0 contains, not the branch instruction address but the address of the
branch target, how would any debugger be able to catch function calls? May
be there is a trick involved here and hence gdb or for that matter the other
debuggers are still in the market. But then I would be immensely obliged if
you could shed some light on how is this accomplished. Lets say I am waiting
at the userspace in my own sigtrap, to watch out for branch instructions.
Lets say I want to profile my code to get to know how many branch
instructions it has generated. How could I ever do that using my own custom
SIGTRAP handler?

Coming on to PTRACE_SINGLESTEP, the sysroot that has been provided to us by
our vendor does not include a PTRACE_SINGLEBLOCK in sys/ptrace.h:

/* Type of the REQUEST argument to `ptrace.'  */
enum __ptrace_request
{
  /* Indicate that the process making this request should be traced.
     All signals received by this process can be intercepted by its
     parent, and its parent can use the other `ptrace' requests.  */
  PTRACE_TRACEME = 0,
#define PT_TRACE_ME PTRACE_TRACEME

  /* Return the word in the process's text space at address ADDR.  */
  PTRACE_PEEKTEXT = 1,
#define PT_READ_I PTRACE_PEEKTEXT

  /* Return the word in the process's data space at address ADDR.  */
  PTRACE_PEEKDATA = 2,
#define PT_READ_D PTRACE_PEEKDATA

  /* Return the word in the process's user area at offset ADDR.  */
  PTRACE_PEEKUSER = 3,
#define PT_READ_U PTRACE_PEEKUSER

  /* Write the word DATA into the process's text space at address ADDR.  */
  PTRACE_POKETEXT = 4,
#define PT_WRITE_I PTRACE_POKETEXT

  /* Write the word DATA into the process's data space at address ADDR.  */
  PTRACE_POKEDATA = 5,
#define PT_WRITE_D PTRACE_POKEDATA

  /* Write the word DATA into the process's user area at offset ADDR.  */
  PTRACE_POKEUSER = 6,
#define PT_WRITE_U PTRACE_POKEUSER

  /* Continue the process.  */
  PTRACE_CONT = 7,
#define PT_CONTINUE PTRACE_CONT

  /* Kill the process.  */
  PTRACE_KILL = 8,
#define PT_KILL PTRACE_KILL

  /* Single step the process.
     This is not supported on all machines.  */
  PTRACE_SINGLESTEP = 9,
#define PT_STEP PTRACE_SINGLESTEP

  /* Attach to a process that is already running. */
  PTRACE_ATTACH = 16,
#define PT_ATTACH PTRACE_ATTACH

  /* Detach from a process attached to with PTRACE_ATTACH.  */
  PTRACE_DETACH = 17,
#define PT_DETACH PTRACE_DETACH

  /* Continue and stop at the next (return from) syscall.  */
  PTRACE_SYSCALL = 24,
#define PT_SYSCALL PTRACE_SYSCALL

  /* Set ptrace filter options.  */
  PTRACE_SETOPTIONS = 0x4200,
#define PT_SETOPTIONS PTRACE_SETOPTIONS

  /* Get last ptrace message.  */
  PTRACE_GETEVENTMSG = 0x4201,
#define PT_GETEVENTMSG PTRACE_GETEVENTMSG

  /* Get siginfo for process.  */
  PTRACE_GETSIGINFO = 0x4202,
#define PT_GETSIGINFO PTRACE_GETSIGINFO

  /* Set new siginfo for process.  */
  PTRACE_SETSIGINFO = 0x4203
#define PT_SETSIGINFO PTRACE_SETSIGINFO
};

Although I can clearly see that PTRACE_SINGLEBLOCK is supported in the
kernel. 

Hence I am not able to compile this simple program in userspace:

#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>


int main() {   
	pid_t childpid;

    childpid = fork();

	if(childpid < 0) {
		perror("error forking:");
		return -1;
	}

    if(childpid == 0) {
		char cwd[512];
		char path[1024];
		int val;
		
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);

		if (getcwd(cwd, sizeof(cwd)) != NULL)
			snprintf(path, sizeof(path), "%s/test", cwd);
		else {
			perror("getcwd() error. Exiting the program");
			exit(1);
		}

		puts("now execle'ing");
		val = execl(path, NULL); //this will not return
		if (val < 0) { //something went wrong
			perror("something went wrong");
			exit(1);
		}		
    }
    else {
		int status,rc;

		ptrace(PTRACE_SINGLEBLOCK, childpid, NULL, NULL);
		rc = waitpid(childpid, &status, 0);
		if (rc == -1) {
			perror("unable to waitpid:");
			exit(1);
		}
		
		if(WIFEXITED(status)) {
			printf("Child exited with status %d.\n", WEXITSTATUS(status));
		}
    }
    return 0;
}

Heres the error I get:
testptrace.c: In function 'int main()':
testptrace.c:47: error: invalid conversion from 'int' to '__ptrace_request'
testptrace.c:47: error:   initializing argument 1 of 'long int
ptrace(__ptrace_request, ...)'
make: *** [testptrace] Error 1

How should I go about using ptrace to test this? 

Keen to hear from you for the above two clarifications.



--
View this message in context: http://linuxppc.10917.n7.nabble.com/BookE-branch-taken-behavior-vis-a-vis-updating-the-NIP-register-tp77960p78004.html
Sent from the linuxppc-dev mailing list archive at Nabble.com.

^ permalink raw reply

* Re: [PATCH v11 3/3] DMA: Freescale: update driver to support 8-channel DMA engine
From: Hongbo Zhang @ 2013-11-11  9:12 UTC (permalink / raw)
  To: Dan Williams
  Cc: mark.rutland, devicetree, ian.campbell, pawel.moll,
	Stephen Warren, Koul, Vinod, Linux Kernel Mailing List,
	rob.herring, dmaengine, linuxppc-dev
In-Reply-To: <CAA9_cme3c7SjH3iio0oR3FHpfoMzgrBDO-2k_Yf68G-AgFNqfA@mail.gmail.com>

On 11/08/2013 10:45 AM, Dan Williams wrote:
> On Mon, Nov 4, 2013 at 6:31 PM, Hongbo Zhang <hongbo.zhang@freescale.com> wrote:
>> Hi Vinod Koul and Dan Williams,
>> Ping?
>>
> Not much to review from the dmaengine side, just one question below.
> It would be helpful if you can send these to the new dmaengine
> patchwork at dmaengine@vger.kernel.org with the Acks you have already
> collected.
>

Sorry didn't notice this new mailing list.
I will resend these patches to it again.

>>
>> On 10/17/2013 01:56 PM, Hongbo Zhang wrote:
>>> Hi Vinod,
>>> I have gotten ACK from Mark for both the 1/3 and 2/3 patches.
>>> Thanks.
>>>
>>>
>>> On 09/26/2013 05:33 PM, hongbo.zhang@freescale.com wrote:
>>>> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>>>>
>>>> This patch adds support to 8-channel DMA engine, thus the driver works
>>>> for both
>>>> the new 8-channel and the legacy 4-channel DMA engines.
>>>>
>>>> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
>>>> ---
>>>>    drivers/dma/Kconfig  |    9 +++++----
>>>>    drivers/dma/fsldma.c |    9 ++++++---
>>>>    drivers/dma/fsldma.h |    2 +-
>>>>    3 files changed, 12 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
>>>> index 6825957..3979c65 100644
>>>> --- a/drivers/dma/Kconfig
>>>> +++ b/drivers/dma/Kconfig
>>>> @@ -89,14 +89,15 @@ config AT_HDMAC
>>>>          Support the Atmel AHB DMA controller.
>>>>      config FSL_DMA
>>>> -    tristate "Freescale Elo and Elo Plus DMA support"
>>>> +    tristate "Freescale Elo series DMA support"
>>>>        depends on FSL_SOC
>>>>        select DMA_ENGINE
>>>>        select ASYNC_TX_ENABLE_CHANNEL_SWITCH
>>>>        ---help---
>>>> -      Enable support for the Freescale Elo and Elo Plus DMA controllers.
>>>> -      The Elo is the DMA controller on some 82xx and 83xx parts, and the
>>>> -      Elo Plus is the DMA controller on 85xx and 86xx parts.
>>>> +      Enable support for the Freescale Elo series DMA controllers.
>>>> +      The Elo is the DMA controller on some mpc82xx and mpc83xx parts,
>>>> the
>>>> +      EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is
>>>> on
>>>> +      some Txxx and Bxxx parts.
>>>>      config MPC512X_DMA
>>>>        tristate "Freescale MPC512x built-in DMA engine support"
>>>> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
>>>> index 49e8fbd..16a9a48 100644
>>>> --- a/drivers/dma/fsldma.c
>>>> +++ b/drivers/dma/fsldma.c
>>>> @@ -1261,7 +1261,9 @@ static int fsl_dma_chan_probe(struct fsldma_device
>>>> *fdev,
>>>>        WARN_ON(fdev->feature != chan->feature);
>>>>          chan->dev = fdev->dev;
>>>> -    chan->id = ((res.start - 0x100) & 0xfff) >> 7;
>>>> +    chan->id = (res.start & 0xfff) < 0x300 ?
>>>> +           ((res.start - 0x100) & 0xfff) >> 7 :
>>>> +           ((res.start - 0x200) & 0xfff) >> 7;
>>>>        if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
> Isn't it a bit fragile to have this based on the resource address?
> Can't device tree tell you the channel id directly by an index into
> the "dma0: dma@100300" node?

Yes, both this way and putting a "cell-index" into device tree work.
This won't be fragile, because the resource address should always be 
defined correctly, otherwise even if we can tell a channel id by 
"cell-index" but with wrong resource address, nothing will work.
This piece of code only doesn't seem as neat as using "cell-index", but 
we prefer the style that let the device tree describes as true as what 
hardware really has. This doesn't mean "cell-index" isn't acceptable, if 
it is necessary and unavoidable, we can send another patch to add it, 
but currently there is no need and we don't have to do this.

> --
> Dan
>

^ permalink raw reply

* [PATCH resend 0/3] DMA: Freescale: Add support for 8-channel DMA engine
From: hongbo.zhang @ 2013-11-11 10:26 UTC (permalink / raw)
  To: dan.j.williams, vinod.koul, dmaengine
  Cc: Hongbo Zhang, devicetree, linuxppc-dev

From: Hongbo Zhang <hongbo.zhang@freescale.com>

Hi Dan Williams and Vinod Koul,

This time only resend all patches to the new dmaengine patchwork at
dmaengine(at)vger.kernel.org as Dan Williams suggested.

Patch 1/3 and 2/3 have been Acked-by: Mark Rutland <mark.rutland@arm.com>
after several iterations of review.

Hongbo Zhang (3):
  DMA: Freescale: revise device tree binding document
  DMA: Freescale: Add new 8-channel DMA engine device tree nodes
  DMA: Freescale: update driver to support 8-channel DMA engine

 .../devicetree/bindings/powerpc/fsl/dma.txt        |  138 ++++++++++++++------
 arch/powerpc/boot/dts/fsl/b4si-post.dtsi           |    4 +-
 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi          |   82 ++++++++++++
 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi          |   82 ++++++++++++
 arch/powerpc/boot/dts/fsl/t4240si-post.dtsi        |    4 +-
 drivers/dma/Kconfig                                |    9 +-
 drivers/dma/fsldma.c                               |    9 +-
 drivers/dma/fsldma.h                               |    2 +-
 8 files changed, 281 insertions(+), 49 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi

-- 
1.7.9.5

^ permalink raw reply


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