devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Damien Le Moal <damien.lemoal@opensource.wdc.com>
To: Serge Semin <Sergey.Semin@baikalelectronics.ru>,
	Hans de Goede <hdegoede@redhat.com>, Jens Axboe <axboe@kernel.dk>
Cc: Serge Semin <fancer.lancer@gmail.com>,
	Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>,
	Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>,
	Rob Herring <robh+dt@kernel.org>,
	linux-ide@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org
Subject: Re: [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API
Date: Thu, 24 Mar 2022 10:29:01 +0900	[thread overview]
Message-ID: <603eb020-3f43-c193-b3f6-8ff697f845c8@opensource.wdc.com> (raw)
In-Reply-To: <20220324001628.13028-6-Sergey.Semin@baikalelectronics.ru>

On 3/24/22 09:16, Serge Semin wrote:
> In order to simplify the clock-related code there is a way to convert the
> current fixed clocks array into using the common bulk clocks kernel API
> with dynamic set of the clock handlers and device-managed clock-resource
> tracking. It's a bit tricky due to the complication coming from the
> requirement to support the platforms (da850, spear13xx) with the
> non-OF-based clock source, but still doable.
> 
> Before this modification there are two methods have been used to get the
> clocks connected to an AHCI device: clk_get() - to get the very first
> clock in the list and of_clk_get() - to get the rest of them. Basically
> the platforms with non-OF-based clocks definition could specify only a
> single reference clock source. The platforms with OF-hw clocks have been
> luckier and could setup up to AHCI_MAX_CLKS clocks. Such semantic can be
> retained with using devm_clk_bulk_get_all() to retrieve the clocks defined
> via the DT firmware and devm_clk_get_optional() otherwise. In both cases
> using the device-managed version of the methods will cause the automatic
> resources deallocation on the AHCI device removal event. The only
> complicated part in the suggested approach is the explicit allocation and
> initialization of the clk_bulk_data structure instance for the non-OF
> reference clocks. It's required in order to use the Bulk Clocks API for
> the both denoted cases of the clocks definition.
> 
> Note aside with the clock-related code reduction and natural
> simplification, there are several bonuses the suggested modification
> provides. First of all the limitation of having no greater than
> AHCI_MAX_CLKS clocks is now removed, since the devm_clk_bulk_get_all()
> method will allocate as many reference clocks data descriptors as there
> are clocks specified for the device. Secondly the clock names are
> auto-detected. So the glue drivers can make sure that the required clocks
> are specified just by checking the clock IDs in the clk_bulk_data array.
> Thirdly using the handy Bulk Clocks kernel API improves the
> clocks-handling code readability. And the last but not least this
> modification implements a true optional clocks support to the
> ahci_platform_get_resources() method. Indeed the previous clocks getting
> procedure just stopped getting the clocks on any errors (aside from
> non-critical -EPROBE_DEFER) in a way so the callee wasn't even informed
> about abnormal loop termination. The new implementation lacks of such
> problem. The ahci_platform_get_resources() will return an error code if
> the corresponding clocks getting method ends execution abnormally.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/ata/ahci.h             |  4 +-
>  drivers/ata/libahci_platform.c | 82 +++++++++++++++-------------------
>  2 files changed, 37 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
> index eeac5482f1d1..1564c691094a 100644
> --- a/drivers/ata/ahci.h
> +++ b/drivers/ata/ahci.h
> @@ -38,7 +38,6 @@
>  
>  enum {
>  	AHCI_MAX_PORTS		= 32,
> -	AHCI_MAX_CLKS		= 5,
>  	AHCI_MAX_SG		= 168, /* hardware max is 64K */
>  	AHCI_DMA_BOUNDARY	= 0xffffffff,
>  	AHCI_MAX_CMDS		= 32,
> @@ -341,7 +340,8 @@ struct ahci_host_priv {
>  	u32			em_msg_type;	/* EM message type */
>  	u32			remapped_nvme;	/* NVMe remapped device count */
>  	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
> -	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
> +	unsigned int		n_clks;
> +	struct clk_bulk_data	*clks;		/* Optional */
>  	struct reset_control	*rsts;		/* Optional */
>  	struct regulator	**target_pwrs;	/* Optional */
>  	struct regulator	*ahci_regulator;/* Optional */
> diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
> index 8eabbb5f208c..d805ddc3a024 100644
> --- a/drivers/ata/libahci_platform.c
> +++ b/drivers/ata/libahci_platform.c
> @@ -8,6 +8,7 @@
>   *   Anton Vorontsov <avorontsov@ru.mvista.com>
>   */
>  
> +#include <linux/clk-provider.h>
>  #include <linux/clk.h>
>  #include <linux/kernel.h>
>  #include <linux/gfp.h>
> @@ -97,28 +98,14 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
>   * ahci_platform_enable_clks - Enable platform clocks
>   * @hpriv: host private area to store config values
>   *
> - * This function enables all the clks found in hpriv->clks, starting at
> - * index 0. If any clk fails to enable it disables all the clks already
> - * enabled in reverse order, and then returns an error.
> + * This function enables all the clks found for the AHCI device.
>   *
>   * RETURNS:
>   * 0 on success otherwise a negative error code
>   */
>  int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
>  {
> -	int c, rc;
> -
> -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
> -		rc = clk_prepare_enable(hpriv->clks[c]);
> -		if (rc)
> -			goto disable_unprepare_clk;
> -	}
> -	return 0;
> -
> -disable_unprepare_clk:
> -	while (--c >= 0)
> -		clk_disable_unprepare(hpriv->clks[c]);
> -	return rc;
> +	return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
>  
> @@ -126,16 +113,13 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
>   * ahci_platform_disable_clks - Disable platform clocks
>   * @hpriv: host private area to store config values
>   *
> - * This function disables all the clks found in hpriv->clks, in reverse
> - * order of ahci_platform_enable_clks (starting at the end of the array).
> + * This function disables all the clocks enabled before
> + * (bulk-clocks-disable function is supposed to do that in reverse
> + * from the enabling procedure order).
>   */
>  void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
>  {
> -	int c;
> -
> -	for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
> -		if (hpriv->clks[c])
> -			clk_disable_unprepare(hpriv->clks[c]);
> +	clk_bulk_disable_unprepare(hpriv->n_clks, hpriv->clks);
>  }
>  EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
>  
> @@ -292,8 +276,6 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
>  		pm_runtime_disable(dev);
>  	}
>  
> -	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
> -		clk_put(hpriv->clks[c]);
>  	/*
>  	 * The regulators are tied to child node device and not to the
>  	 * SATA device itself. So we can't use devm for automatically
> @@ -374,8 +356,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
>   * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
>   * 2) regulator for controlling the targets power (optional)
>   *    regulator for controlling the AHCI controller (optional)
> - * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
> - *    or for non devicetree enabled platforms a single clock
> + * 3) all clocks specified in the devicetree node, or a single
> + *    clock for non-OF platforms (optional)
>   * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
>   * 5) phys (optional)
>   *
> @@ -385,11 +367,10 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
>  struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  						   unsigned int flags)
>  {
> +	int enabled_ports = 0, rc = 0, child_nodes;
>  	struct device *dev = &pdev->dev;
>  	struct ahci_host_priv *hpriv;
> -	struct clk *clk;
>  	struct device_node *child;
> -	int i, enabled_ports = 0, rc = 0, child_nodes;
>  	u32 mask_port_map = 0;
>  
>  	if (!devres_open_group(dev, NULL, GFP_KERNEL))
> @@ -413,25 +394,32 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
>  		}
>  	}
>  
> -	for (i = 0; i < AHCI_MAX_CLKS; i++) {
> -		/*
> -		 * For now we must use clk_get(dev, NULL) for the first clock,
> -		 * because some platforms (da850, spear13xx) are not yet
> -		 * converted to use devicetree for clocks.  For new platforms
> -		 * this is equivalent to of_clk_get(dev->of_node, 0).
> -		 */
> -		if (i == 0)
> -			clk = clk_get(dev, NULL);
> -		else
> -			clk = of_clk_get(dev->of_node, i);
> -
> -		if (IS_ERR(clk)) {
> -			rc = PTR_ERR(clk);
> -			if (rc == -EPROBE_DEFER)
> -				goto err_out;
> -			break;
> +	/*
> +	 * Bulk clock get procedure can fail to find any clock due to running
> +	 * an a non-OF platform or due to the clocks being defined in bypass
> +	 * from the DT firmware (like da850, spear13xx). In that case we
> +	 * fallback to getting a single clock source right from the dev clocks
> +	 * list.
> +	 */
> +	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);

I would move the error check first here to make things more readable:

	rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
	if (rc < 0)
		goto err_out;

	if (rc) {
		/* Got clocks in bulk */
		hpriv->n_clks = rc;
	} else {
		/*
		 * No clock bulk found: fallback to manually getting
		 * the optional clock.
		 */
		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks),
					   GFP_KERNEL);
		...
	}

And it may be cleaner to move this entire code hunk into a helper,
something like ahci_platform_get_clks() ?

> +	if (rc > 0) {
> +		hpriv->n_clks = rc;
> +	} else if (!rc) {
> +		hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks), GFP_KERNEL);
> +		if (!hpriv->clks) {
> +			rc = -ENOMEM;
> +			goto err_out;
>  		}
> -		hpriv->clks[i] = clk;
> +		hpriv->clks->clk = devm_clk_get_optional(dev, NULL);
> +		if (IS_ERR(hpriv->clks->clk)) {
> +			rc = PTR_ERR(hpriv->clks->clk);
> +			goto err_out;
> +		} else if (hpriv->clks->clk) {
> +			hpriv->clks->id = __clk_get_name(hpriv->clks->clk);
> +			hpriv->n_clks = 1;
> +		}
> +	} else {
> +		goto err_out;
>  	}
>  
>  	hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");


-- 
Damien Le Moal
Western Digital Research

  reply	other threads:[~2022-03-24  1:29 UTC|newest]

Thread overview: 63+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-24  0:16 [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Serge Semin
2022-03-24  0:16 ` [PATCH 01/21] dt-bindings: ata: sata: Extend number of SATA ports Serge Semin
2022-03-29  8:15   ` Damien Le Moal
2022-04-11 19:25     ` Serge Semin
2022-03-24  0:16 ` [PATCH 02/21] dt-bindings: ata: Convert AHCI-bindings to DT schema Serge Semin
2022-03-28 19:32   ` Rob Herring
2022-04-11 19:34     ` Serge Semin
2022-03-24  0:16 ` [PATCH 03/21] ata: libahci_platform: Explicitly set rc on devres_alloc failure Serge Semin
2022-03-24  0:58   ` Damien Le Moal
2022-03-24 21:37     ` Serge Semin
2022-03-25  1:56       ` Damien Le Moal
2022-04-06 20:03         ` Serge Semin
2022-03-29  8:20   ` Damien Le Moal
2022-03-24  0:16 ` [PATCH 04/21] ata: libahci_platform: Convert to using handy devm-ioremap methods Serge Semin
2022-03-24  1:11   ` Damien Le Moal
2022-04-06 20:42     ` Serge Semin
2022-03-24  0:16 ` [PATCH 05/21] ata: libahci_platform: Convert to using devm bulk clocks API Serge Semin
2022-03-24  1:29   ` Damien Le Moal [this message]
2022-04-09  4:59     ` Serge Semin
2022-03-28 22:36   ` kernel test robot
2022-03-28 23:42   ` kernel test robot
2022-03-29  0:03   ` kernel test robot
2022-03-24  0:16 ` [PATCH 06/21] ata: libahci_platform: Add function returning a clock-handle by id Serge Semin
2022-03-24  1:36   ` Damien Le Moal
2022-04-11  6:02     ` Serge Semin
2022-03-24  0:16 ` [PATCH 07/21] ata: libahci_platform: Sanity check the DT child nodes number Serge Semin
2022-03-24  1:40   ` Damien Le Moal
2022-03-24  8:12     ` Sergey Shtylyov
2022-03-24  8:13       ` Damien Le Moal
2022-04-11 13:10         ` Serge Semin
2022-03-24  0:16 ` [PATCH 08/21] ata: libahci_platform: Parse ports-implemented property in resources getter Serge Semin
2022-03-24  0:16 ` [PATCH 09/21] ata: libahci_platform: Introduce reset assertion/deassertion methods Serge Semin
2022-03-24  1:52   ` Damien Le Moal
2022-04-11 10:57     ` Serge Semin
2022-03-24  0:16 ` [PATCH 10/21] dt-bindings: ata: ahci: Add platform capability properties Serge Semin
2022-03-24  0:16 ` [PATCH 11/21] ata: libahci: Extend port-cmd flags set with port capabilities Serge Semin
2022-03-24  0:16 ` [PATCH 12/21] ata: libahci: Discard redundant force_port_map parameter Serge Semin
2022-03-24  2:05   ` Damien Le Moal
2022-04-11 12:11     ` Serge Semin
2022-04-11 12:25       ` Damien Le Moal
2022-04-11 20:52         ` Serge Semin
2022-04-11 22:48           ` Damien Le Moal
2022-04-12 12:29             ` Serge Semin
2022-03-24  0:16 ` [PATCH 13/21] ata: libahci: Don't read AHCI version twice in the save-config method Serge Semin
2022-03-24  0:16 ` [PATCH 14/21] ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments Serge Semin
2022-03-24  0:16 ` [PATCH 15/21] ata: ahci: Introduce firmware-specific caps initialization Serge Semin
2022-03-24  0:16 ` [PATCH 16/21] dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema Serge Semin
2022-04-01  0:06   ` Rob Herring
2022-04-11 20:00     ` Serge Semin
2022-03-24  0:16 ` [PATCH 17/21] ata: ahci: Add DWC AHCI SATA controller support Serge Semin
2022-03-24  2:21   ` Damien Le Moal
2022-04-11 12:41     ` Serge Semin
2022-04-11 13:03       ` Damien Le Moal
2022-04-11 20:41         ` Serge Semin
2022-03-24  0:16 ` [PATCH 18/21] dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema Serge Semin
2022-03-24  0:16 ` [PATCH 19/21] ata: ahci-dwc: Add platform-specific quirks support Serge Semin
2022-03-24  0:16 ` [PATCH 20/21] ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support Serge Semin
2022-03-24  0:16 ` [PATCH 21/21] MAINTAINERS: Add maintainers for DWC AHCI SATA driver Serge Semin
2022-03-24  2:17   ` Damien Le Moal
2022-04-11 12:16     ` Serge Semin
2022-03-28 20:06 ` [PATCH 00/21] ata: ahci: Add DWC/Baikal-T1 AHCI SATA support Damien Le Moal
2022-03-29  8:30   ` Damien Le Moal
2022-04-06 19:54     ` Serge Semin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=603eb020-3f43-c193-b3f6-8ff697f845c8@opensource.wdc.com \
    --to=damien.lemoal@opensource.wdc.com \
    --cc=Alexey.Malahov@baikalelectronics.ru \
    --cc=Pavel.Parkhomenko@baikalelectronics.ru \
    --cc=Sergey.Semin@baikalelectronics.ru \
    --cc=axboe@kernel.dk \
    --cc=devicetree@vger.kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=hdegoede@redhat.com \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).