diff mbox

[V2] cpufreq: move policy kobj to policy->cpu at resume

Message ID 1eff59d9b51f8ade67bc1cf9f10683f9463ec9f6.1404996041.git.viresh.kumar@linaro.org
State New
Headers show

Commit Message

Viresh Kumar July 10, 2014, 12:41 p.m. UTC
This is only relevant to implementations with multiple clusters, where clusters
have separate clock lines but all CPUs within a cluster share it.

Consider a dual cluster platform with 2 cores per cluster. During suspend we
start offlining CPUs from 1 to 3. When CPU2 is remove, policy->kobj would be
moved to CPU3 and when CPU3 goes down we wouldn't free policy or its kobj.

Now on resume, we will get CPU2 before CPU3 and will call __cpufreq_add_dev().
We will recover the old policy and update policy->cpu from 3 to 2 from
update_policy_cpu().

But the kobj is still tied to CPU3 and wasn't moved to CPU2. We wouldn't create
a link for CPU2, but would try that while bringing CPU3 online. Which will
report errors as CPU3 already has kobj assigned to it.

This bug got introduced with commit 42f921a, which overlooked this scenario.

To fix this, lets move kobj to the new policy->cpu while bringing first CPU of a
cluster back. We already have update_policy_cpu() routine which can be updated
with this change. That would get rid of the cpufreq_nominate_new_policy_cpu() as
update_policy_cpu() is also called on CPU removal.

To achieve that we add another parameter to update_policy_cpu() as cpu_dev is
present with both the callers.

Fixes: ("42f921a cpufreq: remove sysfs files for CPUs which failed to come back after resume")
Cc: Stable <stable@vger.kernel.org> # 3.13+
Reported-by: Bu Yitian <ybu@qti.qualcomm.com>
Reported-by: Saravana Kannan <skannan@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
V1->V2: Move kobject_move() call to update_policy_cpu(), which makes
cpufreq_nominate_new_policy_cpu() almost empty. So we remove it completely.

@Yitian: Sorry, but you need to test this again as there were enough
modifications in V2.

 drivers/cpufreq/cpufreq.c | 73 +++++++++++++++++++++++------------------------
 1 file changed, 36 insertions(+), 37 deletions(-)

Comments

Bu, Yitian July 10, 2014, 3:12 p.m. UTC | #1
DQoNCj4g1NogMjAxNMTqN9TCMTDI1aOsMjA6NDGjrCJWaXJlc2ggS3VtYXIiIDx2aXJlc2gua3Vt
YXJAbGluYXJvLm9yZz4g0LS1wKO6DQo+IA0KPiBUaGlzIGlzIG9ubHkgcmVsZXZhbnQgdG8gaW1w
bGVtZW50YXRpb25zIHdpdGggbXVsdGlwbGUgY2x1c3RlcnMsIHdoZXJlIGNsdXN0ZXJzDQo+IGhh
dmUgc2VwYXJhdGUgY2xvY2sgbGluZXMgYnV0IGFsbCBDUFVzIHdpdGhpbiBhIGNsdXN0ZXIgc2hh
cmUgaXQuDQo+IA0KPiBDb25zaWRlciBhIGR1YWwgY2x1c3RlciBwbGF0Zm9ybSB3aXRoIDIgY29y
ZXMgcGVyIGNsdXN0ZXIuIER1cmluZyBzdXNwZW5kIHdlDQo+IHN0YXJ0IG9mZmxpbmluZyBDUFVz
IGZyb20gMSB0byAzLiBXaGVuIENQVTIgaXMgcmVtb3ZlLCBwb2xpY3ktPmtvYmogd291bGQgYmUN
Cj4gbW92ZWQgdG8gQ1BVMyBhbmQgd2hlbiBDUFUzIGdvZXMgZG93biB3ZSB3b3VsZG4ndCBmcmVl
IHBvbGljeSBvciBpdHMga29iai4NCj4gDQo+IE5vdyBvbiByZXN1bWUsIHdlIHdpbGwgZ2V0IENQ
VTIgYmVmb3JlIENQVTMgYW5kIHdpbGwgY2FsbCBfX2NwdWZyZXFfYWRkX2RldigpLg0KPiBXZSB3
aWxsIHJlY292ZXIgdGhlIG9sZCBwb2xpY3kgYW5kIHVwZGF0ZSBwb2xpY3ktPmNwdSBmcm9tIDMg
dG8gMiBmcm9tDQo+IHVwZGF0ZV9wb2xpY3lfY3B1KCkuDQo+IA0KPiBCdXQgdGhlIGtvYmogaXMg
c3RpbGwgdGllZCB0byBDUFUzIGFuZCB3YXNuJ3QgbW92ZWQgdG8gQ1BVMi4gV2Ugd291bGRuJ3Qg
Y3JlYXRlDQo+IGEgbGluayBmb3IgQ1BVMiwgYnV0IHdvdWxkIHRyeSB0aGF0IHdoaWxlIGJyaW5n
aW5nIENQVTMgb25saW5lLiBXaGljaCB3aWxsDQo+IHJlcG9ydCBlcnJvcnMgYXMgQ1BVMyBhbHJl
YWR5IGhhcyBrb2JqIGFzc2lnbmVkIHRvIGl0Lg0KPiANCj4gVGhpcyBidWcgZ290IGludHJvZHVj
ZWQgd2l0aCBjb21taXQgNDJmOTIxYSwgd2hpY2ggb3Zlcmxvb2tlZCB0aGlzIHNjZW5hcmlvLg0K
PiANCj4gVG8gZml4IHRoaXMsIGxldHMgbW92ZSBrb2JqIHRvIHRoZSBuZXcgcG9saWN5LT5jcHUg
d2hpbGUgYnJpbmdpbmcgZmlyc3QgQ1BVIG9mIGENCj4gY2x1c3RlciBiYWNrLiBXZSBhbHJlYWR5
IGhhdmUgdXBkYXRlX3BvbGljeV9jcHUoKSByb3V0aW5lIHdoaWNoIGNhbiBiZSB1cGRhdGVkDQo+
IHdpdGggdGhpcyBjaGFuZ2UuIFRoYXQgd291bGQgZ2V0IHJpZCBvZiB0aGUgY3B1ZnJlcV9ub21p
bmF0ZV9uZXdfcG9saWN5X2NwdSgpIGFzDQo+IHVwZGF0ZV9wb2xpY3lfY3B1KCkgaXMgYWxzbyBj
YWxsZWQgb24gQ1BVIHJlbW92YWwuDQo+IA0KPiBUbyBhY2hpZXZlIHRoYXQgd2UgYWRkIGFub3Ro
ZXIgcGFyYW1ldGVyIHRvIHVwZGF0ZV9wb2xpY3lfY3B1KCkgYXMgY3B1X2RldiBpcw0KPiBwcmVz
ZW50IHdpdGggYm90aCB0aGUgY2FsbGVycy4NCj4gDQo+IEZpeGVzOiAoIjQyZjkyMWEgY3B1ZnJl
cTogcmVtb3ZlIHN5c2ZzIGZpbGVzIGZvciBDUFVzIHdoaWNoIGZhaWxlZCB0byBjb21lIGJhY2sg
YWZ0ZXIgcmVzdW1lIikNCj4gQ2M6IFN0YWJsZSA8c3RhYmxlQHZnZXIua2VybmVsLm9yZz4gIyAz
LjEzKw0KPiBSZXBvcnRlZC1ieTogQnUgWWl0aWFuIDx5YnVAcXRpLnF1YWxjb21tLmNvbT4NCj4g
UmVwb3J0ZWQtYnk6IFNhcmF2YW5hIEthbm5hbiA8c2thbm5hbkBjb2RlYXVyb3JhLm9yZz4NCj4g
U2lnbmVkLW9mZi1ieTogVmlyZXNoIEt1bWFyIDx2aXJlc2gua3VtYXJAbGluYXJvLm9yZz4NCj4g
LS0tDQo+IFYxLT5WMjogTW92ZSBrb2JqZWN0X21vdmUoKSBjYWxsIHRvIHVwZGF0ZV9wb2xpY3lf
Y3B1KCksIHdoaWNoIG1ha2VzDQo+IGNwdWZyZXFfbm9taW5hdGVfbmV3X3BvbGljeV9jcHUoKSBh
bG1vc3QgZW1wdHkuIFNvIHdlIHJlbW92ZSBpdCBjb21wbGV0ZWx5Lg0KPiANCj4gQFlpdGlhbjog
U29ycnksIGJ1dCB5b3UgbmVlZCB0byB0ZXN0IHRoaXMgYWdhaW4gYXMgdGhlcmUgd2VyZSBlbm91
Z2gNCj4gbW9kaWZpY2F0aW9ucyBpbiBWMi4NCj4gDQoNClNvcnJ5LCBJIGRvbid0IGhhdmUgbGF0
ZXN0IGtlcm5lbCB0byB0ZXN0IHRoaXMgcGF0Y2guLi4NCldoYXQgSSBhbSB1c2luZyBpcyAzLjEw
LCB0aGlzIHBhdGNoIHNlZW1zIHRvbyBiaWcgdG8gbWFudWFsbHkgYXBwbHkgdG8gMy4xMC4NCg0K
DQo+IGRyaXZlcnMvY3B1ZnJlcS9jcHVmcmVxLmMgfCA3MyArKysrKysrKysrKysrKysrKysrKysr
Ky0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KPiAxIGZpbGUgY2hhbmdlZCwgMzYgaW5zZXJ0aW9u
cygrKSwgMzcgZGVsZXRpb25zKC0pDQo+IA0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jcHVmcmVx
L2NwdWZyZXEuYyBiL2RyaXZlcnMvY3B1ZnJlcS9jcHVmcmVxLmMNCj4gaW5kZXggNjIyNTlkMi4u
YzgxZDllYzYgMTAwNjQ0DQo+IC0tLSBhL2RyaXZlcnMvY3B1ZnJlcS9jcHVmcmVxLmMNCj4gKysr
IGIvZHJpdmVycy9jcHVmcmVxL2NwdWZyZXEuYw0KPiBAQCAtMTA3NiwxMCArMTA3NiwyMCBAQCBz
dGF0aWMgdm9pZCBjcHVmcmVxX3BvbGljeV9mcmVlKHN0cnVjdCBjcHVmcmVxX3BvbGljeSAqcG9s
aWN5KQ0KPiAgICBrZnJlZShwb2xpY3kpOw0KPiB9DQo+IA0KPiAtc3RhdGljIHZvaWQgdXBkYXRl
X3BvbGljeV9jcHUoc3RydWN0IGNwdWZyZXFfcG9saWN5ICpwb2xpY3ksIHVuc2lnbmVkIGludCBj
cHUpDQo+ICtzdGF0aWMgaW50IHVwZGF0ZV9wb2xpY3lfY3B1KHN0cnVjdCBjcHVmcmVxX3BvbGlj
eSAqcG9saWN5LCB1bnNpZ25lZCBpbnQgY3B1LA0KPiArICAgICAgICAgICAgICAgICBzdHJ1Y3Qg
ZGV2aWNlICpjcHVfZGV2KQ0KPiB7DQo+ICsgICAgaW50IHJldDsNCj4gKw0KPiAgICBpZiAoV0FS
Tl9PTihjcHUgPT0gcG9saWN5LT5jcHUpKQ0KPiAtICAgICAgICByZXR1cm47DQo+ICsgICAgICAg
IHJldHVybiAwOw0KPiArDQo+ICsgICAgLyogTW92ZSBrb2JqZWN0IHRvIHRoZSBuZXcgcG9saWN5
LT5jcHUgKi8NCj4gKyAgICByZXQgPSBrb2JqZWN0X21vdmUoJnBvbGljeS0+a29iaiwgJmNwdV9k
ZXYtPmtvYmopOw0KPiArICAgIGlmIChyZXQpIHsNCj4gKyAgICAgICAgcHJfZXJyKCIlczogRmFp
bGVkIHRvIG1vdmUga29iajogJWRcbiIsIF9fZnVuY19fLCByZXQpOw0KPiArICAgICAgICByZXR1
cm4gcmV0Ow0KPiArICAgIH0NCj4gDQo+ICAgIGRvd25fd3JpdGUoJnBvbGljeS0+cndzZW0pOw0K
PiANCj4gQEAgLTEwOTAsNiArMTEwMCw4IEBAIHN0YXRpYyB2b2lkIHVwZGF0ZV9wb2xpY3lfY3B1
KHN0cnVjdCBjcHVmcmVxX3BvbGljeSAqcG9saWN5LCB1bnNpZ25lZCBpbnQgY3B1KQ0KPiANCj4g
ICAgYmxvY2tpbmdfbm90aWZpZXJfY2FsbF9jaGFpbigmY3B1ZnJlcV9wb2xpY3lfbm90aWZpZXJf
bGlzdCwNCj4gICAgICAgICAgICBDUFVGUkVRX1VQREFURV9QT0xJQ1lfQ1BVLCBwb2xpY3kpOw0K
PiArDQo+ICsgICAgcmV0dXJuIDA7DQo+IH0NCj4gDQo+IHN0YXRpYyBpbnQgX19jcHVmcmVxX2Fk
ZF9kZXYoc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3Qgc3Vic3lzX2ludGVyZmFjZSAqc2lmKQ0K
PiBAQCAtMTE1NCw3ICsxMTY2LDcgQEAgc3RhdGljIGludCBfX2NwdWZyZXFfYWRkX2RldihzdHJ1
Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBzdWJzeXNfaW50ZXJmYWNlICpzaWYpDQo+ICAgICAqIGJ5
IGludm9raW5nIHVwZGF0ZV9wb2xpY3lfY3B1KCkuDQo+ICAgICAqLw0KPiAgICBpZiAocmVjb3Zl
cl9wb2xpY3kgJiYgY3B1ICE9IHBvbGljeS0+Y3B1KQ0KPiAtICAgICAgICB1cGRhdGVfcG9saWN5
X2NwdShwb2xpY3ksIGNwdSk7DQo+ICsgICAgICAgIFdBUk5fT04odXBkYXRlX3BvbGljeV9jcHUo
cG9saWN5LCBjcHUsIGRldikpOw0KPiAgICBlbHNlDQo+ICAgICAgICBwb2xpY3ktPmNwdSA9IGNw
dTsNCj4gDQo+IEBAIC0xMzA3LDM4ICsxMzE5LDExIEBAIHN0YXRpYyBpbnQgY3B1ZnJlcV9hZGRf
ZGV2KHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IHN1YnN5c19pbnRlcmZhY2UgKnNpZikNCj4g
ICAgcmV0dXJuIF9fY3B1ZnJlcV9hZGRfZGV2KGRldiwgc2lmKTsNCj4gfQ0KPiANCj4gLXN0YXRp
YyBpbnQgY3B1ZnJlcV9ub21pbmF0ZV9uZXdfcG9saWN5X2NwdShzdHJ1Y3QgY3B1ZnJlcV9wb2xp
Y3kgKnBvbGljeSwNCj4gLSAgICAgICAgICAgICAgICAgICAgICAgdW5zaWduZWQgaW50IG9sZF9j
cHUpDQo+IC17DQo+IC0gICAgc3RydWN0IGRldmljZSAqY3B1X2RldjsNCj4gLSAgICBpbnQgcmV0
Ow0KPiAtDQo+IC0gICAgLyogZmlyc3Qgc2libGluZyBub3cgb3ducyB0aGUgbmV3IHN5c2ZzIGRp
ciAqLw0KPiAtICAgIGNwdV9kZXYgPSBnZXRfY3B1X2RldmljZShjcHVtYXNrX2FueV9idXQocG9s
aWN5LT5jcHVzLCBvbGRfY3B1KSk7DQo+IC0NCj4gLSAgICBzeXNmc19yZW1vdmVfbGluaygmY3B1
X2Rldi0+a29iaiwgImNwdWZyZXEiKTsNCj4gLSAgICByZXQgPSBrb2JqZWN0X21vdmUoJnBvbGlj
eS0+a29iaiwgJmNwdV9kZXYtPmtvYmopOw0KPiAtICAgIGlmIChyZXQpIHsNCj4gLSAgICAgICAg
cHJfZXJyKCIlczogRmFpbGVkIHRvIG1vdmUga29iajogJWRcbiIsIF9fZnVuY19fLCByZXQpOw0K
PiAtDQo+IC0gICAgICAgIGRvd25fd3JpdGUoJnBvbGljeS0+cndzZW0pOw0KPiAtICAgICAgICBj
cHVtYXNrX3NldF9jcHUob2xkX2NwdSwgcG9saWN5LT5jcHVzKTsNCj4gLSAgICAgICAgdXBfd3Jp
dGUoJnBvbGljeS0+cndzZW0pOw0KPiAtDQo+IC0gICAgICAgIHJldCA9IHN5c2ZzX2NyZWF0ZV9s
aW5rKCZjcHVfZGV2LT5rb2JqLCAmcG9saWN5LT5rb2JqLA0KPiAtICAgICAgICAgICAgICAgICAg
ICAiY3B1ZnJlcSIpOw0KPiAtDQo+IC0gICAgICAgIHJldHVybiAtRUlOVkFMOw0KPiAtICAgIH0N
Cj4gLQ0KPiAtICAgIHJldHVybiBjcHVfZGV2LT5pZDsNCj4gLX0NCj4gLQ0KPiBzdGF0aWMgaW50
IF9fY3B1ZnJlcV9yZW1vdmVfZGV2X3ByZXBhcmUoc3RydWN0IGRldmljZSAqZGV2LA0KPiAgICAg
ICAgICAgICAgICAgICAgc3RydWN0IHN1YnN5c19pbnRlcmZhY2UgKnNpZikNCj4gew0KPiAgICB1
bnNpZ25lZCBpbnQgY3B1ID0gZGV2LT5pZCwgY3B1czsNCj4gLSAgICBpbnQgbmV3X2NwdSwgcmV0
Ow0KPiArICAgIGludCByZXQ7DQo+ICAgIHVuc2lnbmVkIGxvbmcgZmxhZ3M7DQo+ICAgIHN0cnVj
dCBjcHVmcmVxX3BvbGljeSAqcG9saWN5Ow0KPiANCj4gQEAgLTEzNzgsMTQgKzEzNjMsMjggQEAg
c3RhdGljIGludCBfX2NwdWZyZXFfcmVtb3ZlX2Rldl9wcmVwYXJlKHN0cnVjdCBkZXZpY2UgKmRl
diwNCj4gICAgaWYgKGNwdSAhPSBwb2xpY3ktPmNwdSkgew0KPiAgICAgICAgc3lzZnNfcmVtb3Zl
X2xpbmsoJmRldi0+a29iaiwgImNwdWZyZXEiKTsNCj4gICAgfSBlbHNlIGlmIChjcHVzID4gMSkg
ew0KPiAtICAgICAgICBuZXdfY3B1ID0gY3B1ZnJlcV9ub21pbmF0ZV9uZXdfcG9saWN5X2NwdShw
b2xpY3ksIGNwdSk7DQo+IC0gICAgICAgIGlmIChuZXdfY3B1ID49IDApIHsNCj4gLSAgICAgICAg
ICAgIHVwZGF0ZV9wb2xpY3lfY3B1KHBvbGljeSwgbmV3X2NwdSk7DQo+ICsgICAgICAgIC8qIE5v
bWluYXRlIG5ldyBDUFUgKi8NCj4gKyAgICAgICAgaW50IG5ld19jcHUgPSBjcHVtYXNrX2FueV9i
dXQocG9saWN5LT5jcHVzLCBjcHUpOw0KPiArICAgICAgICBzdHJ1Y3QgZGV2aWNlICpjcHVfZGV2
ID0gZ2V0X2NwdV9kZXZpY2UobmV3X2NwdSk7DQo+IA0KPiAtICAgICAgICAgICAgaWYgKCFjcHVm
cmVxX3N1c3BlbmRlZCkNCj4gLSAgICAgICAgICAgICAgICBwcl9kZWJ1ZygiJXM6IHBvbGljeSBL
b2JqZWN0IG1vdmVkIHRvIGNwdTogJWQgZnJvbTogJWRcbiIsDQo+IC0gICAgICAgICAgICAgICAg
ICAgICBfX2Z1bmNfXywgbmV3X2NwdSwgY3B1KTsNCj4gKyAgICAgICAgc3lzZnNfcmVtb3ZlX2xp
bmsoJmNwdV9kZXYtPmtvYmosICJjcHVmcmVxIik7DQo+ICsgICAgICAgIHJldCA9IHVwZGF0ZV9w
b2xpY3lfY3B1KHBvbGljeSwgbmV3X2NwdSwgY3B1X2Rldik7DQo+ICsgICAgICAgIGlmIChyZXQp
IHsNCj4gKyAgICAgICAgICAgIC8qDQo+ICsgICAgICAgICAgICAgKiBUbyBzdXByZXNzIGNvbXBp
bGF0aW9uIHdhcm5pbmcgYWJvdXQgcmV0dXJuIHZhbHVlIG9mDQo+ICsgICAgICAgICAgICAgKiBz
eXNmc19jcmVhdGVfbGluaygpLg0KPiArICAgICAgICAgICAgICovDQo+ICsgICAgICAgICAgICBp
bnQgdGVtcDsNCj4gKw0KPiArICAgICAgICAgICAgLyogQ3JlYXRlIGxpbmsgYWdhaW4gaWYgd2Ug
ZmFpbGVkLiAqLw0KPiArICAgICAgICAgICAgdGVtcCA9IHN5c2ZzX2NyZWF0ZV9saW5rKCZjcHVf
ZGV2LT5rb2JqLCAmcG9saWN5LT5rb2JqLA0KPiArICAgICAgICAgICAgICAgICAgICAgICAgICJj
cHVmcmVxIik7DQo+ICsgICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiAgICAgICAgfQ0KPiArDQo+
ICsgICAgICAgIGlmICghY3B1ZnJlcV9zdXNwZW5kZWQpDQo+ICsgICAgICAgICAgICBwcl9kZWJ1
ZygiJXM6IHBvbGljeSBLb2JqZWN0IG1vdmVkIHRvIGNwdTogJWQgZnJvbTogJWRcbiIsDQo+ICsg
ICAgICAgICAgICAgICAgIF9fZnVuY19fLCBuZXdfY3B1LCBjcHUpOw0KPiAgICB9IGVsc2UgaWYg
KGNwdWZyZXFfZHJpdmVyLT5zdG9wX2NwdSAmJiBjcHVmcmVxX2RyaXZlci0+c2V0cG9saWN5KSB7
DQo+ICAgICAgICBjcHVmcmVxX2RyaXZlci0+c3RvcF9jcHUocG9saWN5KTsNCj4gICAgfQ0KPiAt
LSANCj4gMi4wLjAucmMyDQo+IA0K
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Saravana Kannan July 10, 2014, 7:26 p.m. UTC | #2
On 07/10/2014 08:12 AM, Bu, Yitian wrote:
> 
> 
>> 在 2014年7月10日,20:41,"Viresh Kumar" <viresh.kumar@linaro.org> 写道:
>>
>> This is only relevant to implementations with multiple clusters, where clusters
>> have separate clock lines but all CPUs within a cluster share it.
>>
>> Consider a dual cluster platform with 2 cores per cluster. During suspend we
>> start offlining CPUs from 1 to 3. When CPU2 is remove, policy->kobj would be
>> moved to CPU3 and when CPU3 goes down we wouldn't free policy or its kobj.
>>
>> Now on resume, we will get CPU2 before CPU3 and will call __cpufreq_add_dev().
>> We will recover the old policy and update policy->cpu from 3 to 2 from
>> update_policy_cpu().
>>
>> But the kobj is still tied to CPU3 and wasn't moved to CPU2. We wouldn't create
>> a link for CPU2, but would try that while bringing CPU3 online. Which will
>> report errors as CPU3 already has kobj assigned to it.
>>
>> This bug got introduced with commit 42f921a, which overlooked this scenario.
>>
>> To fix this, lets move kobj to the new policy->cpu while bringing first CPU of a
>> cluster back. We already have update_policy_cpu() routine which can be updated
>> with this change. That would get rid of the cpufreq_nominate_new_policy_cpu() as
>> update_policy_cpu() is also called on CPU removal.
>>
>> To achieve that we add another parameter to update_policy_cpu() as cpu_dev is
>> present with both the callers.
>>
>> Fixes: ("42f921a cpufreq: remove sysfs files for CPUs which failed to come back after resume")
>> Cc: Stable <stable@vger.kernel.org> # 3.13+
>> Reported-by: Bu Yitian <ybu@qti.qualcomm.com>
>> Reported-by: Saravana Kannan <skannan@codeaurora.org>
>> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
>> ---
>> V1->V2: Move kobject_move() call to update_policy_cpu(), which makes
>> cpufreq_nominate_new_policy_cpu() almost empty. So we remove it completely.
>>
>> @Yitian: Sorry, but you need to test this again as there were enough
>> modifications in V2.
>>
> 
> Sorry, I don't have latest kernel to test this patch...
> What I am using is 3.10, this patch seems too big to manually apply to 3.10.

Even though our kernel is 3.10, I believe we have pulled in all cpufreq
up to 3.14. So, if you have time, you could pull in rest of the cpufreq
changes and test it out. For our tree, maybe the v1 patch would be
sufficient?

-Saravana
> 
> 
>> drivers/cpufreq/cpufreq.c | 73 +++++++++++++++++++++++------------------------
>> 1 file changed, 36 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>> index 62259d2..c81d9ec6 100644
>> --- a/drivers/cpufreq/cpufreq.c
>> +++ b/drivers/cpufreq/cpufreq.c
>> @@ -1076,10 +1076,20 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
>>     kfree(policy);
>> }
>>
>> -static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
>> +static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
>> +                 struct device *cpu_dev)
>> {
>> +    int ret;
>> +
>>     if (WARN_ON(cpu == policy->cpu))
>> -        return;
>> +        return 0;
>> +
>> +    /* Move kobject to the new policy->cpu */
>> +    ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>> +    if (ret) {
>> +        pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>> +        return ret;
>> +    }
>>
>>     down_write(&policy->rwsem);
>>
>> @@ -1090,6 +1100,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
>>
>>     blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
>>             CPUFREQ_UPDATE_POLICY_CPU, policy);
>> +
>> +    return 0;
>> }
>>
>> static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>> @@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>      * by invoking update_policy_cpu().
>>      */
>>     if (recover_policy && cpu != policy->cpu)
>> -        update_policy_cpu(policy, cpu);
>> +        WARN_ON(update_policy_cpu(policy, cpu, dev));
>>     else
>>         policy->cpu = cpu;
>>
>> @@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>     return __cpufreq_add_dev(dev, sif);
>> }
>>
>> -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
>> -                       unsigned int old_cpu)
>> -{
>> -    struct device *cpu_dev;
>> -    int ret;
>> -
>> -    /* first sibling now owns the new sysfs dir */
>> -    cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
>> -
>> -    sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>> -    ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>> -    if (ret) {
>> -        pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>> -
>> -        down_write(&policy->rwsem);
>> -        cpumask_set_cpu(old_cpu, policy->cpus);
>> -        up_write(&policy->rwsem);
>> -
>> -        ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>> -                    "cpufreq");
>> -
>> -        return -EINVAL;
>> -    }
>> -
>> -    return cpu_dev->id;
>> -}
>> -
>> static int __cpufreq_remove_dev_prepare(struct device *dev,
>>                     struct subsys_interface *sif)
>> {
>>     unsigned int cpu = dev->id, cpus;
>> -    int new_cpu, ret;
>> +    int ret;
>>     unsigned long flags;
>>     struct cpufreq_policy *policy;
>>
>> @@ -1378,14 +1363,28 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
>>     if (cpu != policy->cpu) {
>>         sysfs_remove_link(&dev->kobj, "cpufreq");
>>     } else if (cpus > 1) {
>> -        new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
>> -        if (new_cpu >= 0) {
>> -            update_policy_cpu(policy, new_cpu);
>> +        /* Nominate new CPU */
>> +        int new_cpu = cpumask_any_but(policy->cpus, cpu);
>> +        struct device *cpu_dev = get_cpu_device(new_cpu);
>>
>> -            if (!cpufreq_suspended)
>> -                pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
>> -                     __func__, new_cpu, cpu);
>> +        sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>> +        ret = update_policy_cpu(policy, new_cpu, cpu_dev);
>> +        if (ret) {
>> +            /*
>> +             * To supress compilation warning about return value of
>> +             * sysfs_create_link().
>> +             */
>> +            int temp;
>> +
>> +            /* Create link again if we failed. */
>> +            temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>> +                         "cpufreq");
>> +            return ret;
>>         }
>> +
>> +        if (!cpufreq_suspended)
>> +            pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
>> +                 __func__, new_cpu, cpu);
>>     } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
>>         cpufreq_driver->stop_cpu(policy);
>>     }
>> -- 
>> 2.0.0.rc2
>>
Bu, Yitian July 11, 2014, 12:16 a.m. UTC | #3
> 在 2014年7月11日,3:26,"Saravana Kannan" <skannan@codeaurora.org> 写道:

> 

>> On 07/10/2014 08:12 AM, Bu, Yitian wrote:

>> 

>> 

>>> 在 2014年7月10日,20:41,"Viresh Kumar" <viresh.kumar@linaro.org> 写道:

>>> 

>>> This is only relevant to implementations with multiple clusters, where clusters

>>> have separate clock lines but all CPUs within a cluster share it.

>>> 

>>> Consider a dual cluster platform with 2 cores per cluster. During suspend we

>>> start offlining CPUs from 1 to 3. When CPU2 is remove, policy->kobj would be

>>> moved to CPU3 and when CPU3 goes down we wouldn't free policy or its kobj.

>>> 

>>> Now on resume, we will get CPU2 before CPU3 and will call __cpufreq_add_dev().

>>> We will recover the old policy and update policy->cpu from 3 to 2 from

>>> update_policy_cpu().

>>> 

>>> But the kobj is still tied to CPU3 and wasn't moved to CPU2. We wouldn't create

>>> a link for CPU2, but would try that while bringing CPU3 online. Which will

>>> report errors as CPU3 already has kobj assigned to it.

>>> 

>>> This bug got introduced with commit 42f921a, which overlooked this scenario.

>>> 

>>> To fix this, lets move kobj to the new policy->cpu while bringing first CPU of a

>>> cluster back. We already have update_policy_cpu() routine which can be updated

>>> with this change. That would get rid of the cpufreq_nominate_new_policy_cpu() as

>>> update_policy_cpu() is also called on CPU removal.

>>> 

>>> To achieve that we add another parameter to update_policy_cpu() as cpu_dev is

>>> present with both the callers.

>>> 

>>> Fixes: ("42f921a cpufreq: remove sysfs files for CPUs which failed to come back after resume")

>>> Cc: Stable <stable@vger.kernel.org> # 3.13+

>>> Reported-by: Bu Yitian <ybu@qti.qualcomm.com>

>>> Reported-by: Saravana Kannan <skannan@codeaurora.org>

>>> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>

>>> ---

>>> V1->V2: Move kobject_move() call to update_policy_cpu(), which makes

>>> cpufreq_nominate_new_policy_cpu() almost empty. So we remove it completely.

>>> 

>>> @Yitian: Sorry, but you need to test this again as there were enough

>>> modifications in V2.

>> 

>> Sorry, I don't have latest kernel to test this patch...

>> What I am using is 3.10, this patch seems too big to manually apply to 3.10.

> 

> Even though our kernel is 3.10, I believe we have pulled in all cpufreq

> up to 3.14. So, if you have time, you could pull in rest of the cpufreq

> changes and test it out. For our tree, maybe the v1 patch would be

> sufficient?

> 

> -Saravana


V1 patch is sufficient, which is the same as my original patch.
I have already verified the V1 patch and it works.


>> 

>> 

>>> drivers/cpufreq/cpufreq.c | 73 +++++++++++++++++++++++------------------------

>>> 1 file changed, 36 insertions(+), 37 deletions(-)

>>> 

>>> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c

>>> index 62259d2..c81d9ec6 100644

>>> --- a/drivers/cpufreq/cpufreq.c

>>> +++ b/drivers/cpufreq/cpufreq.c

>>> @@ -1076,10 +1076,20 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)

>>>    kfree(policy);

>>> }

>>> 

>>> -static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)

>>> +static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,

>>> +                 struct device *cpu_dev)

>>> {

>>> +    int ret;

>>> +

>>>    if (WARN_ON(cpu == policy->cpu))

>>> -        return;

>>> +        return 0;

>>> +

>>> +    /* Move kobject to the new policy->cpu */

>>> +    ret = kobject_move(&policy->kobj, &cpu_dev->kobj);

>>> +    if (ret) {

>>> +        pr_err("%s: Failed to move kobj: %d\n", __func__, ret);

>>> +        return ret;

>>> +    }

>>> 

>>>    down_write(&policy->rwsem);

>>> 

>>> @@ -1090,6 +1100,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)

>>> 

>>>    blocking_notifier_call_chain(&cpufreq_policy_notifier_list,

>>>            CPUFREQ_UPDATE_POLICY_CPU, policy);

>>> +

>>> +    return 0;

>>> }

>>> 

>>> static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

>>> @@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

>>>     * by invoking update_policy_cpu().

>>>     */

>>>    if (recover_policy && cpu != policy->cpu)

>>> -        update_policy_cpu(policy, cpu);

>>> +        WARN_ON(update_policy_cpu(policy, cpu, dev));

>>>    else

>>>        policy->cpu = cpu;

>>> 

>>> @@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

>>>    return __cpufreq_add_dev(dev, sif);

>>> }

>>> 

>>> -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,

>>> -                       unsigned int old_cpu)

>>> -{

>>> -    struct device *cpu_dev;

>>> -    int ret;

>>> -

>>> -    /* first sibling now owns the new sysfs dir */

>>> -    cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));

>>> -

>>> -    sysfs_remove_link(&cpu_dev->kobj, "cpufreq");

>>> -    ret = kobject_move(&policy->kobj, &cpu_dev->kobj);

>>> -    if (ret) {

>>> -        pr_err("%s: Failed to move kobj: %d\n", __func__, ret);

>>> -

>>> -        down_write(&policy->rwsem);

>>> -        cpumask_set_cpu(old_cpu, policy->cpus);

>>> -        up_write(&policy->rwsem);

>>> -

>>> -        ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,

>>> -                    "cpufreq");

>>> -

>>> -        return -EINVAL;

>>> -    }

>>> -

>>> -    return cpu_dev->id;

>>> -}

>>> -

>>> static int __cpufreq_remove_dev_prepare(struct device *dev,

>>>                    struct subsys_interface *sif)

>>> {

>>>    unsigned int cpu = dev->id, cpus;

>>> -    int new_cpu, ret;

>>> +    int ret;

>>>    unsigned long flags;

>>>    struct cpufreq_policy *policy;

>>> 

>>> @@ -1378,14 +1363,28 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,

>>>    if (cpu != policy->cpu) {

>>>        sysfs_remove_link(&dev->kobj, "cpufreq");

>>>    } else if (cpus > 1) {

>>> -        new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);

>>> -        if (new_cpu >= 0) {

>>> -            update_policy_cpu(policy, new_cpu);

>>> +        /* Nominate new CPU */

>>> +        int new_cpu = cpumask_any_but(policy->cpus, cpu);

>>> +        struct device *cpu_dev = get_cpu_device(new_cpu);

>>> 

>>> -            if (!cpufreq_suspended)

>>> -                pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",

>>> -                     __func__, new_cpu, cpu);

>>> +        sysfs_remove_link(&cpu_dev->kobj, "cpufreq");

>>> +        ret = update_policy_cpu(policy, new_cpu, cpu_dev);

>>> +        if (ret) {

>>> +            /*

>>> +             * To supress compilation warning about return value of

>>> +             * sysfs_create_link().

>>> +             */

>>> +            int temp;

>>> +

>>> +            /* Create link again if we failed. */

>>> +            temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,

>>> +                         "cpufreq");

>>> +            return ret;

>>>        }

>>> +

>>> +        if (!cpufreq_suspended)

>>> +            pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",

>>> +                 __func__, new_cpu, cpu);

>>>    } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {

>>>        cpufreq_driver->stop_cpu(policy);

>>>    }

>>> -- 

>>> 2.0.0.rc2

> 

> 

> -- 

> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,

> hosted by The Linux Foundation
Rafael J. Wysocki July 16, 2014, 11:18 p.m. UTC | #4
On Thursday, July 10, 2014 06:11:44 PM Viresh Kumar wrote:
> This is only relevant to implementations with multiple clusters, where clusters
> have separate clock lines but all CPUs within a cluster share it.
> 
> Consider a dual cluster platform with 2 cores per cluster. During suspend we
> start offlining CPUs from 1 to 3. When CPU2 is remove, policy->kobj would be
> moved to CPU3 and when CPU3 goes down we wouldn't free policy or its kobj.
> 
> Now on resume, we will get CPU2 before CPU3 and will call __cpufreq_add_dev().
> We will recover the old policy and update policy->cpu from 3 to 2 from
> update_policy_cpu().
> 
> But the kobj is still tied to CPU3 and wasn't moved to CPU2. We wouldn't create
> a link for CPU2, but would try that while bringing CPU3 online. Which will
> report errors as CPU3 already has kobj assigned to it.
> 
> This bug got introduced with commit 42f921a, which overlooked this scenario.
> 
> To fix this, lets move kobj to the new policy->cpu while bringing first CPU of a
> cluster back. We already have update_policy_cpu() routine which can be updated
> with this change. That would get rid of the cpufreq_nominate_new_policy_cpu() as
> update_policy_cpu() is also called on CPU removal.
> 
> To achieve that we add another parameter to update_policy_cpu() as cpu_dev is
> present with both the callers.
> 
> Fixes: ("42f921a cpufreq: remove sysfs files for CPUs which failed to come back after resume")
> Cc: Stable <stable@vger.kernel.org> # 3.13+
> Reported-by: Bu Yitian <ybu@qti.qualcomm.com>
> Reported-by: Saravana Kannan <skannan@codeaurora.org>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> V1->V2: Move kobject_move() call to update_policy_cpu(), which makes
> cpufreq_nominate_new_policy_cpu() almost empty. So we remove it completely.
> 
> @Yitian: Sorry, but you need to test this again as there were enough
> modifications in V2.
> 
>  drivers/cpufreq/cpufreq.c | 73 +++++++++++++++++++++++------------------------
>  1 file changed, 36 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 62259d2..c81d9ec6 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -1076,10 +1076,20 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
>  	kfree(policy);
>  }
>  
> -static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
> +static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
> +			     struct device *cpu_dev)
>  {
> +	int ret;
> +
>  	if (WARN_ON(cpu == policy->cpu))
> -		return;
> +		return 0;
> +
> +	/* Move kobject to the new policy->cpu */
> +	ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
> +	if (ret) {
> +		pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
> +		return ret;

Previously, we returned -EINVAL in the kobject_move() failure case.  Why are
we changing that now?

> +	}
>  
>  	down_write(&policy->rwsem);
>  
> @@ -1090,6 +1100,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
>  
>  	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
>  			CPUFREQ_UPDATE_POLICY_CPU, policy);
> +
> +	return 0;
>  }
>  
>  static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
> @@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>  	 * by invoking update_policy_cpu().
>  	 */
>  	if (recover_policy && cpu != policy->cpu)
> -		update_policy_cpu(policy, cpu);
> +		WARN_ON(update_policy_cpu(policy, cpu, dev));

This is an arbitrary difference in the handling of update_policy_cpu() return
value.  Why do we want the WARN_ON() here and not in the other place?

Don't we want to recover from kobject_move() failures here as well?

>  	else
>  		policy->cpu = cpu;
>  
> @@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>  	return __cpufreq_add_dev(dev, sif);
>  }
>  
> -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
> -					   unsigned int old_cpu)
> -{
> -	struct device *cpu_dev;
> -	int ret;
> -
> -	/* first sibling now owns the new sysfs dir */
> -	cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
> -
> -	sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
> -	ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
> -	if (ret) {
> -		pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
> -
> -		down_write(&policy->rwsem);
> -		cpumask_set_cpu(old_cpu, policy->cpus);
> -		up_write(&policy->rwsem);

Why don't we need the above three lines in the new code?

> -
> -		ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
> -					"cpufreq");
> -
> -		return -EINVAL;
> -	}
> -
> -	return cpu_dev->id;
> -}
> -
>  static int __cpufreq_remove_dev_prepare(struct device *dev,
>  					struct subsys_interface *sif)
>  {
>  	unsigned int cpu = dev->id, cpus;
> -	int new_cpu, ret;
> +	int ret;
>  	unsigned long flags;
>  	struct cpufreq_policy *policy;
>  
> @@ -1378,14 +1363,28 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
>  	if (cpu != policy->cpu) {
>  		sysfs_remove_link(&dev->kobj, "cpufreq");
>  	} else if (cpus > 1) {
> -		new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
> -		if (new_cpu >= 0) {
> -			update_policy_cpu(policy, new_cpu);
> +		/* Nominate new CPU */
> +		int new_cpu = cpumask_any_but(policy->cpus, cpu);
> +		struct device *cpu_dev = get_cpu_device(new_cpu);
>  
> -			if (!cpufreq_suspended)
> -				pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
> -					 __func__, new_cpu, cpu);
> +		sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
> +		ret = update_policy_cpu(policy, new_cpu, cpu_dev);
> +		if (ret) {
> +			/*
> +			 * To supress compilation warning about return value of
> +			 * sysfs_create_link().
> +			 */
> +			int temp;
> +
> +			/* Create link again if we failed. */
> +			temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
> +						 "cpufreq");

And this is *ugly*.

> +			return ret;
>  		}
> +
> +		if (!cpufreq_suspended)
> +			pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
> +				 __func__, new_cpu, cpu);
>  	} else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
>  		cpufreq_driver->stop_cpu(policy);
>  	}
>
Viresh Kumar July 17, 2014, 12:21 a.m. UTC | #5
On 17 July 2014 04:48, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>> +static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
>> +                          struct device *cpu_dev)
>>  {
>> +     int ret;
>> +
>>       if (WARN_ON(cpu == policy->cpu))
>> -             return;
>> +             return 0;
>> +
>> +     /* Move kobject to the new policy->cpu */
>> +     ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>> +     if (ret) {
>> +             pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>> +             return ret;
>
> Previously, we returned -EINVAL in the kobject_move() failure case.  Why are
> we changing that now?

We should have preserved return value of kobject_move() earlier in
cpufreq_nominate_new_policy_cpu() and sent that, but we returned
-EINVAL. And I realized that its more appropriate to return the error
returned by kobject_move().

>>  static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>> @@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>        * by invoking update_policy_cpu().
>>        */
>>       if (recover_policy && cpu != policy->cpu)
>> -             update_policy_cpu(policy, cpu);
>> +             WARN_ON(update_policy_cpu(policy, cpu, dev));
>
> This is an arbitrary difference in the handling of update_policy_cpu() return
> value.  Why do we want the WARN_ON() here and not in the other place?

We really can't recover in this case. We have reached here after a suspend/
resume, and probing first cpu of a non-boot cluster. And we *have* to make
it policy-master.

But in the other case, we are removing a CPU in PREPARE stage and so
we can actually fail from there and let everybody know. Though I am not
aware of anycase in which kobject_move() can fail there.

> Don't we want to recover from kobject_move() failures here as well?

In the other case, we have just removed the link from the new policy->cpu
and so we try to recover for that in failures, but don't have something
similar here.

>>       else
>>               policy->cpu = cpu;
>>
>> @@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>       return __cpufreq_add_dev(dev, sif);
>>  }
>>
>> -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
>> -                                        unsigned int old_cpu)
>> -{
>> -     struct device *cpu_dev;
>> -     int ret;
>> -
>> -     /* first sibling now owns the new sysfs dir */
>> -     cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
>> -
>> -     sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>> -     ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>> -     if (ret) {
>> -             pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>> -
>> -             down_write(&policy->rwsem);
>> -             cpumask_set_cpu(old_cpu, policy->cpus);
>> -             up_write(&policy->rwsem);
>
> Why don't we need the above three lines in the new code?

It was probably meaningful when this was added initially, but later
some commit moved the cpumask_clear_cpu() to
__cpufreq_remove_dev_finish(). And so we don't really need to
set the cpu to policy->cpus again, as it was never cleared by this
stage..

>> -
>> -             ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>> -                                     "cpufreq");
>> -
>> -             return -EINVAL;
>> -     }
>> -
>> -     return cpu_dev->id;
>> -}
>> -
>>  static int __cpufreq_remove_dev_prepare(struct device *dev,
>>                                       struct subsys_interface *sif)
>>  {
>>       unsigned int cpu = dev->id, cpus;
>> -     int new_cpu, ret;
>> +     int ret;
>>       unsigned long flags;
>>       struct cpufreq_policy *policy;
>>
>> @@ -1378,14 +1363,28 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
>>       if (cpu != policy->cpu) {
>>               sysfs_remove_link(&dev->kobj, "cpufreq");
>>       } else if (cpus > 1) {
>> -             new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
>> -             if (new_cpu >= 0) {
>> -                     update_policy_cpu(policy, new_cpu);
>> +             /* Nominate new CPU */
>> +             int new_cpu = cpumask_any_but(policy->cpus, cpu);
>> +             struct device *cpu_dev = get_cpu_device(new_cpu);
>>
>> -                     if (!cpufreq_suspended)
>> -                             pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
>> -                                      __func__, new_cpu, cpu);
>> +             sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>> +             ret = update_policy_cpu(policy, new_cpu, cpu_dev);
>> +             if (ret) {
>> +                     /*
>> +                      * To supress compilation warning about return value of
>> +                      * sysfs_create_link().
>> +                      */
>> +                     int temp;
>> +
>> +                     /* Create link again if we failed. */
>> +                     temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>> +                                              "cpufreq");
>
> And this is *ugly*.

Absolutely, Let me know what can we do to work around this.
It was like this earlier as well, just that I added a descriptive
comment this time.

--
viresh
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki July 17, 2014, 12:49 a.m. UTC | #6
Quite frankly, to me this patch just does too much in one go without
describing about a half of things it is doing.

I would just add the kobject_move() call to __cpufreq_add_dev() to
start with (because that's what you really want if I'm not mistaken)
and do the cleanups separately, later.

On Thu, Jul 17, 2014 at 2:21 AM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 17 July 2014 04:48, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>>> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>>> +static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
>>> +                          struct device *cpu_dev)
>>>  {
>>> +     int ret;
>>> +
>>>       if (WARN_ON(cpu == policy->cpu))
>>> -             return;
>>> +             return 0;
>>> +
>>> +     /* Move kobject to the new policy->cpu */
>>> +     ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>>> +     if (ret) {
>>> +             pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>>> +             return ret;
>>
>> Previously, we returned -EINVAL in the kobject_move() failure case.  Why are
>> we changing that now?
>
> We should have preserved return value of kobject_move() earlier in
> cpufreq_nominate_new_policy_cpu() and sent that, but we returned
> -EINVAL. And I realized that its more appropriate to return the error
> returned by kobject_move().
>
>>>  static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>> @@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>>        * by invoking update_policy_cpu().
>>>        */
>>>       if (recover_policy && cpu != policy->cpu)
>>> -             update_policy_cpu(policy, cpu);
>>> +             WARN_ON(update_policy_cpu(policy, cpu, dev));
>>
>> This is an arbitrary difference in the handling of update_policy_cpu() return
>> value.  Why do we want the WARN_ON() here and not in the other place?
>
> We really can't recover in this case. We have reached here after a suspend/
> resume, and probing first cpu of a non-boot cluster. And we *have* to make
> it policy-master.
>
> But in the other case, we are removing a CPU in PREPARE stage and so
> we can actually fail from there and let everybody know. Though I am not
> aware of anycase in which kobject_move() can fail there.
>
>> Don't we want to recover from kobject_move() failures here as well?
>
> In the other case, we have just removed the link from the new policy->cpu
> and so we try to recover for that in failures, but don't have something
> similar here.
>
>>>       else
>>>               policy->cpu = cpu;
>>>
>>> @@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
>>>       return __cpufreq_add_dev(dev, sif);
>>>  }
>>>
>>> -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
>>> -                                        unsigned int old_cpu)
>>> -{
>>> -     struct device *cpu_dev;
>>> -     int ret;
>>> -
>>> -     /* first sibling now owns the new sysfs dir */
>>> -     cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
>>> -
>>> -     sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>>> -     ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
>>> -     if (ret) {
>>> -             pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
>>> -
>>> -             down_write(&policy->rwsem);
>>> -             cpumask_set_cpu(old_cpu, policy->cpus);
>>> -             up_write(&policy->rwsem);
>>
>> Why don't we need the above three lines in the new code?
>
> It was probably meaningful when this was added initially, but later
> some commit moved the cpumask_clear_cpu() to
> __cpufreq_remove_dev_finish(). And so we don't really need to
> set the cpu to policy->cpus again, as it was never cleared by this
> stage..
>
>>> -
>>> -             ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>>> -                                     "cpufreq");
>>> -
>>> -             return -EINVAL;
>>> -     }
>>> -
>>> -     return cpu_dev->id;
>>> -}
>>> -
>>>  static int __cpufreq_remove_dev_prepare(struct device *dev,
>>>                                       struct subsys_interface *sif)
>>>  {
>>>       unsigned int cpu = dev->id, cpus;
>>> -     int new_cpu, ret;
>>> +     int ret;
>>>       unsigned long flags;
>>>       struct cpufreq_policy *policy;
>>>
>>> @@ -1378,14 +1363,28 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
>>>       if (cpu != policy->cpu) {
>>>               sysfs_remove_link(&dev->kobj, "cpufreq");
>>>       } else if (cpus > 1) {
>>> -             new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
>>> -             if (new_cpu >= 0) {
>>> -                     update_policy_cpu(policy, new_cpu);
>>> +             /* Nominate new CPU */
>>> +             int new_cpu = cpumask_any_but(policy->cpus, cpu);
>>> +             struct device *cpu_dev = get_cpu_device(new_cpu);
>>>
>>> -                     if (!cpufreq_suspended)
>>> -                             pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
>>> -                                      __func__, new_cpu, cpu);
>>> +             sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
>>> +             ret = update_policy_cpu(policy, new_cpu, cpu_dev);
>>> +             if (ret) {
>>> +                     /*
>>> +                      * To supress compilation warning about return value of
>>> +                      * sysfs_create_link().
>>> +                      */
>>> +                     int temp;
>>> +
>>> +                     /* Create link again if we failed. */
>>> +                     temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
>>> +                                              "cpufreq");
>>
>> And this is *ugly*.
>
> Absolutely, Let me know what can we do to work around this.
> It was like this earlier as well, just that I added a descriptive
> comment this time.
>
> --
> viresh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viresh Kumar July 17, 2014, 4:21 a.m. UTC | #7
On 17 July 2014 06:19, Rafael J. Wysocki <rafael@kernel.org> wrote:
> Quite frankly, to me this patch just does too much in one go without
> describing about a half of things it is doing.
>
> I would just add the kobject_move() call to __cpufreq_add_dev() to
> start with (because that's what you really want if I'm not mistaken)
> and do the cleanups separately, later.

I understand that as I had similar feelings about it. See what I sent
during V1: http://www.spinics.net/lists/stable/msg54338.html

Only when Srivatsa asked me to do the cleanups with it, I went for
V2. And still wasn't really sure about getting that as a bug fix. And
so had a chat with him again and asked you to push V1, and we
will do cleanups later.

So, I don't see V1 in patchworks anymore and I must resend?
I will make out a series out of V2, first patch would be a fix for
3.16 & stable, and others would be for 3.17. Hope that works.

--
viresh
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 62259d2..c81d9ec6 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1076,10 +1076,20 @@  static void cpufreq_policy_free(struct cpufreq_policy *policy)
 	kfree(policy);
 }
 
-static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
+			     struct device *cpu_dev)
 {
+	int ret;
+
 	if (WARN_ON(cpu == policy->cpu))
-		return;
+		return 0;
+
+	/* Move kobject to the new policy->cpu */
+	ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
+	if (ret) {
+		pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
+		return ret;
+	}
 
 	down_write(&policy->rwsem);
 
@@ -1090,6 +1100,8 @@  static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
 
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
 			CPUFREQ_UPDATE_POLICY_CPU, policy);
+
+	return 0;
 }
 
 static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
@@ -1154,7 +1166,7 @@  static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 	 * by invoking update_policy_cpu().
 	 */
 	if (recover_policy && cpu != policy->cpu)
-		update_policy_cpu(policy, cpu);
+		WARN_ON(update_policy_cpu(policy, cpu, dev));
 	else
 		policy->cpu = cpu;
 
@@ -1307,38 +1319,11 @@  static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 	return __cpufreq_add_dev(dev, sif);
 }
 
-static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
-					   unsigned int old_cpu)
-{
-	struct device *cpu_dev;
-	int ret;
-
-	/* first sibling now owns the new sysfs dir */
-	cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
-
-	sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
-	ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
-	if (ret) {
-		pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
-
-		down_write(&policy->rwsem);
-		cpumask_set_cpu(old_cpu, policy->cpus);
-		up_write(&policy->rwsem);
-
-		ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
-					"cpufreq");
-
-		return -EINVAL;
-	}
-
-	return cpu_dev->id;
-}
-
 static int __cpufreq_remove_dev_prepare(struct device *dev,
 					struct subsys_interface *sif)
 {
 	unsigned int cpu = dev->id, cpus;
-	int new_cpu, ret;
+	int ret;
 	unsigned long flags;
 	struct cpufreq_policy *policy;
 
@@ -1378,14 +1363,28 @@  static int __cpufreq_remove_dev_prepare(struct device *dev,
 	if (cpu != policy->cpu) {
 		sysfs_remove_link(&dev->kobj, "cpufreq");
 	} else if (cpus > 1) {
-		new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
-		if (new_cpu >= 0) {
-			update_policy_cpu(policy, new_cpu);
+		/* Nominate new CPU */
+		int new_cpu = cpumask_any_but(policy->cpus, cpu);
+		struct device *cpu_dev = get_cpu_device(new_cpu);
 
-			if (!cpufreq_suspended)
-				pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
-					 __func__, new_cpu, cpu);
+		sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+		ret = update_policy_cpu(policy, new_cpu, cpu_dev);
+		if (ret) {
+			/*
+			 * To supress compilation warning about return value of
+			 * sysfs_create_link().
+			 */
+			int temp;
+
+			/* Create link again if we failed. */
+			temp = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
+						 "cpufreq");
+			return ret;
 		}
+
+		if (!cpufreq_suspended)
+			pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
+				 __func__, new_cpu, cpu);
 	} else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
 		cpufreq_driver->stop_cpu(policy);
 	}