lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 14 Jun 2022 17:53:39 +0900
From:   Damien Le Moal <damien.lemoal@...nsource.wdc.com>
To:     Serge Semin <Sergey.Semin@...kalelectronics.ru>,
        Hans de Goede <hdegoede@...hat.com>,
        Jens Axboe <axboe@...nel.dk>, Hannes Reinecke <hare@...e.de>,
        Serge Semin <fancer.lancer@...il.com>
Cc:     Alexey Malahov <Alexey.Malahov@...kalelectronics.ru>,
        Pavel Parkhomenko <Pavel.Parkhomenko@...kalelectronics.ru>,
        Rob Herring <robh+dt@...nel.org>, linux-ide@...r.kernel.org,
        linux-kernel@...r.kernel.org, devicetree@...r.kernel.org
Subject: Re: [PATCH v4 19/23] ata: ahci: Add DWC AHCI SATA controller support

On 6/10/22 17:17, Serge Semin wrote:
> Synopsys AHCI SATA controller can work pretty under with the generic
> AHCI-platform driver control. But there are vendor-specific peculiarities
> which can tune the device performance up and which may need to be fixed up
> for proper device functioning. In addition some DWC AHCI-based controllers
> may require small platform-specific fixups, so adding them in the generic
> AHCI driver would have ruined the code simplicity. Shortly speaking in
> order to keep the generic AHCI-platform code clean and have DWC AHCI
> SATA-specific features supported we suggest to add a dedicated DWC AHCI
> SATA device driver. Aside with the standard AHCI-platform resources
> getting, enabling/disabling and the controller registration the new driver
> performs the next actions.
> 
> First of all there is a way to verify whether the HBA/ports capabilities
> activated in OF are correct. Almost all features availability is reflected
> in the vendor-specific parameters registers. So the DWC AHCI driver does
> the capabilities sanity check based on the corresponding fields state.
> 
> Secondly if either the Command Completion Coalescing or the Device Sleep
> feature is enabled the DWC AHCI-specific internal 1ms timer must be fixed
> in accordance with the application clock signal frequency. In particular
> the timer value must be set to be Fapp * 1000. Normally the SoC designers
> pre-configure the TIMER1MS register to contain a correct value by default.
> But the platforms can support the application clock rate change. If that
> happens the 1ms timer value must be accordingly updated otherwise the
> dependent features won't work as expected. In the DWC AHCI driver we
> suggest to rely on the "aclk" reference clock rate to set the timer
> interval up. That clock source is supposed to be the AHCI SATA application
> clock in accordance with the DT bindings.
> 
> Finally DWC AHCI SATA controller AXI/AHB bus DMA-engine can be tuned up to
> transfer up to 1024 * FIFO words at a time by setting the Tx/Rx
> transaction size in the DMA control register. The maximum value depends on
> the DMA data bus and AXI/AHB bus maximum burst length. In most of the
> cases it's better to set the maximum possible value to reach the best AHCI
> SATA controller performance. But sometimes in order to improve the system
> interconnect responsiveness, transferring in smaller data chunks may be
> more preferable. For such cases and for the case when the default value
> doesn't provide the best DMA bus performance we suggest to use the new
> HBA-port specific DT-properties "snps,{tx,rx}-ts-max" to tune the DMA
> transactions size up.
> 
> After all the settings denoted above are handled the DWC AHCI SATA driver
> proceeds further with the standard AHCI-platform host initializations.
> 
> Note since DWC AHCI controller is now have a dedicated driver we can
> discard the corresponding compatible string from the ahci-platform.c
> module. The same concerns "snps,spear-ahci" compatible string, which is
> also based on the DWC AHCI IP-core.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@...kalelectronics.ru>
> Reviewed-by: Hannes Reinecke <hare@...e.de>
> 
> ---
> 
> Note there are three more AHCI SATA drivers which have been created for
> the devices based on the DWC AHCI SATA IP-core. It's AHCI SunXi, St and
> iMX drivers. Mostly they don't support the features implemented in this
> driver. So hopefully sometime in future they can be converted to be based
> on the generic DWC AHCI SATA driver and just perform some
> subvendor-specific setups in their own LLDD (glue) driver code. But for
> now let's leave the generic DWC AHCI SATA code as is. Hopefully the new
> DWC AHCI-based device drivers will try at least to re-use a part of the
> DWC AHCI driver methods if not being able to be integrated in the generic
> DWC driver code.
> 
> Changelog v2:
> - Change the local objects prefix from 'dwc_ahci_' to 'ahci_dwc_'.
>   (@Damien)
> 
> Changelog v4:
> - Replace GPLv2 with just GPL license which are the same in the framework
>   of the MODULE_LICENSE() macro.
> ---
>  drivers/ata/Kconfig         |  10 +
>  drivers/ata/Makefile        |   1 +
>  drivers/ata/ahci_dwc.c      | 395 ++++++++++++++++++++++++++++++++++++
>  drivers/ata/ahci_platform.c |   2 -
>  4 files changed, 406 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/ata/ahci_dwc.c
> 
> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> index bb45a9c00514..95e0e022b5bb 100644
> --- a/drivers/ata/Kconfig
> +++ b/drivers/ata/Kconfig
> @@ -176,6 +176,16 @@ config AHCI_DM816
>  
>  	  If unsure, say N.
>  
> +config AHCI_DWC
> +	tristate "Synopsys DWC AHCI SATA support"
> +	select SATA_HOST
> +	default SATA_AHCI_PLATFORM
> +	help
> +	  This option enables support for the Synopsys DWC AHCI SATA
> +	  controller implementation.
> +
> +	  If unsure, say N.
> +
>  config AHCI_ST
>  	tristate "ST AHCI SATA support"
>  	depends on ARCH_STI
> diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> index b8aebfb14e82..34623365d9a6 100644
> --- a/drivers/ata/Makefile
> +++ b/drivers/ata/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_DM816)	+= ahci_dm816.o libahci.o libahci_platform.o
> +obj-$(CONFIG_AHCI_DWC)		+= ahci_dwc.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_IMX)		+= ahci_imx.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_MTK)		+= ahci_mtk.o libahci.o libahci_platform.o
>  obj-$(CONFIG_AHCI_MVEBU)	+= ahci_mvebu.o libahci.o libahci_platform.o
> diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
> new file mode 100644
> index 000000000000..8c2510933a31
> --- /dev/null
> +++ b/drivers/ata/ahci_dwc.c
> @@ -0,0 +1,395 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * DWC AHCI SATA Platform driver
> + *
> + * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
> + */
> +
> +#include <linux/ahci_platform.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/libata.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm.h>
> +
> +#include "ahci.h"
> +
> +#define DRV_NAME "ahci-dwc"
> +
> +#define AHCI_DWC_FBS_PMPN_MAX		15
> +
> +/* DWC AHCI SATA controller specific registers */
> +#define AHCI_DWC_HOST_OOBR		0xbc
> +#define AHCI_DWC_HOST_OOB_WE		BIT(31)
> +#define AHCI_DWC_HOST_CWMIN_MASK	GENMASK(30, 24)
> +#define AHCI_DWC_HOST_CWMAX_MASK	GENMASK(23, 16)
> +#define AHCI_DWC_HOST_CIMIN_MASK	GENMASK(15, 8)
> +#define AHCI_DWC_HOST_CIMAX_MASK	GENMASK(7, 0)
> +
> +#define AHCI_DWC_HOST_GPCR		0xd0
> +#define AHCI_DWC_HOST_GPSR		0xd4
> +
> +#define AHCI_DWC_HOST_TIMER1MS		0xe0
> +#define AHCI_DWC_HOST_TIMV_MASK		GENMASK(19, 0)
> +
> +#define AHCI_DWC_HOST_GPARAM1R		0xe8
> +#define AHCI_DWC_HOST_ALIGN_M		BIT(31)
> +#define AHCI_DWC_HOST_RX_BUFFER		BIT(30)
> +#define AHCI_DWC_HOST_PHY_DATA_MASK	GENMASK(29, 28)
> +#define AHCI_DWC_HOST_PHY_RST		BIT(27)
> +#define AHCI_DWC_HOST_PHY_CTRL_MASK	GENMASK(26, 21)
> +#define AHCI_DWC_HOST_PHY_STAT_MASK	GENMASK(20, 15)
> +#define AHCI_DWC_HOST_LATCH_M		BIT(14)
> +#define AHCI_DWC_HOST_PHY_TYPE_MASK	GENMASK(13, 11)
> +#define AHCI_DWC_HOST_RET_ERR		BIT(10)
> +#define AHCI_DWC_HOST_AHB_ENDIAN_MASK	GENMASK(9, 8)
> +#define AHCI_DWC_HOST_S_HADDR		BIT(7)
> +#define AHCI_DWC_HOST_M_HADDR		BIT(6)
> +#define AHCI_DWC_HOST_S_HDATA_MASK	GENMASK(5, 3)
> +#define AHCI_DWC_HOST_M_HDATA_MASK	GENMASK(2, 0)
> +
> +#define AHCI_DWC_HOST_GPARAM2R		0xec
> +#define AHCI_DWC_HOST_FBS_MEM_S		BIT(19)
> +#define AHCI_DWC_HOST_FBS_PMPN_MASK	GENMASK(17, 16)
> +#define AHCI_DWC_HOST_FBS_SUP		BIT(15)
> +#define AHCI_DWC_HOST_DEV_CP		BIT(14)
> +#define AHCI_DWC_HOST_DEV_MP		BIT(13)
> +#define AHCI_DWC_HOST_ENCODE_M		BIT(12)
> +#define AHCI_DWC_HOST_RXOOB_CLK_M	BIT(11)
> +#define AHCI_DWC_HOST_RXOOB_M		BIT(10)
> +#define AHCI_DWC_HOST_TXOOB_M		BIT(9)
> +#define AHCI_DWC_HOST_RXOOB_M		BIT(10)
> +#define AHCI_DWC_HOST_RXOOB_CLK_MASK	GENMASK(8, 0)
> +
> +#define AHCI_DWC_HOST_PPARAMR		0xf0
> +#define AHCI_DWC_HOST_TX_MEM_M		BIT(11)
> +#define AHCI_DWC_HOST_TX_MEM_S		BIT(10)
> +#define AHCI_DWC_HOST_RX_MEM_M		BIT(9)
> +#define AHCI_DWC_HOST_RX_MEM_S		BIT(8)
> +#define AHCI_DWC_HOST_TXFIFO_DEPTH	GENMASK(7, 4)
> +#define AHCI_DWC_HOST_RXFIFO_DEPTH	GENMASK(3, 0)
> +
> +#define AHCI_DWC_HOST_TESTR		0xf4
> +#define AHCI_DWC_HOST_PSEL_MASK		GENMASK(18, 16)
> +#define AHCI_DWC_HOST_TEST_IF		BIT(0)
> +
> +#define AHCI_DWC_HOST_VERSIONR		0xf8
> +#define AHCI_DWC_HOST_IDR		0xfc
> +
> +#define AHCI_DWC_PORT_DMACR		0x70
> +#define AHCI_DWC_PORT_RXABL_MASK	GENMASK(15, 12)
> +#define AHCI_DWC_PORT_TXABL_MASK	GENMASK(11, 8)
> +#define AHCI_DWC_PORT_RXTS_MASK		GENMASK(7, 4)
> +#define AHCI_DWC_PORT_TXTS_MASK		GENMASK(3, 0)
> +#define AHCI_DWC_PORT_PHYCR		0x74
> +#define AHCI_DWC_PORT_PHYSR		0x78
> +
> +struct ahci_dwc_host_priv {
> +	struct platform_device *pdev;
> +
> +	u32 timv;
> +	u32 dmacr[AHCI_MAX_PORTS];
> +};
> +
> +static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)
> +{
> +	struct ahci_dwc_host_priv *dpriv;
> +	struct ahci_host_priv *hpriv;
> +
> +	dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);
> +	if (!dpriv)
> +		return ERR_PTR(-ENOMEM);
> +
> +	dpriv->pdev = pdev;
> +
> +	hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
> +	if (IS_ERR(hpriv))
> +		return hpriv;
> +
> +	hpriv->plat_data = (void *)dpriv;
> +
> +	return hpriv;
> +}
> +
> +static void ahci_dwc_check_cap(struct ahci_host_priv *hpriv)
> +{
> +	unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
> +	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
> +	bool dev_mp, dev_cp, fbs_sup;
> +	unsigned int fbs_pmp;
> +	u32 param;
> +	int i;
> +
> +	param = readl(hpriv->mmio + AHCI_DWC_HOST_GPARAM2R);
> +	dev_mp = !!(param & AHCI_DWC_HOST_DEV_MP);
> +	dev_cp = !!(param & AHCI_DWC_HOST_DEV_CP);
> +	fbs_sup = !!(param & AHCI_DWC_HOST_FBS_SUP);
> +	fbs_pmp = 5 * FIELD_GET(AHCI_DWC_HOST_FBS_PMPN_MASK, param);
> +
> +	if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {
> +		dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");
> +		hpriv->saved_cap &= ~HOST_CAP_MPS;
> +	}
> +
> +
> +	if (fbs_sup && fbs_pmp < AHCI_DWC_FBS_PMPN_MAX) {
> +		dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",
> +			 fbs_pmp);
> +	}
> +
> +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> +		if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {
> +			dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;
> +		}
> +
> +		if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {
> +			dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;
> +		}
> +
> +		if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {
> +			dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);
> +			hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;
> +		}
> +	}
> +}
> +
> +static void ahci_dwc_init_timer(struct ahci_host_priv *hpriv)
> +{
> +	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
> +	unsigned long rate;
> +	struct clk *aclk;
> +	u32 cap, cap2;
> +
> +	/* 1ms tick is generated only for the CCC or DevSleep features */
> +	cap = readl(hpriv->mmio + HOST_CAP);
> +	cap2 = readl(hpriv->mmio + HOST_CAP2);
> +	if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))
> +		return;
> +
> +	/*
> +	 * Tick is generated based on the AXI/AHB application clocks signal
> +	 * so we need to be sure in the clock we are going to use.
> +	 */
> +	aclk = ahci_platform_find_clk(hpriv, "aclk");
> +	if (!aclk)
> +		return;
> +
> +	/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */
> +	dpriv->timv = readl(hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
> +	dpriv->timv = FIELD_GET(AHCI_DWC_HOST_TIMV_MASK, dpriv->timv);
> +	rate = clk_get_rate(aclk) / 1000UL;
> +	if (rate == dpriv->timv)
> +		return;
> +
> +	dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",
> +		 rate / 1000UL);
> +	dpriv->timv = FIELD_PREP(AHCI_DWC_HOST_TIMV_MASK, rate);
> +	writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
> +}
> +
> +static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv)
> +{
> +	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
> +	struct device_node *child;
> +	void __iomem *port_mmio;
> +	u32 port, dmacr, ts;
> +
> +	/*
> +	 * Update the DMA Tx/Rx transaction sizes in accordance with the
> +	 * platform setup. Note values exceeding maximal or minimal limits will
> +	 * be automatically clamped. Also note the register isn't affected by
> +	 * the HBA global reset so we can freely initialize it once until the
> +	 * next system reset.
> +	 */
> +	for_each_child_of_node(dpriv->pdev->dev.of_node, child) {
> +		if (!of_device_is_available(child))
> +			continue;
> +
> +		if (of_property_read_u32(child, "reg", &port)) {
> +			of_node_put(child);
> +			return -EINVAL;
> +		}
> +
> +		port_mmio = __ahci_port_base(hpriv, port);
> +		dmacr = readl(port_mmio + AHCI_DWC_PORT_DMACR);
> +
> +		if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
> +			ts = ilog2(ts);
> +			dmacr &= ~AHCI_DWC_PORT_TXTS_MASK;
> +			dmacr |= FIELD_PREP(AHCI_DWC_PORT_TXTS_MASK, ts);
> +		}
> +
> +		if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
> +			ts = ilog2(ts);
> +			dmacr &= ~AHCI_DWC_PORT_RXTS_MASK;
> +			dmacr |= FIELD_PREP(AHCI_DWC_PORT_RXTS_MASK, ts);
> +		}
> +
> +		writel(dmacr, port_mmio + AHCI_DWC_PORT_DMACR);
> +		dpriv->dmacr[port] = dmacr;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ahci_dwc_init_host(struct ahci_host_priv *hpriv)
> +{
> +	int rc;
> +
> +	rc = ahci_platform_enable_resources(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	ahci_dwc_check_cap(hpriv);
> +
> +	ahci_dwc_init_timer(hpriv);
> +
> +	rc = ahci_dwc_init_dmacr(hpriv);
> +	if (rc)
> +		goto err_disable_resources;
> +
> +	return 0;
> +
> +err_disable_resources:
> +	ahci_platform_disable_resources(hpriv);
> +
> +	return rc;
> +}
> +
> +static int ahci_dwc_reinit_host(struct ahci_host_priv *hpriv)
> +{
> +	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
> +	unsigned long port_map = hpriv->port_map;
> +	void __iomem *port_mmio;
> +	int i, rc;
> +
> +	rc = ahci_platform_enable_resources(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
> +
> +	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
> +		port_mmio = __ahci_port_base(hpriv, i);
> +		writel(dpriv->dmacr[i], port_mmio + AHCI_DWC_PORT_DMACR);
> +	}
> +
> +	return 0;
> +}
> +
> +static void ahci_dwc_clear_host(struct ahci_host_priv *hpriv)
> +{
> +	ahci_platform_disable_resources(hpriv);
> +}
> +
> +static void ahci_dwc_stop_host(struct ata_host *host)
> +{
> +	struct ahci_host_priv *hpriv = host->private_data;
> +
> +	ahci_dwc_clear_host(hpriv);
> +}
> +
> +static struct ata_port_operations ahci_dwc_port_ops = {
> +	.inherits	= &ahci_platform_ops,
> +	.host_stop	= ahci_dwc_stop_host,
> +};
> +
> +static const struct ata_port_info ahci_dwc_port_info = {
> +	.flags		= AHCI_FLAG_COMMON,
> +	.pio_mask	= ATA_PIO4,
> +	.udma_mask	= ATA_UDMA6,
> +	.port_ops	= &ahci_dwc_port_ops,
> +};
> +
> +static struct scsi_host_template ahci_dwc_scsi_info = {
> +	AHCI_SHT(DRV_NAME),
> +};
> +
> +static int ahci_dwc_probe(struct platform_device *pdev)
> +{
> +	struct ahci_host_priv *hpriv;
> +	int rc;
> +
> +	hpriv = ahci_dwc_get_resources(pdev);
> +	if (IS_ERR(hpriv))
> +		return PTR_ERR(hpriv);
> +
> +	rc = ahci_dwc_init_host(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	rc = ahci_platform_init_host(pdev, hpriv, &ahci_dwc_port_info,
> +				     &ahci_dwc_scsi_info);
> +	if (rc)
> +		goto err_clear_host;
> +
> +	return 0;
> +
> +err_clear_host:
> +	ahci_dwc_clear_host(hpriv);
> +
> +	return rc;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int ahci_dwc_suspend(struct device *dev)
> +{
> +	struct ata_host *host = dev_get_drvdata(dev);
> +	struct ahci_host_priv *hpriv = host->private_data;
> +	int rc;
> +
> +	rc = ahci_platform_suspend_host(dev);
> +	if (rc)
> +		return rc;
> +
> +	ahci_dwc_clear_host(hpriv);
> +
> +	return 0;
> +}
> +
> +static int ahci_dwc_resume(struct device *dev)
> +{
> +	struct ata_host *host = dev_get_drvdata(dev);
> +	struct ahci_host_priv *hpriv = host->private_data;
> +	int rc;
> +
> +	rc = ahci_dwc_reinit_host(hpriv);
> +	if (rc)
> +		return rc;
> +
> +	return ahci_platform_resume_host(dev);
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(ahci_dwc_pm_ops, ahci_dwc_suspend, ahci_dwc_resume);

include/linux/pm.h says:
/* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */

> +
> +static const struct of_device_id ahci_dwc_of_match[] = {
> +	{ .compatible = "snps,dwc-ahci", },
> +	{ .compatible = "snps,spear-ahci", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);
> +
> +static struct platform_driver ahci_dwc_driver = {
> +	.probe = ahci_dwc_probe,
> +	.remove = ata_platform_remove_one,
> +	.shutdown = ahci_platform_shutdown,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = ahci_dwc_of_match,
> +		.pm = &ahci_dwc_pm_ops,
> +	},
> +};
> +module_platform_driver(ahci_dwc_driver);
> +
> +MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
> +MODULE_AUTHOR("Serge Semin <Sergey.Semin@...kalelectronics.ru>");
> +MODULE_LICENSE("GPL");

MODULE_LICENSE("GPL v2");

To match the file header SPDX.

> diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
> index 9b56490ecbc3..8f5572a9f8f1 100644
> --- a/drivers/ata/ahci_platform.c
> +++ b/drivers/ata/ahci_platform.c
> @@ -80,9 +80,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
>  static const struct of_device_id ahci_of_match[] = {
>  	{ .compatible = "generic-ahci", },
>  	/* Keep the following compatibles for device tree compatibility */
> -	{ .compatible = "snps,spear-ahci", },
>  	{ .compatible = "ibm,476gtr-ahci", },
> -	{ .compatible = "snps,dwc-ahci", },
>  	{ .compatible = "hisilicon,hisi-ahci", },
>  	{ .compatible = "cavium,octeon-7130-ahci", },
>  	{ /* sentinel */ }


-- 
Damien Le Moal
Western Digital Research

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ