From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [RFC,2/2] dmaengine: xilinx_dma: Add Xilinx AXI MCDMA Engine driver support From: Vinod Koul Message-Id: <20180821154635.GG2388@vkoul-mobl> Date: Tue, 21 Aug 2018 21:16:35 +0530 To: Radhey Shyam Pandey Cc: robh+dt@kernel.org, mark.rutland@arm.com, michal.simek@xilinx.com, dan.j.williams@intel.com, appanad@xilinx.com, lars@metafoo.de, dmaengine@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org List-ID: T24gMzEtMDctMTgsIDIzOjE2LCBSYWRoZXkgU2h5YW0gUGFuZGV5IHdyb3RlOgo+ICBzdHJ1Y3Qg eGlsaW54X2RtYV9jb25maWcgewo+IEBAIC00MDIsNiArNDcwLDcgQEAgc3RydWN0IHhpbGlueF9k bWFfY29uZmlnIHsKPiAgCWludCAoKmNsa19pbml0KShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpw ZGV2LCBzdHJ1Y3QgY2xrICoqYXhpX2NsaywKPiAgCQkJc3RydWN0IGNsayAqKnR4X2Nsaywgc3Ry dWN0IGNsayAqKnR4c19jbGssCj4gIAkJCXN0cnVjdCBjbGsgKipyeF9jbGssIHN0cnVjdCBjbGsg KipyeHNfY2xrKTsKPiArCWlycXJldHVybl90ICgqaXJxX2hhbmRsZXIpKGludCBpcnEsIHZvaWQg KmRhdGEpOwoKdGhpcyBzb3VuZHMgbGlrZSBhIHByZXBhcmF0b3J5IGNoYW5nZT8KCj4gKwl9IGVs c2UgaWYgKGNoYW4tPnhkZXYtPmRtYV9jb25maWctPmRtYXR5cGUgPT0gWERNQV9UWVBFX0FYSU1D RE1BKSB7Cj4gKwkJLyogQWxsb2NhdGUgdGhlIGJ1ZmZlciBkZXNjcmlwdG9ycy4gKi8KPiArCQlj aGFuLT5zZWdfbXYgPSBkbWFfemFsbG9jX2NvaGVyZW50KGNoYW4tPmRldiwKPiArCQkJCQkJICBz aXplb2YoKmNoYW4tPnNlZ19tdikgKgo+ICsJCQkJCQkgIFhJTElOWF9ETUFfTlVNX0RFU0NTLAo+ ICsJCQkJCQkgICZjaGFuLT5zZWdfcCwgR0ZQX0tFUk5FTCk7Cj4gKwkJaWYgKCFjaGFuLT5zZWdf bXYpIHsKPiArCQkJZGV2X2VycihjaGFuLT5kZXYsCj4gKwkJCQkidW5hYmxlIHRvIGFsbG9jYXRl IGNoYW5uZWwgJWQgZGVzY3JpcHRvcnNcbiIsCj4gKwkJCQljaGFuLT5pZCk7Cj4gKwkJCXJldHVy biAtRU5PTUVNOwo+ICsJCX0KPiArCQlmb3IgKGkgPSAwOyBpIDwgWElMSU5YX0RNQV9OVU1fREVT Q1M7IGkrKykgewo+ICsJCQljaGFuLT5zZWdfbXZbaV0uaHcubmV4dF9kZXNjID0KPiArCQkJbG93 ZXJfMzJfYml0cyhjaGFuLT5zZWdfcCArIHNpemVvZigqY2hhbi0+c2VnX212KSAqCj4gKwkJCQko KGkgKyAxKSAlIFhJTElOWF9ETUFfTlVNX0RFU0NTKSk7Cj4gKwkJCWNoYW4tPnNlZ19tdltpXS5o dy5uZXh0X2Rlc2NfbXNiID0KPiArCQkJdXBwZXJfMzJfYml0cyhjaGFuLT5zZWdfcCArIHNpemVv ZigqY2hhbi0+c2VnX212KSAqCj4gKwkJCQkoKGkgKyAxKSAlIFhJTElOWF9ETUFfTlVNX0RFU0NT KSk7Cj4gKwkJCWNoYW4tPnNlZ19tdltpXS5waHlzID0gY2hhbi0+c2VnX3AgKwo+ICsJCQkJc2l6 ZW9mKCpjaGFuLT5zZWdfdikgKiBpOwo+ICsJCQlsaXN0X2FkZF90YWlsKCZjaGFuLT5zZWdfbXZb aV0ubm9kZSwKPiArCQkJCSAgICAgICZjaGFuLT5mcmVlX3NlZ19saXN0KTsKPiArCQl9Cgpvbmx5 IGNoYW5nZSB3aXRoIHRoaXMgYW5kIHByZXZpb3VzIG9uZSBzZWVtcyB0byBiZSB1c2Ugb2Ygc2Vn X212IGluc3RlYWQKb2Ygc2VnX3YgcmlnaHQ/IGlmIHNvLCBjYW4geW91IHRyeSB0byBtb2R1bGFy aXNlIHRoaXMuLgoKPiAgLyoqCj4gKyAqIHhpbGlueF9tY2RtYV9zdGFydF90cmFuc2ZlciAtIFN0 YXJ0cyBNQ0RNQSB0cmFuc2Zlcgo+ICsgKiBAY2hhbjogRHJpdmVyIHNwZWNpZmljIGNoYW5uZWwg c3RydWN0IHBvaW50ZXIKPiArICovCj4gK3N0YXRpYyB2b2lkIHhpbGlueF9tY2RtYV9zdGFydF90 cmFuc2ZlcihzdHJ1Y3QgeGlsaW54X2RtYV9jaGFuICpjaGFuKQo+ICt7Cj4gKwlzdHJ1Y3QgeGls aW54X2RtYV90eF9kZXNjcmlwdG9yICpoZWFkX2Rlc2MsICp0YWlsX2Rlc2M7Cj4gKwlzdHJ1Y3Qg eGlsaW54X2F4aWRtYV90eF9zZWdtZW50ICp0YWlsX3NlZ21lbnQ7Cj4gKwl1MzIgcmVnOwo+ICsK PiArCWlmIChjaGFuLT5lcnIpCj4gKwkJcmV0dXJuOwo+ICsKPiArCWlmICghY2hhbi0+aWRsZSkK PiArCQlyZXR1cm47Cj4gKwo+ICsJaWYgKGxpc3RfZW1wdHkoJmNoYW4tPnBlbmRpbmdfbGlzdCkp Cj4gKwkJcmV0dXJuOwoKb2theSBpIHdhcyB0aGlua2luZyB0aGF0IHdlIG5lZWQgbG9jayBoZXJl LCBidXQgdGhlbiB0aGlzIGlzIGNhbGxlZCB3aXRoCmxvY2sgaGVsZCwgd29ydGggbWVudGlvbmlu ZyBpbiB0aGUgY29tbWVudCB0aG91Z2guLgoKPiArc3RhdGljIGlycXJldHVybl90IHhpbGlueF9t Y2RtYV9pcnFfaGFuZGxlcihpbnQgaXJxLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3QgeGls aW54X2RtYV9jaGFuICpjaGFuID0gZGF0YTsKPiArCXUzMiBzdGF0dXMsIHNlcl9vZmZzZXQsIGNo YW5fc2VybWFzaywgY2hhbl9vZmZzZXQgPSAwLCBjaGFuX2lkOwo+ICsKPiArCWlmIChjaGFuLT5k aXJlY3Rpb24gPT0gRE1BX0RFVl9UT19NRU0pCj4gKwkJc2VyX29mZnNldCA9IFhJTElOWF9NQ0RN QV9SWElOVF9TRVJfT0ZGU0VUOwo+ICsJZWxzZQo+ICsJCXNlcl9vZmZzZXQgPSBYSUxJTlhfTUNE TUFfVFhJTlRfU0VSX09GRlNFVDsKPiArCj4gKwkvKiBSZWFkIHRoZSBjaGFubmVsIGlkIHJhaXNp bmcgdGhlIGludGVycnVwdCovCj4gKwljaGFuX3Nlcm1hc2sgPSBkbWFfY3RybF9yZWFkKGNoYW4s IHNlcl9vZmZzZXQpOwo+ICsJY2hhbl9pZCA9IGZmcyhjaGFuX3Nlcm1hc2spOwo+ICsKPiArCWlm ICghY2hhbl9pZCkKPiArCQlyZXR1cm4gSVJRX05PTkU7Cj4gKwo+ICsJaWYgKGNoYW4tPmRpcmVj dGlvbiA9PSBETUFfREVWX1RPX01FTSkKPiArCQljaGFuX29mZnNldCA9IFhJTElOWF9ETUFfTUFY X0NIQU5TX1BFUl9ERVZJQ0UgLyAyOwo+ICsKPiArCWNoYW5fb2Zmc2V0ID0gY2hhbl9vZmZzZXQg KyAoY2hhbl9pZCAtIDEpOwo+ICsJY2hhbiA9IGNoYW4tPnhkZXYtPmNoYW5bY2hhbl9vZmZzZXRd Owo+ICsJLyogUmVhZCB0aGUgc3RhdHVzIGFuZCBhY2sgdGhlIGludGVycnVwdHMuICovCj4gKwlz dGF0dXMgPSBkbWFfY3RybF9yZWFkKGNoYW4sIFhJTElOWF9NQ0RNQV9DSEFOX1NSX09GRlNFVChj aGFuLT50ZGVzdCkpOwo+ICsJaWYgKCEoc3RhdHVzICYgWElMSU5YX01DRE1BX0lSUV9BTExfTUFT SykpCj4gKwkJcmV0dXJuIElSUV9OT05FOwo+ICsKPiArCWRtYV9jdHJsX3dyaXRlKGNoYW4sIFhJ TElOWF9NQ0RNQV9DSEFOX1NSX09GRlNFVChjaGFuLT50ZGVzdCksCj4gKwkJICAgICAgIHN0YXR1 cyAmIFhJTElOWF9NQ0RNQV9JUlFfQUxMX01BU0spOwo+ICsKPiArCWlmIChzdGF0dXMgJiBYSUxJ TlhfTUNETUFfSVJRX0VSUl9NQVNLKSB7Cj4gKwkJZGV2X2VycihjaGFuLT5kZXYsICJDaGFubmVs ICVwIGhhcyBlcnJvcnMgJXggY2RyICV4IHRkciAleFxuIiwKPiArCQkJY2hhbiwgZG1hX2N0cmxf cmVhZChjaGFuLAo+ICsJCQlYSUxJTlhfTUNETUFfQ0hfRVJSX09GRlNFVCksIGRtYV9jdHJsX3Jl YWQoY2hhbiwKPiArCQkJWElMSU5YX01DRE1BX0NIQU5fQ0RFU0NfT0ZGU0VUKGNoYW4tPnRkZXN0 KSksCj4gKwkJCWRtYV9jdHJsX3JlYWQoY2hhbiwKPiArCQkJCSAgICAgIFhJTElOWF9NQ0RNQV9D SEFOX1RERVNDX09GRlNFVAo+ICsJCQkJICAgICAgKGNoYW4tPnRkZXN0KSkpOwoKdGhpcyBsb29r cyB2ZXJ5IGhhcmQgdG8gcmVhZCwgcGxlYXNlIHN0YXJ0IGVhY2ggZG1hX2N0cmxfcmVhZCgpIGZy b20gYQpuZXcgbGluZSB0byBtYWtlIGl0IGJldHRlcgoKPiArCQljaGFuLT5lcnIgPSB0cnVlOwo+ ICsJfQo+ICsKPiArCWlmIChzdGF0dXMgJiBYSUxJTlhfTUNETUFfSVJRX0RFTEFZX01BU0spIHsK PiArCQkvKgo+ICsJCSAqIERldmljZSB0YWtlcyB0b28gbG9uZyB0byBkbyB0aGUgdHJhbnNmZXIg d2hlbiB1c2VyIHJlcXVpcmVzCj4gKwkJICogcmVzcG9uc2l2ZW5lc3MuCj4gKwkJICovCj4gKwkJ ZGV2X2RiZyhjaGFuLT5kZXYsICJJbnRlci1wYWNrZXQgbGF0ZW5jeSB0b28gbG9uZ1xuIik7Cgpz byB3ZSBqdXN0IGxvZyBpdC4uPwoKPiArCX0KPiArCj4gKwlpZiAoc3RhdHVzICYgWElMSU5YX01D RE1BX0lSUV9JT0NfTUFTSykgewo+ICsJCXNwaW5fbG9jaygmY2hhbi0+bG9jayk7Cj4gKwkJeGls aW54X2RtYV9jb21wbGV0ZV9kZXNjcmlwdG9yKGNoYW4pOwo+ICsJCWNoYW4tPmlkbGUgPSB0cnVl Owo+ICsJCWNoYW4tPnN0YXJ0X3RyYW5zZmVyKGNoYW4pOwo+ICsJCXNwaW5fdW5sb2NrKCZjaGFu LT5sb2NrKTsKPiArCX0KPiArCj4gKwl0YXNrbGV0X3NjaGVkdWxlKCZjaGFuLT50YXNrbGV0KTsK PiArCXJldHVybiBJUlFfSEFORExFRDsKPiArCgpib2d1cyBlbXB0eSBsaW5lLi4uCgo+ICtzdGF0 aWMgc3RydWN0IGRtYV9hc3luY190eF9kZXNjcmlwdG9yICp4aWxpbnhfbWNkbWFfcHJlcF9zbGF2 ZV9zZygKPiArCXN0cnVjdCBkbWFfY2hhbiAqZGNoYW4sIHN0cnVjdCBzY2F0dGVybGlzdCAqc2ds LCB1bnNpZ25lZCBpbnQgc2dfbGVuLAo+ICsJZW51bSBkbWFfdHJhbnNmZXJfZGlyZWN0aW9uIGRp cmVjdGlvbiwgdW5zaWduZWQgbG9uZyBmbGFncywKPiArCXZvaWQgKmNvbnRleHQpCgppbmRlbnQg aXMgcHJldHR5IGJhZCBoZXJlIHRvbyA6KAoKPiArewo+ICsJc3RydWN0IHhpbGlueF9kbWFfY2hh biAqY2hhbiA9IHRvX3hpbGlueF9jaGFuKGRjaGFuKTsKPiArCXN0cnVjdCB4aWxpbnhfZG1hX3R4 X2Rlc2NyaXB0b3IgKmRlc2M7Cj4gKwlzdHJ1Y3QgeGlsaW54X2F4aW1jZG1hX3R4X3NlZ21lbnQg KnNlZ21lbnQgPSBOVUxMOwo+ICsJdTMyICphcHBfdyA9ICh1MzIgKiljb250ZXh0Owo+ICsJc3Ry dWN0IHNjYXR0ZXJsaXN0ICpzZzsKPiArCXNpemVfdCBjb3B5Owo+ICsJc2l6ZV90IHNnX3VzZWQ7 Cj4gKwl1bnNpZ25lZCBpbnQgaTsKPiArCj4gKwlpZiAoIWlzX3NsYXZlX2RpcmVjdGlvbihkaXJl Y3Rpb24pKQo+ICsJCXJldHVybiBOVUxMOwo+ICsKPiArCS8qIEFsbG9jYXRlIGEgdHJhbnNhY3Rp b24gZGVzY3JpcHRvci4gKi8KPiArCWRlc2MgPSB4aWxpbnhfZG1hX2FsbG9jX3R4X2Rlc2NyaXB0 b3IoY2hhbik7Cj4gKwlpZiAoIWRlc2MpCj4gKwkJcmV0dXJuIE5VTEw7Cj4gKwo+ICsJZG1hX2Fz eW5jX3R4X2Rlc2NyaXB0b3JfaW5pdCgmZGVzYy0+YXN5bmNfdHgsICZjaGFuLT5jb21tb24pOwo+ ICsJZGVzYy0+YXN5bmNfdHgudHhfc3VibWl0ID0geGlsaW54X2RtYV90eF9zdWJtaXQ7Cj4gKwo+ ICsJLyogQnVpbGQgdHJhbnNhY3Rpb25zIHVzaW5nIGluZm9ybWF0aW9uIGluIHRoZSBzY2F0dGVy IGdhdGhlciBsaXN0ICovCj4gKwlmb3JfZWFjaF9zZyhzZ2wsIHNnLCBzZ19sZW4sIGkpIHsKPiAr CQlzZ191c2VkID0gMDsKPiArCj4gKwkJLyogTG9vcCB1bnRpbCB0aGUgZW50aXJlIHNjYXR0ZXJs aXN0IGVudHJ5IGlzIHVzZWQgKi8KPiArCQl3aGlsZSAoc2dfdXNlZCA8IHNnX2RtYV9sZW4oc2cp KSB7Cj4gKwkJCXN0cnVjdCB4aWxpbnhfYXhpbWNkbWFfZGVzY19odyAqaHc7Cj4gKwo+ICsJCQkv KiBHZXQgYSBmcmVlIHNlZ21lbnQgKi8KPiArCQkJc2VnbWVudCA9IHhpbGlueF9heGltY2RtYV9h bGxvY190eF9zZWdtZW50KGNoYW4pOwo+ICsJCQlpZiAoIXNlZ21lbnQpCj4gKwkJCQlnb3RvIGVy cm9yOwo+ICsKPiArCQkJLyoKPiArCQkJICogQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIG51bWJlciBv ZiBieXRlcyB0byB0cmFuc2ZlciwKPiArCQkJICogbWFraW5nIHN1cmUgaXQgaXMgbGVzcyB0aGFu IHRoZSBodyBsaW1pdAo+ICsJCQkgKi8KPiArCQkJY29weSA9IG1pbl90KHNpemVfdCwgc2dfZG1h X2xlbihzZykgLSBzZ191c2VkLAo+ICsJCQkJICAgICBYSUxJTlhfRE1BX01BWF9UUkFOU19MRU4p Owo+ICsJCQlodyA9ICZzZWdtZW50LT5odzsKPiArCj4gKwkJCS8qIEZpbGwgaW4gdGhlIGRlc2Ny aXB0b3IgKi8KPiArCQkJeGlsaW54X2F4aW1jZG1hX2J1ZihjaGFuLCBodywgc2dfZG1hX2FkZHJl c3Moc2cpLAo+ICsJCQkJCSAgICBzZ191c2VkKTsKPiArCQkJaHctPmNvbnRyb2wgPSBjb3B5Owo+ ICsKPiArCQkJaWYgKGNoYW4tPmRpcmVjdGlvbiA9PSBETUFfTUVNX1RPX0RFVikgewo+ICsJCQkJ aWYgKGFwcF93KQoKd2h5IG5vdCBtYWtlIGNvbmRpdGlvbiBhczogY2hhbi0+ZGlyZWN0aW9uID09 IERNQV9NRU1fVE9fREVWICYmIGFwcF93Cgo+ICsJCQkJCW1lbWNweShody0+YXBwLCBhcHBfdywg c2l6ZW9mKHUzMikgKgo+ICsJCQkJCSAgICAgICBYSUxJTlhfRE1BX05VTV9BUFBfV09SRFMpOwo+ ICsJCQl9Cj4gKwo+ICsJCQlzZ191c2VkICs9IGNvcHk7Cj4gKwkJCS8qCj4gKwkJCSAqIEluc2Vy dCB0aGUgc2VnbWVudCBpbnRvIHRoZSBkZXNjcmlwdG9yIHNlZ21lbnRzCj4gKwkJCSAqIGxpc3Qu Cj4gKwkJCSAqLwo+ICsJCQlsaXN0X2FkZF90YWlsKCZzZWdtZW50LT5ub2RlLCAmZGVzYy0+c2Vn bWVudHMpOwo+ICsJCX0KPiArCX0KPiArCj4gKwlzZWdtZW50ID0gbGlzdF9maXJzdF9lbnRyeSgm ZGVzYy0+c2VnbWVudHMsCj4gKwkJCQkgICBzdHJ1Y3QgeGlsaW54X2F4aW1jZG1hX3R4X3NlZ21l bnQsIG5vZGUpOwo+ICsJZGVzYy0+YXN5bmNfdHgucGh5cyA9IHNlZ21lbnQtPnBoeXM7Cj4gKwo+ ICsJLyogRm9yIHRoZSBsYXN0IERNQV9NRU1fVE9fREVWIHRyYW5zZmVyLCBzZXQgRU9QICovCj4g KwlpZiAoY2hhbi0+ZGlyZWN0aW9uID09IERNQV9NRU1fVE9fREVWKSB7Cj4gKwkJc2VnbWVudC0+ aHcuY29udHJvbCB8PSBYSUxJTlhfTUNETUFfQkRfU09QOwo+ICsJCXNlZ21lbnQgPSBsaXN0X2xh c3RfZW50cnkoJmRlc2MtPnNlZ21lbnRzLAo+ICsJCQkJCSAgc3RydWN0IHhpbGlueF9heGltY2Rt YV90eF9zZWdtZW50LAo+ICsJCQkJCSAgbm9kZSk7Cj4gKwkJc2VnbWVudC0+aHcuY29udHJvbCB8 PSBYSUxJTlhfTUNETUFfQkRfRU9QOwo+ICsJfQo+ICsKPiArCXJldHVybiAmZGVzYy0+YXN5bmNf dHg7Cj4gKwo+ICtlcnJvcjoKPiArCXhpbGlueF9kbWFfZnJlZV90eF9kZXNjcmlwdG9yKGNoYW4s IGRlc2MpOwoKd2lsbCBpdCBmcmVlIHRoZSBvbmVzIGFsbG9jYXRlZCBoZXJlIG9yIGFsbCBkZXNj cmlwdG9ycz8KCj4gIC8qKgo+ICAgKiB4aWxpbnhfZG1hX3ByZXBfc2xhdmVfc2cgLSBwcmVwYXJl IGRlc2NyaXB0b3JzIGZvciBhIERNQV9TTEFWRSB0cmFuc2FjdGlvbgo+IEBAIC0yNDIyLDEyICsy ODI3LDE2IEBAIHN0YXRpYyBpbnQgeGlsaW54X2RtYV9jaGFuX3Byb2JlKHN0cnVjdCB4aWxpbnhf ZG1hX2RldmljZSAqeGRldiwKPiAgCj4gIAlpZiAob2ZfZGV2aWNlX2lzX2NvbXBhdGlibGUobm9k ZSwgInhsbngsYXhpLXZkbWEtbW0ycy1jaGFubmVsIikgfHwKPiAgCSAgICBvZl9kZXZpY2VfaXNf Y29tcGF0aWJsZShub2RlLCAieGxueCxheGktZG1hLW1tMnMtY2hhbm5lbCIpIHx8Cj4gLQkgICAg b2ZfZGV2aWNlX2lzX2NvbXBhdGlibGUobm9kZSwgInhsbngsYXhpLWNkbWEtY2hhbm5lbCIpKSB7 Cj4gKwkgICAgb2ZfZGV2aWNlX2lzX2NvbXBhdGlibGUobm9kZSwgInhsbngsYXhpLWNkbWEtY2hh bm5lbCIpIHx8Cj4gKwkgICAgb2ZfZGV2aWNlX2lzX2NvbXBhdGlibGUobm9kZSwgInhsbngsYXhp LW1jZG1hLW1tMnMtY2hhbm5lbCIpKSB7Cgp0aGlzIGlzIG5vdCBzY2FsaW5nLCBtYXliZSB5b3Ug c2hvdWxkIHVzZSBkYXRhIHdpdGggZWFjaApjb21wYXRpYmxlIHRvIGNoZWNrIGZvciBzcGVjaWZp YyB0aGluZ3MuLgoKPiArc3RhdGljIGNvbnN0IHN0cnVjdCB4aWxpbnhfZG1hX2NvbmZpZyBheGlt Y2RtYV9jb25maWcgPSB7Cj4gKwkuZG1hdHlwZSA9IFhETUFfVFlQRV9BWElNQ0RNQSwKPiArCS5j bGtfaW5pdCA9IGF4aWRtYV9jbGtfaW5pdCwKPiArCS5pcnFfaGFuZGxlciA9IHhpbGlueF9tY2Rt YV9pcnFfaGFuZGxlciwKPiArfTsKPiAgc3RhdGljIGNvbnN0IHN0cnVjdCB4aWxpbnhfZG1hX2Nv bmZpZyBheGljZG1hX2NvbmZpZyA9IHsKPiAgCS5kbWF0eXBlID0gWERNQV9UWVBFX0NETUEsCj4g IAkuY2xrX2luaXQgPSBheGljZG1hX2Nsa19pbml0LAo+ICsJLmlycV9oYW5kbGVyID0geGlsaW54 X2RtYV9pcnFfaGFuZGxlciwKCnRoaXMgc2hvdWxkIGJlIGluIHByZXBhcmF0b3J5IHBhdGNoCg== From mboxrd@z Thu Jan 1 00:00:00 1970 From: vkoul@kernel.org (Vinod) Date: Tue, 21 Aug 2018 21:16:35 +0530 Subject: [RFC PATCH 2/2] dmaengine: xilinx_dma: Add Xilinx AXI MCDMA Engine driver support In-Reply-To: <1533059173-21405-3-git-send-email-radhey.shyam.pandey@xilinx.com> References: <1533059173-21405-1-git-send-email-radhey.shyam.pandey@xilinx.com> <1533059173-21405-3-git-send-email-radhey.shyam.pandey@xilinx.com> Message-ID: <20180821154635.GG2388@vkoul-mobl> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 31-07-18, 23:16, Radhey Shyam Pandey wrote: > struct xilinx_dma_config { > @@ -402,6 +470,7 @@ struct xilinx_dma_config { > int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk, > struct clk **tx_clk, struct clk **txs_clk, > struct clk **rx_clk, struct clk **rxs_clk); > + irqreturn_t (*irq_handler)(int irq, void *data); this sounds like a preparatory change? > + } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) { > + /* Allocate the buffer descriptors. */ > + chan->seg_mv = dma_zalloc_coherent(chan->dev, > + sizeof(*chan->seg_mv) * > + XILINX_DMA_NUM_DESCS, > + &chan->seg_p, GFP_KERNEL); > + if (!chan->seg_mv) { > + dev_err(chan->dev, > + "unable to allocate channel %d descriptors\n", > + chan->id); > + return -ENOMEM; > + } > + for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) { > + chan->seg_mv[i].hw.next_desc = > + lower_32_bits(chan->seg_p + sizeof(*chan->seg_mv) * > + ((i + 1) % XILINX_DMA_NUM_DESCS)); > + chan->seg_mv[i].hw.next_desc_msb = > + upper_32_bits(chan->seg_p + sizeof(*chan->seg_mv) * > + ((i + 1) % XILINX_DMA_NUM_DESCS)); > + chan->seg_mv[i].phys = chan->seg_p + > + sizeof(*chan->seg_v) * i; > + list_add_tail(&chan->seg_mv[i].node, > + &chan->free_seg_list); > + } only change with this and previous one seems to be use of seg_mv instead of seg_v right? if so, can you try to modularise this.. > /** > + * xilinx_mcdma_start_transfer - Starts MCDMA transfer > + * @chan: Driver specific channel struct pointer > + */ > +static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan) > +{ > + struct xilinx_dma_tx_descriptor *head_desc, *tail_desc; > + struct xilinx_axidma_tx_segment *tail_segment; > + u32 reg; > + > + if (chan->err) > + return; > + > + if (!chan->idle) > + return; > + > + if (list_empty(&chan->pending_list)) > + return; okay i was thinking that we need lock here, but then this is called with lock held, worth mentioning in the comment though.. > +static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data) > +{ > + struct xilinx_dma_chan *chan = data; > + u32 status, ser_offset, chan_sermask, chan_offset = 0, chan_id; > + > + if (chan->direction == DMA_DEV_TO_MEM) > + ser_offset = XILINX_MCDMA_RXINT_SER_OFFSET; > + else > + ser_offset = XILINX_MCDMA_TXINT_SER_OFFSET; > + > + /* Read the channel id raising the interrupt*/ > + chan_sermask = dma_ctrl_read(chan, ser_offset); > + chan_id = ffs(chan_sermask); > + > + if (!chan_id) > + return IRQ_NONE; > + > + if (chan->direction == DMA_DEV_TO_MEM) > + chan_offset = XILINX_DMA_MAX_CHANS_PER_DEVICE / 2; > + > + chan_offset = chan_offset + (chan_id - 1); > + chan = chan->xdev->chan[chan_offset]; > + /* Read the status and ack the interrupts. */ > + status = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest)); > + if (!(status & XILINX_MCDMA_IRQ_ALL_MASK)) > + return IRQ_NONE; > + > + dma_ctrl_write(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest), > + status & XILINX_MCDMA_IRQ_ALL_MASK); > + > + if (status & XILINX_MCDMA_IRQ_ERR_MASK) { > + dev_err(chan->dev, "Channel %p has errors %x cdr %x tdr %x\n", > + chan, dma_ctrl_read(chan, > + XILINX_MCDMA_CH_ERR_OFFSET), dma_ctrl_read(chan, > + XILINX_MCDMA_CHAN_CDESC_OFFSET(chan->tdest)), > + dma_ctrl_read(chan, > + XILINX_MCDMA_CHAN_TDESC_OFFSET > + (chan->tdest))); this looks very hard to read, please start each dma_ctrl_read() from a new line to make it better > + chan->err = true; > + } > + > + if (status & XILINX_MCDMA_IRQ_DELAY_MASK) { > + /* > + * Device takes too long to do the transfer when user requires > + * responsiveness. > + */ > + dev_dbg(chan->dev, "Inter-packet latency too long\n"); so we just log it..? > + } > + > + if (status & XILINX_MCDMA_IRQ_IOC_MASK) { > + spin_lock(&chan->lock); > + xilinx_dma_complete_descriptor(chan); > + chan->idle = true; > + chan->start_transfer(chan); > + spin_unlock(&chan->lock); > + } > + > + tasklet_schedule(&chan->tasklet); > + return IRQ_HANDLED; > + bogus empty line... > +static struct dma_async_tx_descriptor *xilinx_mcdma_prep_slave_sg( > + struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, > + enum dma_transfer_direction direction, unsigned long flags, > + void *context) indent is pretty bad here too :( > +{ > + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); > + struct xilinx_dma_tx_descriptor *desc; > + struct xilinx_aximcdma_tx_segment *segment = NULL; > + u32 *app_w = (u32 *)context; > + struct scatterlist *sg; > + size_t copy; > + size_t sg_used; > + unsigned int i; > + > + if (!is_slave_direction(direction)) > + return NULL; > + > + /* Allocate a transaction descriptor. */ > + desc = xilinx_dma_alloc_tx_descriptor(chan); > + if (!desc) > + return NULL; > + > + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); > + desc->async_tx.tx_submit = xilinx_dma_tx_submit; > + > + /* Build transactions using information in the scatter gather list */ > + for_each_sg(sgl, sg, sg_len, i) { > + sg_used = 0; > + > + /* Loop until the entire scatterlist entry is used */ > + while (sg_used < sg_dma_len(sg)) { > + struct xilinx_aximcdma_desc_hw *hw; > + > + /* Get a free segment */ > + segment = xilinx_aximcdma_alloc_tx_segment(chan); > + if (!segment) > + goto error; > + > + /* > + * Calculate the maximum number of bytes to transfer, > + * making sure it is less than the hw limit > + */ > + copy = min_t(size_t, sg_dma_len(sg) - sg_used, > + XILINX_DMA_MAX_TRANS_LEN); > + hw = &segment->hw; > + > + /* Fill in the descriptor */ > + xilinx_aximcdma_buf(chan, hw, sg_dma_address(sg), > + sg_used); > + hw->control = copy; > + > + if (chan->direction == DMA_MEM_TO_DEV) { > + if (app_w) why not make condition as: chan->direction == DMA_MEM_TO_DEV && app_w > + memcpy(hw->app, app_w, sizeof(u32) * > + XILINX_DMA_NUM_APP_WORDS); > + } > + > + sg_used += copy; > + /* > + * Insert the segment into the descriptor segments > + * list. > + */ > + list_add_tail(&segment->node, &desc->segments); > + } > + } > + > + segment = list_first_entry(&desc->segments, > + struct xilinx_aximcdma_tx_segment, node); > + desc->async_tx.phys = segment->phys; > + > + /* For the last DMA_MEM_TO_DEV transfer, set EOP */ > + if (chan->direction == DMA_MEM_TO_DEV) { > + segment->hw.control |= XILINX_MCDMA_BD_SOP; > + segment = list_last_entry(&desc->segments, > + struct xilinx_aximcdma_tx_segment, > + node); > + segment->hw.control |= XILINX_MCDMA_BD_EOP; > + } > + > + return &desc->async_tx; > + > +error: > + xilinx_dma_free_tx_descriptor(chan, desc); will it free the ones allocated here or all descriptors? > /** > * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction > @@ -2422,12 +2827,16 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, > > if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") || > of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") || > - of_device_is_compatible(node, "xlnx,axi-cdma-channel")) { > + of_device_is_compatible(node, "xlnx,axi-cdma-channel") || > + of_device_is_compatible(node, "xlnx,axi-mcdma-mm2s-channel")) { this is not scaling, maybe you should use data with each compatible to check for specific things.. > +static const struct xilinx_dma_config aximcdma_config = { > + .dmatype = XDMA_TYPE_AXIMCDMA, > + .clk_init = axidma_clk_init, > + .irq_handler = xilinx_mcdma_irq_handler, > +}; > static const struct xilinx_dma_config axicdma_config = { > .dmatype = XDMA_TYPE_CDMA, > .clk_init = axicdma_clk_init, > + .irq_handler = xilinx_dma_irq_handler, this should be in preparatory patch -- ~Vinod From mboxrd@z Thu Jan 1 00:00:00 1970 From: Vinod Subject: Re: [RFC PATCH 2/2] dmaengine: xilinx_dma: Add Xilinx AXI MCDMA Engine driver support Date: Tue, 21 Aug 2018 21:16:35 +0530 Message-ID: <20180821154635.GG2388@vkoul-mobl> References: <1533059173-21405-1-git-send-email-radhey.shyam.pandey@xilinx.com> <1533059173-21405-3-git-send-email-radhey.shyam.pandey@xilinx.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Return-path: Content-Disposition: inline In-Reply-To: <1533059173-21405-3-git-send-email-radhey.shyam.pandey@xilinx.com> Sender: linux-kernel-owner@vger.kernel.org To: Radhey Shyam Pandey Cc: robh+dt@kernel.org, mark.rutland@arm.com, michal.simek@xilinx.com, dan.j.williams@intel.com, appanad@xilinx.com, lars@metafoo.de, dmaengine@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org List-Id: devicetree@vger.kernel.org On 31-07-18, 23:16, Radhey Shyam Pandey wrote: > struct xilinx_dma_config { > @@ -402,6 +470,7 @@ struct xilinx_dma_config { > int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk, > struct clk **tx_clk, struct clk **txs_clk, > struct clk **rx_clk, struct clk **rxs_clk); > + irqreturn_t (*irq_handler)(int irq, void *data); this sounds like a preparatory change? > + } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) { > + /* Allocate the buffer descriptors. */ > + chan->seg_mv = dma_zalloc_coherent(chan->dev, > + sizeof(*chan->seg_mv) * > + XILINX_DMA_NUM_DESCS, > + &chan->seg_p, GFP_KERNEL); > + if (!chan->seg_mv) { > + dev_err(chan->dev, > + "unable to allocate channel %d descriptors\n", > + chan->id); > + return -ENOMEM; > + } > + for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) { > + chan->seg_mv[i].hw.next_desc = > + lower_32_bits(chan->seg_p + sizeof(*chan->seg_mv) * > + ((i + 1) % XILINX_DMA_NUM_DESCS)); > + chan->seg_mv[i].hw.next_desc_msb = > + upper_32_bits(chan->seg_p + sizeof(*chan->seg_mv) * > + ((i + 1) % XILINX_DMA_NUM_DESCS)); > + chan->seg_mv[i].phys = chan->seg_p + > + sizeof(*chan->seg_v) * i; > + list_add_tail(&chan->seg_mv[i].node, > + &chan->free_seg_list); > + } only change with this and previous one seems to be use of seg_mv instead of seg_v right? if so, can you try to modularise this.. > /** > + * xilinx_mcdma_start_transfer - Starts MCDMA transfer > + * @chan: Driver specific channel struct pointer > + */ > +static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan) > +{ > + struct xilinx_dma_tx_descriptor *head_desc, *tail_desc; > + struct xilinx_axidma_tx_segment *tail_segment; > + u32 reg; > + > + if (chan->err) > + return; > + > + if (!chan->idle) > + return; > + > + if (list_empty(&chan->pending_list)) > + return; okay i was thinking that we need lock here, but then this is called with lock held, worth mentioning in the comment though.. > +static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data) > +{ > + struct xilinx_dma_chan *chan = data; > + u32 status, ser_offset, chan_sermask, chan_offset = 0, chan_id; > + > + if (chan->direction == DMA_DEV_TO_MEM) > + ser_offset = XILINX_MCDMA_RXINT_SER_OFFSET; > + else > + ser_offset = XILINX_MCDMA_TXINT_SER_OFFSET; > + > + /* Read the channel id raising the interrupt*/ > + chan_sermask = dma_ctrl_read(chan, ser_offset); > + chan_id = ffs(chan_sermask); > + > + if (!chan_id) > + return IRQ_NONE; > + > + if (chan->direction == DMA_DEV_TO_MEM) > + chan_offset = XILINX_DMA_MAX_CHANS_PER_DEVICE / 2; > + > + chan_offset = chan_offset + (chan_id - 1); > + chan = chan->xdev->chan[chan_offset]; > + /* Read the status and ack the interrupts. */ > + status = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest)); > + if (!(status & XILINX_MCDMA_IRQ_ALL_MASK)) > + return IRQ_NONE; > + > + dma_ctrl_write(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest), > + status & XILINX_MCDMA_IRQ_ALL_MASK); > + > + if (status & XILINX_MCDMA_IRQ_ERR_MASK) { > + dev_err(chan->dev, "Channel %p has errors %x cdr %x tdr %x\n", > + chan, dma_ctrl_read(chan, > + XILINX_MCDMA_CH_ERR_OFFSET), dma_ctrl_read(chan, > + XILINX_MCDMA_CHAN_CDESC_OFFSET(chan->tdest)), > + dma_ctrl_read(chan, > + XILINX_MCDMA_CHAN_TDESC_OFFSET > + (chan->tdest))); this looks very hard to read, please start each dma_ctrl_read() from a new line to make it better > + chan->err = true; > + } > + > + if (status & XILINX_MCDMA_IRQ_DELAY_MASK) { > + /* > + * Device takes too long to do the transfer when user requires > + * responsiveness. > + */ > + dev_dbg(chan->dev, "Inter-packet latency too long\n"); so we just log it..? > + } > + > + if (status & XILINX_MCDMA_IRQ_IOC_MASK) { > + spin_lock(&chan->lock); > + xilinx_dma_complete_descriptor(chan); > + chan->idle = true; > + chan->start_transfer(chan); > + spin_unlock(&chan->lock); > + } > + > + tasklet_schedule(&chan->tasklet); > + return IRQ_HANDLED; > + bogus empty line... > +static struct dma_async_tx_descriptor *xilinx_mcdma_prep_slave_sg( > + struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, > + enum dma_transfer_direction direction, unsigned long flags, > + void *context) indent is pretty bad here too :( > +{ > + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); > + struct xilinx_dma_tx_descriptor *desc; > + struct xilinx_aximcdma_tx_segment *segment = NULL; > + u32 *app_w = (u32 *)context; > + struct scatterlist *sg; > + size_t copy; > + size_t sg_used; > + unsigned int i; > + > + if (!is_slave_direction(direction)) > + return NULL; > + > + /* Allocate a transaction descriptor. */ > + desc = xilinx_dma_alloc_tx_descriptor(chan); > + if (!desc) > + return NULL; > + > + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); > + desc->async_tx.tx_submit = xilinx_dma_tx_submit; > + > + /* Build transactions using information in the scatter gather list */ > + for_each_sg(sgl, sg, sg_len, i) { > + sg_used = 0; > + > + /* Loop until the entire scatterlist entry is used */ > + while (sg_used < sg_dma_len(sg)) { > + struct xilinx_aximcdma_desc_hw *hw; > + > + /* Get a free segment */ > + segment = xilinx_aximcdma_alloc_tx_segment(chan); > + if (!segment) > + goto error; > + > + /* > + * Calculate the maximum number of bytes to transfer, > + * making sure it is less than the hw limit > + */ > + copy = min_t(size_t, sg_dma_len(sg) - sg_used, > + XILINX_DMA_MAX_TRANS_LEN); > + hw = &segment->hw; > + > + /* Fill in the descriptor */ > + xilinx_aximcdma_buf(chan, hw, sg_dma_address(sg), > + sg_used); > + hw->control = copy; > + > + if (chan->direction == DMA_MEM_TO_DEV) { > + if (app_w) why not make condition as: chan->direction == DMA_MEM_TO_DEV && app_w > + memcpy(hw->app, app_w, sizeof(u32) * > + XILINX_DMA_NUM_APP_WORDS); > + } > + > + sg_used += copy; > + /* > + * Insert the segment into the descriptor segments > + * list. > + */ > + list_add_tail(&segment->node, &desc->segments); > + } > + } > + > + segment = list_first_entry(&desc->segments, > + struct xilinx_aximcdma_tx_segment, node); > + desc->async_tx.phys = segment->phys; > + > + /* For the last DMA_MEM_TO_DEV transfer, set EOP */ > + if (chan->direction == DMA_MEM_TO_DEV) { > + segment->hw.control |= XILINX_MCDMA_BD_SOP; > + segment = list_last_entry(&desc->segments, > + struct xilinx_aximcdma_tx_segment, > + node); > + segment->hw.control |= XILINX_MCDMA_BD_EOP; > + } > + > + return &desc->async_tx; > + > +error: > + xilinx_dma_free_tx_descriptor(chan, desc); will it free the ones allocated here or all descriptors? > /** > * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction > @@ -2422,12 +2827,16 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, > > if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") || > of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") || > - of_device_is_compatible(node, "xlnx,axi-cdma-channel")) { > + of_device_is_compatible(node, "xlnx,axi-cdma-channel") || > + of_device_is_compatible(node, "xlnx,axi-mcdma-mm2s-channel")) { this is not scaling, maybe you should use data with each compatible to check for specific things.. > +static const struct xilinx_dma_config aximcdma_config = { > + .dmatype = XDMA_TYPE_AXIMCDMA, > + .clk_init = axidma_clk_init, > + .irq_handler = xilinx_mcdma_irq_handler, > +}; > static const struct xilinx_dma_config axicdma_config = { > .dmatype = XDMA_TYPE_CDMA, > .clk_init = axicdma_clk_init, > + .irq_handler = xilinx_dma_irq_handler, this should be in preparatory patch -- ~Vinod