Message ID | 1461235118-800-4-git-send-email-appanad@xilinx.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
On Thu, 2016-04-21 at 16:08:38 +0530, Kedareswara rao Appana wrote: > Added basic clock support for axi dma's. > The clocks are requested at probe and released at remove. > > Reviewed-by: Shubhrajyoti Datta <shubhraj@xilinx.com> > Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com> > --- > Changes for v3: > ---> Added clock support for all the AXI DMA's. > ---> Fixed clk_unprepare leak during probe fail as suggested by Moritz. > ---> Fixed comment driver specifically asks for the clocks it needs and return > an error if a mandatory clock is missing as suggested by soren. > Changes for v2: > ---> None. > > drivers/dma/xilinx/xilinx_vdma.c | 225 ++++++++++++++++++++++++++++++++++++++- > 1 file changed, 223 insertions(+), 2 deletions(-) > > diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c > index 5bfaa32..41bb5b3 100644 > --- a/drivers/dma/xilinx/xilinx_vdma.c > +++ b/drivers/dma/xilinx/xilinx_vdma.c > @@ -44,6 +44,7 @@ > #include <linux/of_platform.h> > #include <linux/of_irq.h> > #include <linux/slab.h> > +#include <linux/clk.h> > > #include "../dmaengine.h" > > @@ -344,6 +345,9 @@ struct xilinx_dma_chan { > > struct dma_config { > enum xdma_ip_type dmatype; > + 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); > }; > > /** > @@ -365,7 +369,13 @@ struct xilinx_dma_device { > bool has_sg; > u32 flush_on_fsync; > bool ext_addr; > + struct platform_device *pdev; > const struct dma_config *dma_config; > + struct clk *axi_clk; > + struct clk *tx_clk; > + struct clk *txs_clk; > + struct clk *rx_clk; > + struct clk *rxs_clk; > }; the struct members could be documented > > /* Macros */ > @@ -1757,6 +1767,200 @@ static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan) > list_del(&chan->common.device_node); > } > > +static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk, > + struct clk **tx_clk, struct clk **rx_clk, > + struct clk **sg_clk, struct clk **tmp_clk) > +{ > + int err; > + > + *tmp_clk = NULL; > + > + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); > + if (IS_ERR(*axi_clk)) { > + err = PTR_ERR(*axi_clk); > + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); > + return err; > + } > + > + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); > + if (IS_ERR(*tx_clk)) > + *tx_clk = NULL; > + > + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); > + if (IS_ERR(*rx_clk)) > + *rx_clk = NULL; > + > + *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk"); > + if (IS_ERR(*sg_clk)) > + *sg_clk = NULL; > + > + > + err = clk_prepare_enable(*axi_clk); Should this be called if you know that the pointer might be NULL? > + if (err) { > + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); > + return err; > + } > + > + err = clk_prepare_enable(*tx_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); > + goto err_disable_axiclk; > + } > + > + err = clk_prepare_enable(*rx_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err); > + goto err_disable_txclk; > + } > + > + err = clk_prepare_enable(*sg_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err); > + goto err_disable_rxclk; > + } > + > + return 0; > + > +err_disable_rxclk: > + clk_disable_unprepare(*rx_clk); > +err_disable_txclk: > + clk_disable_unprepare(*tx_clk); > +err_disable_axiclk: > + clk_disable_unprepare(*axi_clk); > + > + return err; > +} > + > +static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk, > + struct clk **dev_clk, struct clk **tmp_clk, > + struct clk **tmp1_clk, struct clk **tmp2_clk) > +{ > + int err; > + > + *tmp_clk = NULL; > + *tmp1_clk = NULL; > + *tmp2_clk = NULL; > + > + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); > + if (IS_ERR(*axi_clk)) { > + err = PTR_ERR(*axi_clk); > + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); > + return err; > + } > + > + *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk"); > + if (IS_ERR(*dev_clk)) > + *dev_clk = NULL; This is a required clock according to binding but a failure is ignored here. > + > + > + err = clk_prepare_enable(*axi_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); > + return err; > + } > + > + err = clk_prepare_enable(*dev_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); > + goto err_disable_axiclk; > + } > + > + > + return 0; > + > +err_disable_axiclk: > + clk_disable_unprepare(*axi_clk); > + > + return err; > +} > + > +static int axivdma_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) > +{ > + int err; > + > + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); > + if (IS_ERR(*axi_clk)) { > + err = PTR_ERR(*axi_clk); > + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); > + return err; > + } > + > + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); > + if (IS_ERR(*tx_clk)) > + *tx_clk = NULL; > + > + *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk"); > + if (IS_ERR(*txs_clk)) > + *txs_clk = NULL; > + > + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); > + if (IS_ERR(*rx_clk)) > + *rx_clk = NULL; > + > + *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk"); > + if (IS_ERR(*rxs_clk)) > + *rxs_clk = NULL; > + > + > + err = clk_prepare_enable(*axi_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); > + return err; > + } > + > + err = clk_prepare_enable(*tx_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); > + goto err_disable_axiclk; > + } > + > + err = clk_prepare_enable(*txs_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err); > + goto err_disable_txclk; > + } > + > + err = clk_prepare_enable(*rx_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err); > + goto err_disable_txsclk; > + } > + > + err = clk_prepare_enable(*rxs_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err); > + goto err_disable_rxclk; > + } > + > + return 0; > + > +err_disable_rxclk: > + clk_disable_unprepare(*rx_clk); > +err_disable_txsclk: > + clk_disable_unprepare(*txs_clk); > +err_disable_txclk: > + clk_disable_unprepare(*tx_clk); > +err_disable_axiclk: > + clk_disable_unprepare(*axi_clk); > + > + return err; > +} > + > +static void xdma_disable_allclks(struct xilinx_dma_device *xdev) > +{ > + if (!IS_ERR(xdev->rxs_clk)) The init functions set the optional clocks to NULL if not present. So, these pointers should be valid or NULL, but not an error pointer (I think NULL is not considered an error pointer as there is a IS_ERR_OR_NULL macro). > + clk_disable_unprepare(xdev->rxs_clk); > + if (!IS_ERR(xdev->rx_clk)) > + clk_disable_unprepare(xdev->rx_clk); > + if (!IS_ERR(xdev->txs_clk)) > + clk_disable_unprepare(xdev->txs_clk); > + if (!IS_ERR(xdev->tx_clk)) > + clk_disable_unprepare(xdev->tx_clk); > + clk_disable_unprepare(xdev->axi_clk); > +} > + > /** > * xilinx_dma_chan_probe - Per Channel Probing > * It get channel features from the device tree entry and > @@ -1900,14 +2104,17 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, > > static const struct dma_config axidma_config = { > .dmatype = XDMA_TYPE_AXIDMA, > + .clk_init = axidma_clk_init, > }; > > static const struct dma_config axicdma_config = { > .dmatype = XDMA_TYPE_CDMA, > + .clk_init = axicdma_clk_init, > }; > > static const struct dma_config axivdma_config = { > .dmatype = XDMA_TYPE_VDMA, > + .clk_init = axivdma_clk_init, > }; > > static const struct of_device_id xilinx_dma_of_ids[] = { > @@ -1926,9 +2133,13 @@ MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids); > */ > static int xilinx_dma_probe(struct platform_device *pdev) > { > + int (*clk_init)(struct platform_device *, struct clk **, struct clk **, > + struct clk **, struct clk **, struct clk **) > + = axivdma_clk_init; > struct device_node *node = pdev->dev.of_node; > struct xilinx_dma_device *xdev; > struct device_node *child, *np = pdev->dev.of_node; > + struct clk *axi_clk, *tx_clk, *txs_clk, *rx_clk, *rxs_clk; Are these local vars ever transferred into the struct xilinx_dma_device (I actually think you can directly use the struct instead of these locals). > struct resource *io; > u32 num_frames, addr_width; > int i, err; > @@ -1943,10 +2154,16 @@ static int xilinx_dma_probe(struct platform_device *pdev) > const struct of_device_id *match; > > match = of_match_node(xilinx_dma_of_ids, np); > - if (match && match->data) > + if (match && match->data) { > xdev->dma_config = match->data; > + clk_init = xdev->dma_config->clk_init; > + } > } > > + err = clk_init(pdev, &axi_clk, &tx_clk, &txs_clk, &rx_clk, &rxs_clk); > + if (err) > + return err; > + > /* Request and map I/O memory */ > io = platform_get_resource(pdev, IORESOURCE_MEM, 0); > xdev->regs = devm_ioremap_resource(&pdev->dev, io); > @@ -2019,7 +2236,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) > for_each_child_of_node(node, child) { > err = xilinx_dma_chan_probe(xdev, child); > if (err < 0) > - goto error; > + goto disable_clks; > } > > if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { > @@ -2043,6 +2260,8 @@ static int xilinx_dma_probe(struct platform_device *pdev) > > return 0; > > +disable_clks: > + xdma_disable_allclks(xdev); > error: > for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++) > if (xdev->chan[i]) > @@ -2070,6 +2289,8 @@ static int xilinx_dma_remove(struct platform_device *pdev) > if (xdev->chan[i]) > xilinx_dma_chan_remove(xdev->chan[i]); > > + xdma_disable_allclks(xdev); > + > return 0; > } Sören -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
SGkgU29yZW4sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogU8O2cmVu IEJyaW5rbWFubiBbbWFpbHRvOnNvcmVuLmJyaW5rbWFubkB4aWxpbnguY29tXQ0KPiBTZW50OiBU aHVyc2RheSwgQXByaWwgMjEsIDIwMTYgOTo1MiBQTQ0KPiBUbzogQXBwYW5hIER1cmdhIEtlZGFy ZXN3YXJhIFJhbyA8YXBwYW5hZEB4aWxpbnguY29tPg0KPiBDYzogcm9iaCtkdEBrZXJuZWwub3Jn OyBwYXdlbC5tb2xsQGFybS5jb207IG1hcmsucnV0bGFuZEBhcm0uY29tOw0KPiBpamMrZGV2aWNl dHJlZUBoZWxsaW9uLm9yZy51azsgZ2FsYWtAY29kZWF1cm9yYS5vcmc7IE1pY2hhbCBTaW1law0K PiA8bWljaGFsc0B4aWxpbnguY29tPjsgdmlub2Qua291bEBpbnRlbC5jb207IGRhbi5qLndpbGxp YW1zQGludGVsLmNvbTsNCj4gQXBwYW5hIER1cmdhIEtlZGFyZXN3YXJhIFJhbyA8YXBwYW5hZEB4 aWxpbnguY29tPjsNCj4gbW9yaXR6LmZpc2NoZXJAZXR0dXMuY29tOyBsYXVyZW50LnBpbmNoYXJ0 QGlkZWFzb25ib2FyZC5jb207DQo+IGx1aXNAZGViZXRoZW5jb3VydC5jb207IEFuaXJ1ZGhhIFNh cmFuZ2kgPGFuaXJ1ZGhAeGlsaW54LmNvbT47IFB1bm5haWFoDQo+IENob3VkYXJ5IEthbGx1cmkg PHB1bm5haWFAeGlsaW54LmNvbT47IFNodWJocmFqeW90aSBEYXR0YQ0KPiA8c2h1YmhyYWpAeGls aW54LmNvbT47IGRldmljZXRyZWVAdmdlci5rZXJuZWwub3JnOyBsaW51eC1hcm0tDQo+IGtlcm5l bEBsaXN0cy5pbmZyYWRlYWQub3JnOyBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnOw0KPiBk bWFlbmdpbmVAdmdlci5rZXJuZWwub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjMgMy8zXSBk bWFlbmdpbmU6IHZkbWE6IEFkZCBjbG9jayBzdXBwb3J0DQo+IA0KPiBPbiBUaHUsIDIwMTYtMDQt MjEgYXQgMTY6MDg6MzggKzA1MzAsIEtlZGFyZXN3YXJhIHJhbyBBcHBhbmEgd3JvdGU6DQo+ID4g QWRkZWQgYmFzaWMgY2xvY2sgc3VwcG9ydCBmb3IgYXhpIGRtYSdzLg0KPiA+IFRoZSBjbG9ja3Mg YXJlIHJlcXVlc3RlZCBhdCBwcm9iZSBhbmQgcmVsZWFzZWQgYXQgcmVtb3ZlLg0KPiA+DQo+ID4g UmV2aWV3ZWQtYnk6IFNodWJocmFqeW90aSBEYXR0YSA8c2h1YmhyYWpAeGlsaW54LmNvbT4NCj4g PiBTaWduZWQtb2ZmLWJ5OiBLZWRhcmVzd2FyYSByYW8gQXBwYW5hIDxhcHBhbmFkQHhpbGlueC5j b20+DQo+ID4gLS0tDQo+ID4gQ2hhbmdlcyBmb3IgdjM6DQo+ID4gLS0tPiBBZGRlZCBjbG9jayBz dXBwb3J0IGZvciBhbGwgdGhlIEFYSSBETUEncy4NCj4gPiAtLS0+IEZpeGVkIGNsa191bnByZXBh cmUgbGVhayBkdXJpbmcgcHJvYmUgZmFpbCBhcyBzdWdnZXN0ZWQgYnkgTW9yaXR6Lg0KPiA+IC0t LT4gRml4ZWQgY29tbWVudCBkcml2ZXIgc3BlY2lmaWNhbGx5IGFza3MgZm9yIHRoZSBjbG9ja3Mg aXQgbmVlZHMNCj4gPiAtLS0+IGFuZCByZXR1cm4NCj4gPiBhbiBlcnJvciBpZiBhIG1hbmRhdG9y eSBjbG9jayBpcyBtaXNzaW5nIGFzIHN1Z2dlc3RlZCBieSBzb3Jlbi4NCj4gPiBDaGFuZ2VzIGZv ciB2MjoNCj4gPiAtLS0+IE5vbmUuDQo+ID4NCj4gPiAgZHJpdmVycy9kbWEveGlsaW54L3hpbGlu eF92ZG1hLmMgfCAyMjUNCj4gPiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr Ky0NCj4gPiAgMSBmaWxlIGNoYW5nZWQsIDIyMyBpbnNlcnRpb25zKCspLCAyIGRlbGV0aW9ucygt KQ0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hL3hpbGlueC94aWxpbnhfdmRtYS5j DQo+ID4gYi9kcml2ZXJzL2RtYS94aWxpbngveGlsaW54X3ZkbWEuYw0KPiA+IGluZGV4IDViZmFh MzIuLjQxYmI1YjMgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9kbWEveGlsaW54L3hpbGlueF92 ZG1hLmMNCj4gPiArKysgYi9kcml2ZXJzL2RtYS94aWxpbngveGlsaW54X3ZkbWEuYw0KPiA+IEBA IC00NCw2ICs0NCw3IEBADQo+ID4gICNpbmNsdWRlIDxsaW51eC9vZl9wbGF0Zm9ybS5oPg0KPiA+ ICAjaW5jbHVkZSA8bGludXgvb2ZfaXJxLmg+DQo+ID4gICNpbmNsdWRlIDxsaW51eC9zbGFiLmg+ DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4NCj4gPg0KPiA+ICAjaW5jbHVkZSAiLi4vZG1h ZW5naW5lLmgiDQo+ID4NCj4gPiBAQCAtMzQ0LDYgKzM0NSw5IEBAIHN0cnVjdCB4aWxpbnhfZG1h X2NoYW4gew0KPiA+DQo+ID4gIHN0cnVjdCBkbWFfY29uZmlnIHsNCj4gPiAgCWVudW0geGRtYV9p cF90eXBlIGRtYXR5cGU7DQo+ID4gKwlpbnQgKCpjbGtfaW5pdCkoc3RydWN0IHBsYXRmb3JtX2Rl dmljZSAqcGRldiwgc3RydWN0IGNsayAqKmF4aV9jbGssDQo+ID4gKwkJCXN0cnVjdCBjbGsgKip0 eF9jbGssIHN0cnVjdCBjbGsgKip0eHNfY2xrLA0KPiA+ICsJCQlzdHJ1Y3QgY2xrICoqcnhfY2xr LCBzdHJ1Y3QgY2xrICoqcnhzX2Nsayk7DQo+ID4gIH07DQo+ID4NCj4gPiAgLyoqDQo+ID4gQEAg LTM2NSw3ICszNjksMTMgQEAgc3RydWN0IHhpbGlueF9kbWFfZGV2aWNlIHsNCj4gPiAgCWJvb2wg aGFzX3NnOw0KPiA+ICAJdTMyIGZsdXNoX29uX2ZzeW5jOw0KPiA+ICAJYm9vbCBleHRfYWRkcjsN Cj4gPiArCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgICpwZGV2Ow0KPiA+ICAJY29uc3Qgc3RydWN0 IGRtYV9jb25maWcgKmRtYV9jb25maWc7DQo+ID4gKwlzdHJ1Y3QgY2xrICpheGlfY2xrOw0KPiA+ ICsJc3RydWN0IGNsayAqdHhfY2xrOw0KPiA+ICsJc3RydWN0IGNsayAqdHhzX2NsazsNCj4gPiAr CXN0cnVjdCBjbGsgKnJ4X2NsazsNCj4gPiArCXN0cnVjdCBjbGsgKnJ4c19jbGs7DQo+ID4gIH07 DQo+IA0KPiB0aGUgc3RydWN0IG1lbWJlcnMgY291bGQgYmUgZG9jdW1lbnRlZA0KDQpPayBXaWxs IGRvY3VtZW50IGluIHRoZSBuZXh0IHZlcnNpb24uLi4NCg0KPiANCj4gPg0KPiA+ICAvKiBNYWNy b3MgKi8NCj4gPiBAQCAtMTc1Nyw2ICsxNzY3LDIwMCBAQCBzdGF0aWMgdm9pZCB4aWxpbnhfZG1h X2NoYW5fcmVtb3ZlKHN0cnVjdA0KPiB4aWxpbnhfZG1hX2NoYW4gKmNoYW4pDQo+ID4gIAlsaXN0 X2RlbCgmY2hhbi0+Y29tbW9uLmRldmljZV9ub2RlKTsNCj4gPiAgfQ0KPiA+DQo+ID4gK3N0YXRp YyBpbnQgYXhpZG1hX2Nsa19pbml0KHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYsIHN0cnVj dCBjbGsgKipheGlfY2xrLA0KPiA+ICsJCQkgICAgc3RydWN0IGNsayAqKnR4X2Nsaywgc3RydWN0 IGNsayAqKnJ4X2NsaywNCj4gPiArCQkJICAgIHN0cnVjdCBjbGsgKipzZ19jbGssIHN0cnVjdCBj bGsgKip0bXBfY2xrKSB7DQo+ID4gKwlpbnQgZXJyOw0KPiA+ICsNCj4gPiArCSp0bXBfY2xrID0g TlVMTDsNCj4gPiArDQo+ID4gKwkqYXhpX2NsayA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCAi c19heGlfbGl0ZV9hY2xrIik7DQo+ID4gKwlpZiAoSVNfRVJSKCpheGlfY2xrKSkgew0KPiA+ICsJ CWVyciA9IFBUUl9FUlIoKmF4aV9jbGspOw0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgImZh aWxlZCB0byBnZXQgYXhpX2FjbGsgKCV1KVxuIiwgZXJyKTsNCj4gPiArCQlyZXR1cm4gZXJyOw0K PiA+ICsJfQ0KPiA+ICsNCj4gPiArCSp0eF9jbGsgPSBkZXZtX2Nsa19nZXQoJnBkZXYtPmRldiwg Im1fYXhpX21tMnNfYWNsayIpOw0KPiA+ICsJaWYgKElTX0VSUigqdHhfY2xrKSkNCj4gPiArCQkq dHhfY2xrID0gTlVMTDsNCj4gPiArDQo+ID4gKwkqcnhfY2xrID0gZGV2bV9jbGtfZ2V0KCZwZGV2 LT5kZXYsICJtX2F4aV9zMm1tX2FjbGsiKTsNCj4gPiArCWlmIChJU19FUlIoKnJ4X2NsaykpDQo+ ID4gKwkJKnJ4X2NsayA9IE5VTEw7DQo+ID4gKw0KPiA+ICsJKnNnX2NsayA9IGRldm1fY2xrX2dl dCgmcGRldi0+ZGV2LCAibV9heGlfc2dfYWNsayIpOw0KPiA+ICsJaWYgKElTX0VSUigqc2dfY2xr KSkNCj4gPiArCQkqc2dfY2xrID0gTlVMTDsNCj4gPiArDQo+ID4gKw0KPiA+ICsJZXJyID0gY2xr X3ByZXBhcmVfZW5hYmxlKCpheGlfY2xrKTsNCj4gDQo+IFNob3VsZCB0aGlzIGJlIGNhbGxlZCBp ZiB5b3Uga25vdyB0aGF0IHRoZSBwb2ludGVyIG1pZ2h0IGJlIE5VTEw/DQoNCkl0IGlzIGEgbWFu ZGF0b3J5IGNsb2NrIGFuZCBpZiB0aGlzIGNsayBpcyBub3QgdGhlcmUgaW4gRFQgSSBhbSBhbHJl YWR5IHJldHVybmluZyBlcnJvci4uLg0KSSBkaWRuJ3QgZ2V0IHlvdXIgcXVlc3Rpb24gY291bGQg eW91IHBsZWFzZSBlbGFib3JhdGU/Pz8NCiANCj4gDQo+ID4gKwlpZiAoZXJyKSB7DQo+ID4gKwkJ ZGV2X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSBheGlfY2xrICgldSlcbiIsIGVy cik7DQo+ID4gKwkJcmV0dXJuIGVycjsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwllcnIgPSBjbGtf cHJlcGFyZV9lbmFibGUoKnR4X2Nsayk7DQo+ID4gKwlpZiAoZXJyKSB7DQo+ID4gKwkJZGV2X2Vy cigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSB0eF9jbGsgKCV1KVxuIiwgZXJyKTsNCj4g PiArCQlnb3RvIGVycl9kaXNhYmxlX2F4aWNsazsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwllcnIg PSBjbGtfcHJlcGFyZV9lbmFibGUoKnJ4X2Nsayk7DQo+ID4gKwlpZiAoZXJyKSB7DQo+ID4gKwkJ ZGV2X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSB0eHNfY2xrICgldSlcbiIsIGVy cik7DQo+ID4gKwkJZ290byBlcnJfZGlzYWJsZV90eGNsazsNCj4gPiArCX0NCj4gPiArDQo+ID4g KwllcnIgPSBjbGtfcHJlcGFyZV9lbmFibGUoKnNnX2Nsayk7DQo+ID4gKwlpZiAoZXJyKSB7DQo+ ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSByeHNfY2xrICgldSlc biIsIGVycik7DQo+ID4gKwkJZ290byBlcnJfZGlzYWJsZV9yeGNsazsNCj4gPiArCX0NCj4gPiAr DQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArDQo+ID4gK2Vycl9kaXNhYmxlX3J4Y2xrOg0KPiA+ICsJ Y2xrX2Rpc2FibGVfdW5wcmVwYXJlKCpyeF9jbGspOw0KPiA+ICtlcnJfZGlzYWJsZV90eGNsazoN Cj4gPiArCWNsa19kaXNhYmxlX3VucHJlcGFyZSgqdHhfY2xrKTsNCj4gPiArZXJyX2Rpc2FibGVf YXhpY2xrOg0KPiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKCpheGlfY2xrKTsNCj4gPiArDQo+ ID4gKwlyZXR1cm4gZXJyOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGF4aWNkbWFf Y2xrX2luaXQoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiwgc3RydWN0IGNsayAqKmF4aV9j bGssDQo+ID4gKwkJCSAgICBzdHJ1Y3QgY2xrICoqZGV2X2Nsaywgc3RydWN0IGNsayAqKnRtcF9j bGssDQo+ID4gKwkJCSAgICBzdHJ1Y3QgY2xrICoqdG1wMV9jbGssIHN0cnVjdCBjbGsgKip0bXAy X2Nsaykgew0KPiA+ICsJaW50IGVycjsNCj4gPiArDQo+ID4gKwkqdG1wX2NsayA9IE5VTEw7DQo+ ID4gKwkqdG1wMV9jbGsgPSBOVUxMOw0KPiA+ICsJKnRtcDJfY2xrID0gTlVMTDsNCj4gPiArDQo+ ID4gKwkqYXhpX2NsayA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCAic19heGlfbGl0ZV9hY2xr Iik7DQo+ID4gKwlpZiAoSVNfRVJSKCpheGlfY2xrKSkgew0KPiA+ICsJCWVyciA9IFBUUl9FUlIo KmF4aV9jbGspOw0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgImZhaWxlZCB0byBnZXQgYXhp X2FjbGsgKCV1KVxuIiwgZXJyKTsNCj4gPiArCQlyZXR1cm4gZXJyOw0KPiA+ICsJfQ0KPiA+ICsN Cj4gPiArCSpkZXZfY2xrID0gZGV2bV9jbGtfZ2V0KCZwZGV2LT5kZXYsICJtX2F4aV9hY2xrIik7 DQo+ID4gKwlpZiAoSVNfRVJSKCpkZXZfY2xrKSkNCj4gPiArCQkqZGV2X2NsayA9IE5VTEw7DQo+ IA0KPiBUaGlzIGlzIGEgcmVxdWlyZWQgY2xvY2sgYWNjb3JkaW5nIHRvIGJpbmRpbmcgYnV0IGEg ZmFpbHVyZSBpcyBpZ25vcmVkIGhlcmUuDQoNCkhtbSBuaWNlIGNhdGNoIHdpbGwgZml4IGluIG5l eHQgdmVyc2lvbi4uLg0KDQo+IA0KPiA+ICsNCj4gPiArDQo+ID4gKwllcnIgPSBjbGtfcHJlcGFy ZV9lbmFibGUoKmF4aV9jbGspOw0KPiA+ICsJaWYgKGVycikgew0KPiA+ICsJCWRldl9lcnIoJnBk ZXYtPmRldiwgImZhaWxlZCB0byBlbmFibGUgYXhpX2NsayAoJXUpXG4iLCBlcnIpOw0KPiA+ICsJ CXJldHVybiBlcnI7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZXJyID0gY2xrX3ByZXBhcmVfZW5h YmxlKCpkZXZfY2xrKTsNCj4gPiArCWlmIChlcnIpIHsNCj4gPiArCQlkZXZfZXJyKCZwZGV2LT5k ZXYsICJmYWlsZWQgdG8gZW5hYmxlIHR4X2NsayAoJXUpXG4iLCBlcnIpOw0KPiA+ICsJCWdvdG8g ZXJyX2Rpc2FibGVfYXhpY2xrOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArDQo+ID4gKwlyZXR1cm4g MDsNCj4gPiArDQo+ID4gK2Vycl9kaXNhYmxlX2F4aWNsazoNCj4gPiArCWNsa19kaXNhYmxlX3Vu cHJlcGFyZSgqYXhpX2Nsayk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIGVycjsNCj4gPiArfQ0KPiA+ ICsNCj4gPiArc3RhdGljIGludCBheGl2ZG1hX2Nsa19pbml0KHN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UgKnBkZXYsIHN0cnVjdCBjbGsgKipheGlfY2xrLA0KPiA+ICsJCQkgICAgc3RydWN0IGNsayAq KnR4X2Nsaywgc3RydWN0IGNsayAqKnR4c19jbGssDQo+ID4gKwkJCSAgICBzdHJ1Y3QgY2xrICoq cnhfY2xrLCBzdHJ1Y3QgY2xrICoqcnhzX2Nsaykgew0KPiA+ICsJaW50IGVycjsNCj4gPiArDQo+ ID4gKwkqYXhpX2NsayA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCAic19heGlfbGl0ZV9hY2xr Iik7DQo+ID4gKwlpZiAoSVNfRVJSKCpheGlfY2xrKSkgew0KPiA+ICsJCWVyciA9IFBUUl9FUlIo KmF4aV9jbGspOw0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgImZhaWxlZCB0byBnZXQgYXhp X2FjbGsgKCV1KVxuIiwgZXJyKTsNCj4gPiArCQlyZXR1cm4gZXJyOw0KPiA+ICsJfQ0KPiA+ICsN Cj4gPiArCSp0eF9jbGsgPSBkZXZtX2Nsa19nZXQoJnBkZXYtPmRldiwgIm1fYXhpX21tMnNfYWNs ayIpOw0KPiA+ICsJaWYgKElTX0VSUigqdHhfY2xrKSkNCj4gPiArCQkqdHhfY2xrID0gTlVMTDsN Cj4gPiArDQo+ID4gKwkqdHhzX2NsayA9IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCAibV9heGlz X21tMnNfYWNsayIpOw0KPiA+ICsJaWYgKElTX0VSUigqdHhzX2NsaykpDQo+ID4gKwkJKnR4c19j bGsgPSBOVUxMOw0KPiA+ICsNCj4gPiArCSpyeF9jbGsgPSBkZXZtX2Nsa19nZXQoJnBkZXYtPmRl diwgIm1fYXhpX3MybW1fYWNsayIpOw0KPiA+ICsJaWYgKElTX0VSUigqcnhfY2xrKSkNCj4gPiAr CQkqcnhfY2xrID0gTlVMTDsNCj4gPiArDQo+ID4gKwkqcnhzX2NsayA9IGRldm1fY2xrX2dldCgm cGRldi0+ZGV2LCAic19heGlzX3MybW1fYWNsayIpOw0KPiA+ICsJaWYgKElTX0VSUigqcnhzX2Ns aykpDQo+ID4gKwkJKnJ4c19jbGsgPSBOVUxMOw0KPiA+ICsNCj4gPiArDQo+ID4gKwllcnIgPSBj bGtfcHJlcGFyZV9lbmFibGUoKmF4aV9jbGspOw0KPiA+ICsJaWYgKGVycikgew0KPiA+ICsJCWRl dl9lcnIoJnBkZXYtPmRldiwgImZhaWxlZCB0byBlbmFibGUgYXhpX2NsayAoJXUpXG4iLCBlcnIp Ow0KPiA+ICsJCXJldHVybiBlcnI7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZXJyID0gY2xrX3By ZXBhcmVfZW5hYmxlKCp0eF9jbGspOw0KPiA+ICsJaWYgKGVycikgew0KPiA+ICsJCWRldl9lcnIo JnBkZXYtPmRldiwgImZhaWxlZCB0byBlbmFibGUgdHhfY2xrICgldSlcbiIsIGVycik7DQo+ID4g KwkJZ290byBlcnJfZGlzYWJsZV9heGljbGs7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZXJyID0g Y2xrX3ByZXBhcmVfZW5hYmxlKCp0eHNfY2xrKTsNCj4gPiArCWlmIChlcnIpIHsNCj4gPiArCQlk ZXZfZXJyKCZwZGV2LT5kZXYsICJmYWlsZWQgdG8gZW5hYmxlIHR4c19jbGsgKCV1KVxuIiwgZXJy KTsNCj4gPiArCQlnb3RvIGVycl9kaXNhYmxlX3R4Y2xrOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiAr CWVyciA9IGNsa19wcmVwYXJlX2VuYWJsZSgqcnhfY2xrKTsNCj4gPiArCWlmIChlcnIpIHsNCj4g PiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJmYWlsZWQgdG8gZW5hYmxlIHJ4X2NsayAoJXUpXG4i LCBlcnIpOw0KPiA+ICsJCWdvdG8gZXJyX2Rpc2FibGVfdHhzY2xrOw0KPiA+ICsJfQ0KPiA+ICsN Cj4gPiArCWVyciA9IGNsa19wcmVwYXJlX2VuYWJsZSgqcnhzX2Nsayk7DQo+ID4gKwlpZiAoZXJy KSB7DQo+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSByeHNfY2xr ICgldSlcbiIsIGVycik7DQo+ID4gKwkJZ290byBlcnJfZGlzYWJsZV9yeGNsazsNCj4gPiArCX0N Cj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArDQo+ID4gK2Vycl9kaXNhYmxlX3J4Y2xrOg0K PiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKCpyeF9jbGspOw0KPiA+ICtlcnJfZGlzYWJsZV90 eHNjbGs6DQo+ID4gKwljbGtfZGlzYWJsZV91bnByZXBhcmUoKnR4c19jbGspOw0KPiA+ICtlcnJf ZGlzYWJsZV90eGNsazoNCj4gPiArCWNsa19kaXNhYmxlX3VucHJlcGFyZSgqdHhfY2xrKTsNCj4g PiArZXJyX2Rpc2FibGVfYXhpY2xrOg0KPiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKCpheGlf Y2xrKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gZXJyOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0 aWMgdm9pZCB4ZG1hX2Rpc2FibGVfYWxsY2xrcyhzdHJ1Y3QgeGlsaW54X2RtYV9kZXZpY2UgKnhk ZXYpIHsNCj4gPiArCWlmICghSVNfRVJSKHhkZXYtPnJ4c19jbGspKQ0KPiANCj4gVGhlIGluaXQg ZnVuY3Rpb25zIHNldCB0aGUgb3B0aW9uYWwgY2xvY2tzIHRvIE5VTEwgaWYgbm90IHByZXNlbnQu IFNvLCB0aGVzZQ0KPiBwb2ludGVycyBzaG91bGQgYmUgdmFsaWQgb3IgTlVMTCwgYnV0IG5vdCBh biBlcnJvciBwb2ludGVyIChJIHRoaW5rIE5VTEwgaXMgbm90DQo+IGNvbnNpZGVyZWQgYW4gZXJy b3IgcG9pbnRlciBhcyB0aGVyZSBpcyBhIElTX0VSUl9PUl9OVUxMIG1hY3JvKS4NCg0KT2sgd2ls bCByZW1vdmUgSVNfRVJSIGNoZWNrcy4uLg0KDQo+IA0KPiA+ICsJCWNsa19kaXNhYmxlX3VucHJl cGFyZSh4ZGV2LT5yeHNfY2xrKTsNCj4gPiArCWlmICghSVNfRVJSKHhkZXYtPnJ4X2NsaykpDQo+ ID4gKwkJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKHhkZXYtPnJ4X2Nsayk7DQo+ID4gKwlpZiAoIUlT X0VSUih4ZGV2LT50eHNfY2xrKSkNCj4gPiArCQljbGtfZGlzYWJsZV91bnByZXBhcmUoeGRldi0+ dHhzX2Nsayk7DQo+ID4gKwlpZiAoIUlTX0VSUih4ZGV2LT50eF9jbGspKQ0KPiA+ICsJCWNsa19k aXNhYmxlX3VucHJlcGFyZSh4ZGV2LT50eF9jbGspOw0KPiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVw YXJlKHhkZXYtPmF4aV9jbGspOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICAvKioNCj4gPiAgICogeGls aW54X2RtYV9jaGFuX3Byb2JlIC0gUGVyIENoYW5uZWwgUHJvYmluZw0KPiA+ICAgKiBJdCBnZXQg Y2hhbm5lbCBmZWF0dXJlcyBmcm9tIHRoZSBkZXZpY2UgdHJlZSBlbnRyeSBhbmQgQEAgLTE5MDAs MTQNCj4gPiArMjEwNCwxNyBAQCBzdGF0aWMgc3RydWN0IGRtYV9jaGFuICpvZl9kbWFfeGlsaW54 X3hsYXRlKHN0cnVjdA0KPiA+IG9mX3BoYW5kbGVfYXJncyAqZG1hX3NwZWMsDQo+ID4NCj4gPiAg c3RhdGljIGNvbnN0IHN0cnVjdCBkbWFfY29uZmlnIGF4aWRtYV9jb25maWcgPSB7DQo+ID4gIAku ZG1hdHlwZSA9IFhETUFfVFlQRV9BWElETUEsDQo+ID4gKwkuY2xrX2luaXQgPSBheGlkbWFfY2xr X2luaXQsDQo+ID4gIH07DQo+ID4NCj4gPiAgc3RhdGljIGNvbnN0IHN0cnVjdCBkbWFfY29uZmln IGF4aWNkbWFfY29uZmlnID0gew0KPiA+ICAJLmRtYXR5cGUgPSBYRE1BX1RZUEVfQ0RNQSwNCj4g PiArCS5jbGtfaW5pdCA9IGF4aWNkbWFfY2xrX2luaXQsDQo+ID4gIH07DQo+ID4NCj4gPiAgc3Rh dGljIGNvbnN0IHN0cnVjdCBkbWFfY29uZmlnIGF4aXZkbWFfY29uZmlnID0gew0KPiA+ICAJLmRt YXR5cGUgPSBYRE1BX1RZUEVfVkRNQSwNCj4gPiArCS5jbGtfaW5pdCA9IGF4aXZkbWFfY2xrX2lu aXQsDQo+ID4gIH07DQo+ID4NCj4gPiAgc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQg eGlsaW54X2RtYV9vZl9pZHNbXSA9IHsgQEAgLTE5MjYsOQ0KPiA+ICsyMTMzLDEzIEBAIE1PRFVM RV9ERVZJQ0VfVEFCTEUob2YsIHhpbGlueF9kbWFfb2ZfaWRzKTsNCj4gPiAgICovDQo+ID4gIHN0 YXRpYyBpbnQgeGlsaW54X2RtYV9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KSAg ew0KPiA+ICsJaW50ICgqY2xrX2luaXQpKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKiwgc3RydWN0 IGNsayAqKiwgc3RydWN0IGNsayAqKiwNCj4gPiArCQkJc3RydWN0IGNsayAqKiwgc3RydWN0IGNs ayAqKiwgc3RydWN0IGNsayAqKikNCj4gPiArCQkJCQk9IGF4aXZkbWFfY2xrX2luaXQ7DQo+ID4g IAlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5vZGUgPSBwZGV2LT5kZXYub2Zfbm9kZTsNCj4gPiAgCXN0 cnVjdCB4aWxpbnhfZG1hX2RldmljZSAqeGRldjsNCj4gPiAgCXN0cnVjdCBkZXZpY2Vfbm9kZSAq Y2hpbGQsICpucCA9IHBkZXYtPmRldi5vZl9ub2RlOw0KPiA+ICsJc3RydWN0IGNsayAqYXhpX2Ns aywgKnR4X2NsaywgKnR4c19jbGssICpyeF9jbGssICpyeHNfY2xrOw0KPiANCj4gQXJlIHRoZXNl IGxvY2FsIHZhcnMgZXZlciB0cmFuc2ZlcnJlZCBpbnRvIHRoZSBzdHJ1Y3QgeGlsaW54X2RtYV9k ZXZpY2UgKEkgYWN0dWFsbHkNCj4gdGhpbmsgeW91IGNhbiBkaXJlY3RseSB1c2UgdGhlIHN0cnVj dCBpbnN0ZWFkIG9mIHRoZXNlIGxvY2FscykuDQoNCk9rIHdpbGwgZml4IGluIHRoZSBuZXh0IHZl cnNpb24uLi4NCg0KUmVnYXJkcywNCktlZGFyLg0KDQo+IA0KPiA+ICAJc3RydWN0IHJlc291cmNl ICppbzsNCj4gPiAgCXUzMiBudW1fZnJhbWVzLCBhZGRyX3dpZHRoOw0KPiA+ICAJaW50IGksIGVy cjsNCj4gPiBAQCAtMTk0MywxMCArMjE1NCwxNiBAQCBzdGF0aWMgaW50IHhpbGlueF9kbWFfcHJv YmUoc3RydWN0DQo+IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gPiAgCQljb25zdCBzdHJ1Y3Qg b2ZfZGV2aWNlX2lkICptYXRjaDsNCj4gPg0KPiA+ICAJCW1hdGNoID0gb2ZfbWF0Y2hfbm9kZSh4 aWxpbnhfZG1hX29mX2lkcywgbnApOw0KPiA+IC0JCWlmIChtYXRjaCAmJiBtYXRjaC0+ZGF0YSkN Cj4gPiArCQlpZiAobWF0Y2ggJiYgbWF0Y2gtPmRhdGEpIHsNCj4gPiAgCQkJeGRldi0+ZG1hX2Nv bmZpZyA9IG1hdGNoLT5kYXRhOw0KPiA+ICsJCQljbGtfaW5pdCA9IHhkZXYtPmRtYV9jb25maWct PmNsa19pbml0Ow0KPiA+ICsJCX0NCj4gPiAgCX0NCj4gPg0KPiA+ICsJZXJyID0gY2xrX2luaXQo cGRldiwgJmF4aV9jbGssICZ0eF9jbGssICZ0eHNfY2xrLCAmcnhfY2xrLCAmcnhzX2Nsayk7DQo+ ID4gKwlpZiAoZXJyKQ0KPiA+ICsJCXJldHVybiBlcnI7DQo+ID4gKw0KPiA+ICAJLyogUmVxdWVz dCBhbmQgbWFwIEkvTyBtZW1vcnkgKi8NCj4gPiAgCWlvID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNl KHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAwKTsNCj4gPiAgCXhkZXYtPnJlZ3MgPSBkZXZtX2lvcmVt YXBfcmVzb3VyY2UoJnBkZXYtPmRldiwgaW8pOyBAQCAtMjAxOSw3DQo+ID4gKzIyMzYsNyBAQCBz dGF0aWMgaW50IHhpbGlueF9kbWFfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikN Cj4gPiAgCWZvcl9lYWNoX2NoaWxkX29mX25vZGUobm9kZSwgY2hpbGQpIHsNCj4gPiAgCQllcnIg PSB4aWxpbnhfZG1hX2NoYW5fcHJvYmUoeGRldiwgY2hpbGQpOw0KPiA+ICAJCWlmIChlcnIgPCAw KQ0KPiA+IC0JCQlnb3RvIGVycm9yOw0KPiA+ICsJCQlnb3RvIGRpc2FibGVfY2xrczsNCj4gPiAg CX0NCj4gPg0KPiA+ICAJaWYgKHhkZXYtPmRtYV9jb25maWctPmRtYXR5cGUgPT0gWERNQV9UWVBF X1ZETUEpIHsgQEAgLTIwNDMsNg0KPiA+ICsyMjYwLDggQEAgc3RhdGljIGludCB4aWxpbnhfZG1h X3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4NCj4gPiAgCXJldHVybiAw Ow0KPiA+DQo+ID4gK2Rpc2FibGVfY2xrczoNCj4gPiArCXhkbWFfZGlzYWJsZV9hbGxjbGtzKHhk ZXYpOw0KPiA+ICBlcnJvcjoNCj4gPiAgCWZvciAoaSA9IDA7IGkgPCBYSUxJTlhfRE1BX01BWF9D SEFOU19QRVJfREVWSUNFOyBpKyspDQo+ID4gIAkJaWYgKHhkZXYtPmNoYW5baV0pDQo+ID4gQEAg LTIwNzAsNiArMjI4OSw4IEBAIHN0YXRpYyBpbnQgeGlsaW54X2RtYV9yZW1vdmUoc3RydWN0DQo+ IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gPiAgCQlpZiAoeGRldi0+Y2hhbltpXSkNCj4gPiAg CQkJeGlsaW54X2RtYV9jaGFuX3JlbW92ZSh4ZGV2LT5jaGFuW2ldKTsNCj4gPg0KPiA+ICsJeGRt YV9kaXNhYmxlX2FsbGNsa3MoeGRldik7DQo+ID4gKw0KPiA+ICAJcmV0dXJuIDA7DQo+ID4gIH0N Cj4gDQo+IFPDtnJlbg0K -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, 2016-04-21 at 09:32:44 -0700, Appana Durga Kedareswara Rao wrote: > Hi Soren, > > > -----Original Message----- > > From: Sören Brinkmann [mailto:soren.brinkmann@xilinx.com] > > Sent: Thursday, April 21, 2016 9:52 PM > > To: Appana Durga Kedareswara Rao <appanad@xilinx.com> > > Cc: robh+dt@kernel.org; pawel.moll@arm.com; mark.rutland@arm.com; > > ijc+devicetree@hellion.org.uk; galak@codeaurora.org; Michal Simek > > <michals@xilinx.com>; vinod.koul@intel.com; dan.j.williams@intel.com; > > Appana Durga Kedareswara Rao <appanad@xilinx.com>; > > moritz.fischer@ettus.com; laurent.pinchart@ideasonboard.com; > > luis@debethencourt.com; Anirudha Sarangi <anirudh@xilinx.com>; Punnaiah > > Choudary Kalluri <punnaia@xilinx.com>; Shubhrajyoti Datta > > <shubhraj@xilinx.com>; devicetree@vger.kernel.org; linux-arm- > > kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > > dmaengine@vger.kernel.org > > Subject: Re: [PATCH v3 3/3] dmaengine: vdma: Add clock support > > > > On Thu, 2016-04-21 at 16:08:38 +0530, Kedareswara rao Appana wrote: [...] > > > @@ -1757,6 +1767,200 @@ static void xilinx_dma_chan_remove(struct > > xilinx_dma_chan *chan) > > > list_del(&chan->common.device_node); > > > } > > > > > > +static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk, > > > + struct clk **tx_clk, struct clk **rx_clk, > > > + struct clk **sg_clk, struct clk **tmp_clk) { > > > + int err; > > > + > > > + *tmp_clk = NULL; > > > + > > > + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); > > > + if (IS_ERR(*axi_clk)) { > > > + err = PTR_ERR(*axi_clk); > > > + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); > > > + return err; > > > + } > > > + > > > + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); > > > + if (IS_ERR(*tx_clk)) > > > + *tx_clk = NULL; > > > + > > > + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); > > > + if (IS_ERR(*rx_clk)) > > > + *rx_clk = NULL; > > > + > > > + *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk"); > > > + if (IS_ERR(*sg_clk)) > > > + *sg_clk = NULL; > > > + > > > + > > > + err = clk_prepare_enable(*axi_clk); > > > > Should this be called if you know that the pointer might be NULL? > > It is a mandatory clock and if this clk is not there in DT I am already returning error... > I didn't get your question could you please elaborate??? But for all the optional clocks. They could all be NULL and you're calling clk_prepare_enable with a NULL pointer. That function is nice enough to do a NULL check for you, but I wonder whether these calls should happen at all when you already know that the pointer is not a valid clock. Sören -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Soren, > -----Original Message----- > From: Sören Brinkmann [mailto:soren.brinkmann@xilinx.com] > Sent: Thursday, April 21, 2016 10:32 PM > To: Appana Durga Kedareswara Rao <appanad@xilinx.com> > Cc: Soren Brinkmann <sorenb@xilinx.com>; robh+dt@kernel.org; > pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk; > galak@codeaurora.org; Michal Simek <michals@xilinx.com>; > vinod.koul@intel.com; dan.j.williams@intel.com; moritz.fischer@ettus.com; > laurent.pinchart@ideasonboard.com; luis@debethencourt.com; Anirudha > Sarangi <anirudh@xilinx.com>; Punnaiah Choudary Kalluri > <punnaia@xilinx.com>; Shubhrajyoti Datta <shubhraj@xilinx.com>; > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux- > kernel@vger.kernel.org; dmaengine@vger.kernel.org > Subject: Re: [PATCH v3 3/3] dmaengine: vdma: Add clock support > > On Thu, 2016-04-21 at 09:32:44 -0700, Appana Durga Kedareswara Rao wrote: > > Hi Soren, > > > > > -----Original Message----- > > > From: Sören Brinkmann [mailto:soren.brinkmann@xilinx.com] > > > Sent: Thursday, April 21, 2016 9:52 PM > > > To: Appana Durga Kedareswara Rao <appanad@xilinx.com> > > > Cc: robh+dt@kernel.org; pawel.moll@arm.com; mark.rutland@arm.com; > > > ijc+devicetree@hellion.org.uk; galak@codeaurora.org; Michal Simek > > > <michals@xilinx.com>; vinod.koul@intel.com; dan.j.williams@intel.com; > > > Appana Durga Kedareswara Rao <appanad@xilinx.com>; > > > moritz.fischer@ettus.com; laurent.pinchart@ideasonboard.com; > > > luis@debethencourt.com; Anirudha Sarangi <anirudh@xilinx.com>; Punnaiah > > > Choudary Kalluri <punnaia@xilinx.com>; Shubhrajyoti Datta > > > <shubhraj@xilinx.com>; devicetree@vger.kernel.org; linux-arm- > > > kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > > > dmaengine@vger.kernel.org > > > Subject: Re: [PATCH v3 3/3] dmaengine: vdma: Add clock support > > > > > > On Thu, 2016-04-21 at 16:08:38 +0530, Kedareswara rao Appana wrote: > [...] > > > > @@ -1757,6 +1767,200 @@ static void xilinx_dma_chan_remove(struct > > > xilinx_dma_chan *chan) > > > > list_del(&chan->common.device_node); > > > > } > > > > > > > > +static int axidma_clk_init(struct platform_device *pdev, struct clk > **axi_clk, > > > > + struct clk **tx_clk, struct clk **rx_clk, > > > > + struct clk **sg_clk, struct clk **tmp_clk) { > > > > + int err; > > > > + > > > > + *tmp_clk = NULL; > > > > + > > > > + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); > > > > + if (IS_ERR(*axi_clk)) { > > > > + err = PTR_ERR(*axi_clk); > > > > + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); > > > > + return err; > > > > + } > > > > + > > > > + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); > > > > + if (IS_ERR(*tx_clk)) > > > > + *tx_clk = NULL; > > > > + > > > > + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); > > > > + if (IS_ERR(*rx_clk)) > > > > + *rx_clk = NULL; > > > > + > > > > + *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk"); > > > > + if (IS_ERR(*sg_clk)) > > > > + *sg_clk = NULL; > > > > + > > > > + > > > > + err = clk_prepare_enable(*axi_clk); > > > > > > Should this be called if you know that the pointer might be NULL? > > > > It is a mandatory clock and if this clk is not there in DT I am already returning > error... > > I didn't get your question could you please elaborate??? > > But for all the optional clocks. They could all be NULL and you're calling > clk_prepare_enable with a NULL pointer. That function is nice enough to > do a NULL check for you, but I wonder whether these calls should happen at > all when you already know that the pointer is not a valid clock. I referred macb driver http://lxr.free-electrons.com/source/drivers/net/ethernet/cadence/macb.c There tx_clk is optional and in this driver they are calling clk_prepare_enable for the optional clocks. Please let me know if you are ok to call the clk_prepare_enable() for optional clocks with a NULL pointer. Will fix rest of the comments and will send next version of the patch... Regards, Kedar. > > Sören
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c index 5bfaa32..41bb5b3 100644 --- a/drivers/dma/xilinx/xilinx_vdma.c +++ b/drivers/dma/xilinx/xilinx_vdma.c @@ -44,6 +44,7 @@ #include <linux/of_platform.h> #include <linux/of_irq.h> #include <linux/slab.h> +#include <linux/clk.h> #include "../dmaengine.h" @@ -344,6 +345,9 @@ struct xilinx_dma_chan { struct dma_config { enum xdma_ip_type dmatype; + 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); }; /** @@ -365,7 +369,13 @@ struct xilinx_dma_device { bool has_sg; u32 flush_on_fsync; bool ext_addr; + struct platform_device *pdev; const struct dma_config *dma_config; + struct clk *axi_clk; + struct clk *tx_clk; + struct clk *txs_clk; + struct clk *rx_clk; + struct clk *rxs_clk; }; /* Macros */ @@ -1757,6 +1767,200 @@ static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan) list_del(&chan->common.device_node); } +static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk, + struct clk **tx_clk, struct clk **rx_clk, + struct clk **sg_clk, struct clk **tmp_clk) +{ + int err; + + *tmp_clk = NULL; + + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); + if (IS_ERR(*axi_clk)) { + err = PTR_ERR(*axi_clk); + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); + return err; + } + + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); + if (IS_ERR(*tx_clk)) + *tx_clk = NULL; + + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); + if (IS_ERR(*rx_clk)) + *rx_clk = NULL; + + *sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk"); + if (IS_ERR(*sg_clk)) + *sg_clk = NULL; + + + err = clk_prepare_enable(*axi_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); + return err; + } + + err = clk_prepare_enable(*tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); + goto err_disable_axiclk; + } + + err = clk_prepare_enable(*rx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err); + goto err_disable_txclk; + } + + err = clk_prepare_enable(*sg_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err); + goto err_disable_rxclk; + } + + return 0; + +err_disable_rxclk: + clk_disable_unprepare(*rx_clk); +err_disable_txclk: + clk_disable_unprepare(*tx_clk); +err_disable_axiclk: + clk_disable_unprepare(*axi_clk); + + return err; +} + +static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk, + struct clk **dev_clk, struct clk **tmp_clk, + struct clk **tmp1_clk, struct clk **tmp2_clk) +{ + int err; + + *tmp_clk = NULL; + *tmp1_clk = NULL; + *tmp2_clk = NULL; + + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); + if (IS_ERR(*axi_clk)) { + err = PTR_ERR(*axi_clk); + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); + return err; + } + + *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk"); + if (IS_ERR(*dev_clk)) + *dev_clk = NULL; + + + err = clk_prepare_enable(*axi_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); + return err; + } + + err = clk_prepare_enable(*dev_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); + goto err_disable_axiclk; + } + + + return 0; + +err_disable_axiclk: + clk_disable_unprepare(*axi_clk); + + return err; +} + +static int axivdma_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) +{ + int err; + + *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); + if (IS_ERR(*axi_clk)) { + err = PTR_ERR(*axi_clk); + dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err); + return err; + } + + *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); + if (IS_ERR(*tx_clk)) + *tx_clk = NULL; + + *txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk"); + if (IS_ERR(*txs_clk)) + *txs_clk = NULL; + + *rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk"); + if (IS_ERR(*rx_clk)) + *rx_clk = NULL; + + *rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk"); + if (IS_ERR(*rxs_clk)) + *rxs_clk = NULL; + + + err = clk_prepare_enable(*axi_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err); + return err; + } + + err = clk_prepare_enable(*tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); + goto err_disable_axiclk; + } + + err = clk_prepare_enable(*txs_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err); + goto err_disable_txclk; + } + + err = clk_prepare_enable(*rx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err); + goto err_disable_txsclk; + } + + err = clk_prepare_enable(*rxs_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err); + goto err_disable_rxclk; + } + + return 0; + +err_disable_rxclk: + clk_disable_unprepare(*rx_clk); +err_disable_txsclk: + clk_disable_unprepare(*txs_clk); +err_disable_txclk: + clk_disable_unprepare(*tx_clk); +err_disable_axiclk: + clk_disable_unprepare(*axi_clk); + + return err; +} + +static void xdma_disable_allclks(struct xilinx_dma_device *xdev) +{ + if (!IS_ERR(xdev->rxs_clk)) + clk_disable_unprepare(xdev->rxs_clk); + if (!IS_ERR(xdev->rx_clk)) + clk_disable_unprepare(xdev->rx_clk); + if (!IS_ERR(xdev->txs_clk)) + clk_disable_unprepare(xdev->txs_clk); + if (!IS_ERR(xdev->tx_clk)) + clk_disable_unprepare(xdev->tx_clk); + clk_disable_unprepare(xdev->axi_clk); +} + /** * xilinx_dma_chan_probe - Per Channel Probing * It get channel features from the device tree entry and @@ -1900,14 +2104,17 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, static const struct dma_config axidma_config = { .dmatype = XDMA_TYPE_AXIDMA, + .clk_init = axidma_clk_init, }; static const struct dma_config axicdma_config = { .dmatype = XDMA_TYPE_CDMA, + .clk_init = axicdma_clk_init, }; static const struct dma_config axivdma_config = { .dmatype = XDMA_TYPE_VDMA, + .clk_init = axivdma_clk_init, }; static const struct of_device_id xilinx_dma_of_ids[] = { @@ -1926,9 +2133,13 @@ MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids); */ static int xilinx_dma_probe(struct platform_device *pdev) { + int (*clk_init)(struct platform_device *, struct clk **, struct clk **, + struct clk **, struct clk **, struct clk **) + = axivdma_clk_init; struct device_node *node = pdev->dev.of_node; struct xilinx_dma_device *xdev; struct device_node *child, *np = pdev->dev.of_node; + struct clk *axi_clk, *tx_clk, *txs_clk, *rx_clk, *rxs_clk; struct resource *io; u32 num_frames, addr_width; int i, err; @@ -1943,10 +2154,16 @@ static int xilinx_dma_probe(struct platform_device *pdev) const struct of_device_id *match; match = of_match_node(xilinx_dma_of_ids, np); - if (match && match->data) + if (match && match->data) { xdev->dma_config = match->data; + clk_init = xdev->dma_config->clk_init; + } } + err = clk_init(pdev, &axi_clk, &tx_clk, &txs_clk, &rx_clk, &rxs_clk); + if (err) + return err; + /* Request and map I/O memory */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); xdev->regs = devm_ioremap_resource(&pdev->dev, io); @@ -2019,7 +2236,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) for_each_child_of_node(node, child) { err = xilinx_dma_chan_probe(xdev, child); if (err < 0) - goto error; + goto disable_clks; } if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { @@ -2043,6 +2260,8 @@ static int xilinx_dma_probe(struct platform_device *pdev) return 0; +disable_clks: + xdma_disable_allclks(xdev); error: for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++) if (xdev->chan[i]) @@ -2070,6 +2289,8 @@ static int xilinx_dma_remove(struct platform_device *pdev) if (xdev->chan[i]) xilinx_dma_chan_remove(xdev->chan[i]); + xdma_disable_allclks(xdev); + return 0; }