On Fri 05 Apr 10:54 +07 2019, Georgi Djakov wrote:
[..]
> diff --git a/drivers/interconnect/qcom/qcs404.c 
> b/drivers/interconnect/qcom/qcs404.c
> new file mode 100644
> index 000000000000..42d36db13ec0
> --- /dev/null
> +++ b/drivers/interconnect/qcom/qcs404.c
> @@ -0,0 +1,488 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Linaro Ltd
> + */
> +
> +#include <dt-bindings/interconnect/qcom,qcs404.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/interconnect-provider.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/soc/qcom/smd-rpm.h>
> +
> +#include "qcs404_ids.h"
> +
> +#define RPM_BUS_MASTER_REQ   0x73616d62
> +#define RPM_BUS_SLAVE_REQ    0x766c7362
> +#define RPM_KEY_BW           0x00007762
> +
> +#define to_qcom_provider(_provider) \
> +     container_of(_provider, struct qcom_icc_provider, provider)
> +
> +struct qcom_smd_rpm *qcs404_rpm;

static

> +
[..]
> +#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id,        
> \
> +                  _numlinks, ...)                                    \
> +             static struct qcom_icc_node _name = {                   \
> +             .name = #_name,                                         \
> +             .id = _id,                                              \
> +             .buswidth = _buswidth,                                  \
> +             .mas_rpm_id = _mas_rpm_id,                              \
> +             .slv_rpm_id = _slv_rpm_id,                              \
> +             .num_links = _numlinks,                                 \

If you write this as ARRAY_SIZE(((int[]){ __VA_ARGS__ })), you don't
need the manually entered _numlinks number.

> +             .links = { __VA_ARGS__ },                               \
> +     }
> +
[..]
> +static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
> +{
> +     struct qcom_icc_provider *qp;
> +     struct qcom_icc_node *qn;
> +     struct icc_provider *provider;
> +     struct icc_node *n;
> +     u64 sum_bw;
> +     u64 max_peak_bw;
> +     u64 rate;
> +     u32 agg_avg = 0;
> +     u32 agg_peak = 0;
> +     int ret = 0;
> +
> +     qn = src->data;
> +     provider = src->provider;
> +     qp = to_qcom_provider(provider);
> +
> +     list_for_each_entry(n, &provider->nodes, node_list)
> +             qcom_icc_aggregate(n, n->avg_bw, n->peak_bw,
> +                                &agg_avg, &agg_peak);
> +
> +     sum_bw = icc_units_to_bps(agg_avg);
> +     max_peak_bw = icc_units_to_bps(agg_peak);
> +
> +     /* send message to the RPM processor */
> +     if (qn->mas_rpm_id != -1) {
> +             ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
> +                                         RPM_BUS_MASTER_REQ,
> +                                         qn->mas_rpm_id,
> +                                         sum_bw);
> +             if (ret) {
> +                     pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
> +                            qn->mas_rpm_id, ret);
> +                     return ret;
> +             }
> +     }
> +
> +     if (qn->slv_rpm_id != -1) {
> +             ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
> +                                         RPM_BUS_SLAVE_REQ,
> +                                         qn->slv_rpm_id,
> +                                         sum_bw);
> +             if (ret) {
> +                     pr_err("qcom_icc_rpm_smd_send slv error %d\n",
> +                            ret);
> +                     return ret;
> +             }
> +     }
> +
> +     rate = max(sum_bw, max_peak_bw);
> +
> +     do_div(rate, qn->buswidth);
> +
> +     if (qn->rate != rate) {
> +             ret = clk_set_rate(qp->bus_clk, rate);
> +             if (ret) {
> +                     pr_err("set clk rate %lld error %d\n", rate, ret);
> +                     return ret;
> +             }
> +
> +             ret = clk_set_rate(qp->bus_a_clk, rate);
> +             if (ret) {
> +                     pr_err("set clk rate %lld error %d\n", rate, ret);
> +                     return ret;
> +             }
> +
> +             qn->rate = rate;
> +     }
> +
> +     return ret;

ret is 0, return 0; and you can skip setting ret = 0 above.

> +}
> +
> +static int qnoc_probe(struct platform_device *pdev)
> +{
> +     const struct qcom_icc_desc *desc;
> +     struct icc_onecell_data *data;
> +     struct icc_provider *provider;
> +     struct qcom_icc_node **qnodes;
> +     struct qcom_icc_provider *qp;
> +     struct icc_node *node;
> +     size_t num_nodes, i;
> +     int ret;
> +
> +     /* wait for RPM */

This isn't waiting, it's getting the reference. That said if you make
these sit on mmio bus you would need to EPROBE_DEFER on the rpm-child
not being probed yet (and by that it would be a wait).

> +     qcs404_rpm = dev_get_drvdata(pdev->dev.parent);
> +     if (!qcs404_rpm) {
> +             dev_err(&pdev->dev, "unable to retrieve handle to RPM\n");
> +             return -ENODEV;
> +     }
> +
> +     desc = of_device_get_match_data(&pdev->dev);
> +     if (!desc)
> +             return -EINVAL;
> +
> +     qnodes = desc->nodes;
> +     num_nodes = desc->num_nodes;
> +
> +     qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
> +     if (!qp)
> +             return -ENOMEM;
> +
> +     data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
> +     if (!data)
> +             return -ENOMEM;
> +
> +     qp->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");

Please use the clk_bulk interface instead.

> +     if (IS_ERR(qp->bus_clk))
> +             return PTR_ERR(qp->bus_clk);
> +
> +     ret = clk_prepare_enable(qp->bus_clk);
> +     if (ret) {
> +             dev_err(&pdev->dev, "error enabling bus_clk: %d\n", ret);

clk_prepare_enable() will complain if it fails to enable the clock, so
no need to add another print.

> +             return ret;
> +     }
> +
> +     qp->bus_a_clk = devm_clk_get(&pdev->dev, "bus_a_clk");
> +     if (IS_ERR(qp->bus_a_clk))
> +             return PTR_ERR(qp->bus_a_clk);
> +
> +     ret = clk_prepare_enable(qp->bus_a_clk);
> +     if (ret) {
> +             dev_err(&pdev->dev, "error enabling bus_a_clk: %d\n", ret);
> +             clk_disable_unprepare(qp->bus_clk);
> +             return ret;
> +     }
> +
> +     provider = &qp->provider;
> +     INIT_LIST_HEAD(&provider->nodes);
> +     provider->dev = &pdev->dev;
> +     provider->set = qcom_icc_set;
> +     provider->aggregate = qcom_icc_aggregate;
> +     provider->xlate = of_icc_xlate_onecell;
> +     provider->data = data;
> +
> +     ret = icc_provider_add(provider);
> +     if (ret) {
> +             dev_err(&pdev->dev, "error adding interconnect provider\n");
> +             clk_disable_unprepare(qp->bus_clk);
> +             clk_disable_unprepare(qp->bus_a_clk);
> +             return ret;
> +     }
> +
> +     for (i = 0; i < num_nodes; i++) {
> +             size_t j;
> +
> +             node = icc_node_create(qnodes[i]->id);
> +             if (IS_ERR(node)) {
> +                     ret = PTR_ERR(node);
> +                     goto err;
> +             }
> +
> +             node->name = qnodes[i]->name;
> +             node->data = qnodes[i];
> +             icc_node_add(node, provider);
> +
> +             dev_dbg(&pdev->dev, "registered node %s\n", node->name);
> +
> +             /* populate links */
> +             for (j = 0; j < qnodes[i]->num_links; j++)
> +                     icc_link_create(node, qnodes[i]->links[j]);
> +
> +             data->nodes[i] = node;
> +     }
> +     data->num_nodes = num_nodes;
> +
> +     platform_set_drvdata(pdev, qp);
> +
> +     return ret;

ret is 0 here, so just return 0;

> +err:
> +     list_for_each_entry(node, &provider->nodes, node_list) {
> +             icc_node_del(node);
> +             icc_node_destroy(node->id);
> +     }
> +     clk_disable_unprepare(qp->bus_clk);
> +     clk_disable_unprepare(qp->bus_a_clk);
> +     icc_provider_del(provider);
> +
> +     return ret;
> +}
[..]
> diff --git a/drivers/interconnect/qcom/qcs404_ids.h 
> b/drivers/interconnect/qcom/qcs404_ids.h

You use these defines in the driver, so I think this file should be the
one in include/dt-bindings...

[..]
> diff --git a/include/dt-bindings/interconnect/qcom,qcs404.h 
> b/include/dt-bindings/interconnect/qcom,qcs404.h

...and that this is an accidental include(?)

Regards,
Bjorn

Reply via email to