cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

libahci_platform.c (20828B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * AHCI SATA platform library
      4 *
      5 * Copyright 2004-2005  Red Hat, Inc.
      6 *   Jeff Garzik <jgarzik@pobox.com>
      7 * Copyright 2010  MontaVista Software, LLC.
      8 *   Anton Vorontsov <avorontsov@ru.mvista.com>
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/kernel.h>
     13#include <linux/gfp.h>
     14#include <linux/module.h>
     15#include <linux/pm.h>
     16#include <linux/interrupt.h>
     17#include <linux/device.h>
     18#include <linux/platform_device.h>
     19#include <linux/libata.h>
     20#include <linux/ahci_platform.h>
     21#include <linux/phy/phy.h>
     22#include <linux/pm_runtime.h>
     23#include <linux/of_platform.h>
     24#include <linux/reset.h>
     25#include "ahci.h"
     26
     27static void ahci_host_stop(struct ata_host *host);
     28
     29struct ata_port_operations ahci_platform_ops = {
     30	.inherits	= &ahci_ops,
     31	.host_stop	= ahci_host_stop,
     32};
     33EXPORT_SYMBOL_GPL(ahci_platform_ops);
     34
     35/**
     36 * ahci_platform_enable_phys - Enable PHYs
     37 * @hpriv: host private area to store config values
     38 *
     39 * This function enables all the PHYs found in hpriv->phys, if any.
     40 * If a PHY fails to be enabled, it disables all the PHYs already
     41 * enabled in reverse order and returns an error.
     42 *
     43 * RETURNS:
     44 * 0 on success otherwise a negative error code
     45 */
     46int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
     47{
     48	int rc, i;
     49
     50	for (i = 0; i < hpriv->nports; i++) {
     51		rc = phy_init(hpriv->phys[i]);
     52		if (rc)
     53			goto disable_phys;
     54
     55		rc = phy_set_mode(hpriv->phys[i], PHY_MODE_SATA);
     56		if (rc) {
     57			phy_exit(hpriv->phys[i]);
     58			goto disable_phys;
     59		}
     60
     61		rc = phy_power_on(hpriv->phys[i]);
     62		if (rc) {
     63			phy_exit(hpriv->phys[i]);
     64			goto disable_phys;
     65		}
     66	}
     67
     68	return 0;
     69
     70disable_phys:
     71	while (--i >= 0) {
     72		phy_power_off(hpriv->phys[i]);
     73		phy_exit(hpriv->phys[i]);
     74	}
     75	return rc;
     76}
     77EXPORT_SYMBOL_GPL(ahci_platform_enable_phys);
     78
     79/**
     80 * ahci_platform_disable_phys - Disable PHYs
     81 * @hpriv: host private area to store config values
     82 *
     83 * This function disables all PHYs found in hpriv->phys.
     84 */
     85void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
     86{
     87	int i;
     88
     89	for (i = 0; i < hpriv->nports; i++) {
     90		phy_power_off(hpriv->phys[i]);
     91		phy_exit(hpriv->phys[i]);
     92	}
     93}
     94EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
     95
     96/**
     97 * ahci_platform_enable_clks - Enable platform clocks
     98 * @hpriv: host private area to store config values
     99 *
    100 * This function enables all the clks found in hpriv->clks, starting at
    101 * index 0. If any clk fails to enable it disables all the clks already
    102 * enabled in reverse order, and then returns an error.
    103 *
    104 * RETURNS:
    105 * 0 on success otherwise a negative error code
    106 */
    107int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
    108{
    109	int c, rc;
    110
    111	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
    112		rc = clk_prepare_enable(hpriv->clks[c]);
    113		if (rc)
    114			goto disable_unprepare_clk;
    115	}
    116	return 0;
    117
    118disable_unprepare_clk:
    119	while (--c >= 0)
    120		clk_disable_unprepare(hpriv->clks[c]);
    121	return rc;
    122}
    123EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
    124
    125/**
    126 * ahci_platform_disable_clks - Disable platform clocks
    127 * @hpriv: host private area to store config values
    128 *
    129 * This function disables all the clks found in hpriv->clks, in reverse
    130 * order of ahci_platform_enable_clks (starting at the end of the array).
    131 */
    132void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
    133{
    134	int c;
    135
    136	for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
    137		if (hpriv->clks[c])
    138			clk_disable_unprepare(hpriv->clks[c]);
    139}
    140EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
    141
    142/**
    143 * ahci_platform_enable_regulators - Enable regulators
    144 * @hpriv: host private area to store config values
    145 *
    146 * This function enables all the regulators found in controller and
    147 * hpriv->target_pwrs, if any.  If a regulator fails to be enabled, it
    148 * disables all the regulators already enabled in reverse order and
    149 * returns an error.
    150 *
    151 * RETURNS:
    152 * 0 on success otherwise a negative error code
    153 */
    154int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
    155{
    156	int rc, i;
    157
    158	rc = regulator_enable(hpriv->ahci_regulator);
    159	if (rc)
    160		return rc;
    161
    162	rc = regulator_enable(hpriv->phy_regulator);
    163	if (rc)
    164		goto disable_ahci_pwrs;
    165
    166	for (i = 0; i < hpriv->nports; i++) {
    167		if (!hpriv->target_pwrs[i])
    168			continue;
    169
    170		rc = regulator_enable(hpriv->target_pwrs[i]);
    171		if (rc)
    172			goto disable_target_pwrs;
    173	}
    174
    175	return 0;
    176
    177disable_target_pwrs:
    178	while (--i >= 0)
    179		if (hpriv->target_pwrs[i])
    180			regulator_disable(hpriv->target_pwrs[i]);
    181
    182	regulator_disable(hpriv->phy_regulator);
    183disable_ahci_pwrs:
    184	regulator_disable(hpriv->ahci_regulator);
    185	return rc;
    186}
    187EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
    188
    189/**
    190 * ahci_platform_disable_regulators - Disable regulators
    191 * @hpriv: host private area to store config values
    192 *
    193 * This function disables all regulators found in hpriv->target_pwrs and
    194 * AHCI controller.
    195 */
    196void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
    197{
    198	int i;
    199
    200	for (i = 0; i < hpriv->nports; i++) {
    201		if (!hpriv->target_pwrs[i])
    202			continue;
    203		regulator_disable(hpriv->target_pwrs[i]);
    204	}
    205
    206	regulator_disable(hpriv->ahci_regulator);
    207	regulator_disable(hpriv->phy_regulator);
    208}
    209EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
    210/**
    211 * ahci_platform_enable_resources - Enable platform resources
    212 * @hpriv: host private area to store config values
    213 *
    214 * This function enables all ahci_platform managed resources in the
    215 * following order:
    216 * 1) Regulator
    217 * 2) Clocks (through ahci_platform_enable_clks)
    218 * 3) Resets
    219 * 4) Phys
    220 *
    221 * If resource enabling fails at any point the previous enabled resources
    222 * are disabled in reverse order.
    223 *
    224 * RETURNS:
    225 * 0 on success otherwise a negative error code
    226 */
    227int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
    228{
    229	int rc;
    230
    231	rc = ahci_platform_enable_regulators(hpriv);
    232	if (rc)
    233		return rc;
    234
    235	rc = ahci_platform_enable_clks(hpriv);
    236	if (rc)
    237		goto disable_regulator;
    238
    239	rc = reset_control_deassert(hpriv->rsts);
    240	if (rc)
    241		goto disable_clks;
    242
    243	rc = ahci_platform_enable_phys(hpriv);
    244	if (rc)
    245		goto disable_resets;
    246
    247	return 0;
    248
    249disable_resets:
    250	reset_control_assert(hpriv->rsts);
    251
    252disable_clks:
    253	ahci_platform_disable_clks(hpriv);
    254
    255disable_regulator:
    256	ahci_platform_disable_regulators(hpriv);
    257
    258	return rc;
    259}
    260EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
    261
    262/**
    263 * ahci_platform_disable_resources - Disable platform resources
    264 * @hpriv: host private area to store config values
    265 *
    266 * This function disables all ahci_platform managed resources in the
    267 * following order:
    268 * 1) Phys
    269 * 2) Resets
    270 * 3) Clocks (through ahci_platform_disable_clks)
    271 * 4) Regulator
    272 */
    273void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
    274{
    275	ahci_platform_disable_phys(hpriv);
    276
    277	reset_control_assert(hpriv->rsts);
    278
    279	ahci_platform_disable_clks(hpriv);
    280
    281	ahci_platform_disable_regulators(hpriv);
    282}
    283EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
    284
    285static void ahci_platform_put_resources(struct device *dev, void *res)
    286{
    287	struct ahci_host_priv *hpriv = res;
    288	int c;
    289
    290	if (hpriv->got_runtime_pm) {
    291		pm_runtime_put_sync(dev);
    292		pm_runtime_disable(dev);
    293	}
    294
    295	for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
    296		clk_put(hpriv->clks[c]);
    297	/*
    298	 * The regulators are tied to child node device and not to the
    299	 * SATA device itself. So we can't use devm for automatically
    300	 * releasing them. We have to do it manually here.
    301	 */
    302	for (c = 0; c < hpriv->nports; c++)
    303		if (hpriv->target_pwrs && hpriv->target_pwrs[c])
    304			regulator_put(hpriv->target_pwrs[c]);
    305
    306	kfree(hpriv->target_pwrs);
    307}
    308
    309static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
    310				struct device *dev, struct device_node *node)
    311{
    312	int rc;
    313
    314	hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
    315
    316	if (!IS_ERR(hpriv->phys[port]))
    317		return 0;
    318
    319	rc = PTR_ERR(hpriv->phys[port]);
    320	switch (rc) {
    321	case -ENOSYS:
    322		/* No PHY support. Check if PHY is required. */
    323		if (of_find_property(node, "phys", NULL)) {
    324			dev_err(dev,
    325				"couldn't get PHY in node %pOFn: ENOSYS\n",
    326				node);
    327			break;
    328		}
    329		fallthrough;
    330	case -ENODEV:
    331		/* continue normally */
    332		hpriv->phys[port] = NULL;
    333		rc = 0;
    334		break;
    335	case -EPROBE_DEFER:
    336		/* Do not complain yet */
    337		break;
    338
    339	default:
    340		dev_err(dev,
    341			"couldn't get PHY in node %pOFn: %d\n",
    342			node, rc);
    343
    344		break;
    345	}
    346
    347	return rc;
    348}
    349
    350static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
    351				struct device *dev)
    352{
    353	struct regulator *target_pwr;
    354	int rc = 0;
    355
    356	target_pwr = regulator_get(dev, "target");
    357
    358	if (!IS_ERR(target_pwr))
    359		hpriv->target_pwrs[port] = target_pwr;
    360	else
    361		rc = PTR_ERR(target_pwr);
    362
    363	return rc;
    364}
    365
    366/**
    367 * ahci_platform_get_resources - Get platform resources
    368 * @pdev: platform device to get resources for
    369 * @flags: bitmap representing the resource to get
    370 *
    371 * This function allocates an ahci_host_priv struct, and gets the following
    372 * resources, storing a reference to them inside the returned struct:
    373 *
    374 * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
    375 * 2) regulator for controlling the targets power (optional)
    376 *    regulator for controlling the AHCI controller (optional)
    377 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
    378 *    or for non devicetree enabled platforms a single clock
    379 * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
    380 * 5) phys (optional)
    381 *
    382 * RETURNS:
    383 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
    384 */
    385struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
    386						   unsigned int flags)
    387{
    388	struct device *dev = &pdev->dev;
    389	struct ahci_host_priv *hpriv;
    390	struct clk *clk;
    391	struct device_node *child;
    392	int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
    393	u32 mask_port_map = 0;
    394
    395	if (!devres_open_group(dev, NULL, GFP_KERNEL))
    396		return ERR_PTR(-ENOMEM);
    397
    398	hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
    399			     GFP_KERNEL);
    400	if (!hpriv)
    401		goto err_out;
    402
    403	devres_add(dev, hpriv);
    404
    405	hpriv->mmio = devm_ioremap_resource(dev,
    406			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
    407	if (IS_ERR(hpriv->mmio)) {
    408		rc = PTR_ERR(hpriv->mmio);
    409		goto err_out;
    410	}
    411
    412	for (i = 0; i < AHCI_MAX_CLKS; i++) {
    413		/*
    414		 * For now we must use clk_get(dev, NULL) for the first clock,
    415		 * because some platforms (da850, spear13xx) are not yet
    416		 * converted to use devicetree for clocks.  For new platforms
    417		 * this is equivalent to of_clk_get(dev->of_node, 0).
    418		 */
    419		if (i == 0)
    420			clk = clk_get(dev, NULL);
    421		else
    422			clk = of_clk_get(dev->of_node, i);
    423
    424		if (IS_ERR(clk)) {
    425			rc = PTR_ERR(clk);
    426			if (rc == -EPROBE_DEFER)
    427				goto err_out;
    428			break;
    429		}
    430		hpriv->clks[i] = clk;
    431	}
    432
    433	hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
    434	if (IS_ERR(hpriv->ahci_regulator)) {
    435		rc = PTR_ERR(hpriv->ahci_regulator);
    436		if (rc != 0)
    437			goto err_out;
    438	}
    439
    440	hpriv->phy_regulator = devm_regulator_get(dev, "phy");
    441	if (IS_ERR(hpriv->phy_regulator)) {
    442		rc = PTR_ERR(hpriv->phy_regulator);
    443		goto err_out;
    444	}
    445
    446	if (flags & AHCI_PLATFORM_GET_RESETS) {
    447		hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
    448		if (IS_ERR(hpriv->rsts)) {
    449			rc = PTR_ERR(hpriv->rsts);
    450			goto err_out;
    451		}
    452	}
    453
    454	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
    455
    456	/*
    457	 * If no sub-node was found, we still need to set nports to
    458	 * one in order to be able to use the
    459	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
    460	 */
    461	if (!child_nodes)
    462		hpriv->nports = 1;
    463
    464	hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
    465	if (!hpriv->phys) {
    466		rc = -ENOMEM;
    467		goto err_out;
    468	}
    469	/*
    470	 * We cannot use devm_ here, since ahci_platform_put_resources() uses
    471	 * target_pwrs after devm_ have freed memory
    472	 */
    473	hpriv->target_pwrs = kcalloc(hpriv->nports, sizeof(*hpriv->target_pwrs), GFP_KERNEL);
    474	if (!hpriv->target_pwrs) {
    475		rc = -ENOMEM;
    476		goto err_out;
    477	}
    478
    479	if (child_nodes) {
    480		for_each_child_of_node(dev->of_node, child) {
    481			u32 port;
    482			struct platform_device *port_dev __maybe_unused;
    483
    484			if (!of_device_is_available(child))
    485				continue;
    486
    487			if (of_property_read_u32(child, "reg", &port)) {
    488				rc = -EINVAL;
    489				of_node_put(child);
    490				goto err_out;
    491			}
    492
    493			if (port >= hpriv->nports) {
    494				dev_warn(dev, "invalid port number %d\n", port);
    495				continue;
    496			}
    497			mask_port_map |= BIT(port);
    498
    499#ifdef CONFIG_OF_ADDRESS
    500			of_platform_device_create(child, NULL, NULL);
    501
    502			port_dev = of_find_device_by_node(child);
    503
    504			if (port_dev) {
    505				rc = ahci_platform_get_regulator(hpriv, port,
    506								&port_dev->dev);
    507				if (rc == -EPROBE_DEFER) {
    508					of_node_put(child);
    509					goto err_out;
    510				}
    511			}
    512#endif
    513
    514			rc = ahci_platform_get_phy(hpriv, port, dev, child);
    515			if (rc) {
    516				of_node_put(child);
    517				goto err_out;
    518			}
    519
    520			enabled_ports++;
    521		}
    522		if (!enabled_ports) {
    523			dev_warn(dev, "No port enabled\n");
    524			rc = -ENODEV;
    525			goto err_out;
    526		}
    527
    528		if (!hpriv->mask_port_map)
    529			hpriv->mask_port_map = mask_port_map;
    530	} else {
    531		/*
    532		 * If no sub-node was found, keep this for device tree
    533		 * compatibility
    534		 */
    535		rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
    536		if (rc)
    537			goto err_out;
    538
    539		rc = ahci_platform_get_regulator(hpriv, 0, dev);
    540		if (rc == -EPROBE_DEFER)
    541			goto err_out;
    542	}
    543	pm_runtime_enable(dev);
    544	pm_runtime_get_sync(dev);
    545	hpriv->got_runtime_pm = true;
    546
    547	devres_remove_group(dev, NULL);
    548	return hpriv;
    549
    550err_out:
    551	devres_release_group(dev, NULL);
    552	return ERR_PTR(rc);
    553}
    554EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
    555
    556/**
    557 * ahci_platform_init_host - Bring up an ahci-platform host
    558 * @pdev: platform device pointer for the host
    559 * @hpriv: ahci-host private data for the host
    560 * @pi_template: template for the ata_port_info to use
    561 * @sht: scsi_host_template to use when registering
    562 *
    563 * This function does all the usual steps needed to bring up an
    564 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
    565 * must be initialized / enabled before calling this.
    566 *
    567 * RETURNS:
    568 * 0 on success otherwise a negative error code
    569 */
    570int ahci_platform_init_host(struct platform_device *pdev,
    571			    struct ahci_host_priv *hpriv,
    572			    const struct ata_port_info *pi_template,
    573			    struct scsi_host_template *sht)
    574{
    575	struct device *dev = &pdev->dev;
    576	struct ata_port_info pi = *pi_template;
    577	const struct ata_port_info *ppi[] = { &pi, NULL };
    578	struct ata_host *host;
    579	int i, irq, n_ports, rc;
    580
    581	irq = platform_get_irq(pdev, 0);
    582	if (irq < 0)
    583		return irq;
    584	if (!irq)
    585		return -EINVAL;
    586
    587	hpriv->irq = irq;
    588
    589	/* prepare host */
    590	pi.private_data = (void *)(unsigned long)hpriv->flags;
    591
    592	ahci_save_initial_config(dev, hpriv);
    593
    594	if (hpriv->cap & HOST_CAP_NCQ)
    595		pi.flags |= ATA_FLAG_NCQ;
    596
    597	if (hpriv->cap & HOST_CAP_PMP)
    598		pi.flags |= ATA_FLAG_PMP;
    599
    600	ahci_set_em_messages(hpriv, &pi);
    601
    602	/* CAP.NP sometimes indicate the index of the last enabled
    603	 * port, at other times, that of the last possible port, so
    604	 * determining the maximum port number requires looking at
    605	 * both CAP.NP and port_map.
    606	 */
    607	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
    608
    609	host = ata_host_alloc_pinfo(dev, ppi, n_ports);
    610	if (!host)
    611		return -ENOMEM;
    612
    613	host->private_data = hpriv;
    614
    615	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
    616		host->flags |= ATA_HOST_PARALLEL_SCAN;
    617	else
    618		dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
    619
    620	if (pi.flags & ATA_FLAG_EM)
    621		ahci_reset_em(host);
    622
    623	for (i = 0; i < host->n_ports; i++) {
    624		struct ata_port *ap = host->ports[i];
    625
    626		ata_port_desc(ap, "mmio %pR",
    627			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
    628		ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
    629
    630		/* set enclosure management message type */
    631		if (ap->flags & ATA_FLAG_EM)
    632			ap->em_message_type = hpriv->em_msg_type;
    633
    634		/* disabled/not-implemented port */
    635		if (!(hpriv->port_map & (1 << i)))
    636			ap->ops = &ata_dummy_port_ops;
    637	}
    638
    639	if (hpriv->cap & HOST_CAP_64) {
    640		rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
    641		if (rc) {
    642			dev_err(dev, "Failed to enable 64-bit DMA.\n");
    643			return rc;
    644		}
    645	}
    646
    647	rc = ahci_reset_controller(host);
    648	if (rc)
    649		return rc;
    650
    651	ahci_init_controller(host);
    652	ahci_print_info(host, "platform");
    653
    654	return ahci_host_activate(host, sht);
    655}
    656EXPORT_SYMBOL_GPL(ahci_platform_init_host);
    657
    658static void ahci_host_stop(struct ata_host *host)
    659{
    660	struct ahci_host_priv *hpriv = host->private_data;
    661
    662	ahci_platform_disable_resources(hpriv);
    663}
    664
    665/**
    666 * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports
    667 * @pdev: platform device pointer for the host
    668 *
    669 * This function is called during system shutdown and performs the minimal
    670 * deconfiguration required to ensure that an ahci_platform host cannot
    671 * corrupt or otherwise interfere with a new kernel being started with kexec.
    672 */
    673void ahci_platform_shutdown(struct platform_device *pdev)
    674{
    675	struct ata_host *host = platform_get_drvdata(pdev);
    676	struct ahci_host_priv *hpriv = host->private_data;
    677	void __iomem *mmio = hpriv->mmio;
    678	int i;
    679
    680	for (i = 0; i < host->n_ports; i++) {
    681		struct ata_port *ap = host->ports[i];
    682
    683		/* Disable port interrupts */
    684		if (ap->ops->freeze)
    685			ap->ops->freeze(ap);
    686
    687		/* Stop the port DMA engines */
    688		if (ap->ops->port_stop)
    689			ap->ops->port_stop(ap);
    690	}
    691
    692	/* Disable and clear host interrupts */
    693	writel(readl(mmio + HOST_CTL) & ~HOST_IRQ_EN, mmio + HOST_CTL);
    694	readl(mmio + HOST_CTL); /* flush */
    695	writel(GENMASK(host->n_ports, 0), mmio + HOST_IRQ_STAT);
    696}
    697EXPORT_SYMBOL_GPL(ahci_platform_shutdown);
    698
    699#ifdef CONFIG_PM_SLEEP
    700/**
    701 * ahci_platform_suspend_host - Suspend an ahci-platform host
    702 * @dev: device pointer for the host
    703 *
    704 * This function does all the usual steps needed to suspend an
    705 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
    706 * must be disabled after calling this.
    707 *
    708 * RETURNS:
    709 * 0 on success otherwise a negative error code
    710 */
    711int ahci_platform_suspend_host(struct device *dev)
    712{
    713	struct ata_host *host = dev_get_drvdata(dev);
    714	struct ahci_host_priv *hpriv = host->private_data;
    715	void __iomem *mmio = hpriv->mmio;
    716	u32 ctl;
    717
    718	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
    719		dev_err(dev, "firmware update required for suspend/resume\n");
    720		return -EIO;
    721	}
    722
    723	/*
    724	 * AHCI spec rev1.1 section 8.3.3:
    725	 * Software must disable interrupts prior to requesting a
    726	 * transition of the HBA to D3 state.
    727	 */
    728	ctl = readl(mmio + HOST_CTL);
    729	ctl &= ~HOST_IRQ_EN;
    730	writel(ctl, mmio + HOST_CTL);
    731	readl(mmio + HOST_CTL); /* flush */
    732
    733	if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS)
    734		ahci_platform_disable_phys(hpriv);
    735
    736	ata_host_suspend(host, PMSG_SUSPEND);
    737	return 0;
    738}
    739EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
    740
    741/**
    742 * ahci_platform_resume_host - Resume an ahci-platform host
    743 * @dev: device pointer for the host
    744 *
    745 * This function does all the usual steps needed to resume an ahci-platform
    746 * host, note any necessary resources (ie clks, phys, etc.)  must be
    747 * initialized / enabled before calling this.
    748 *
    749 * RETURNS:
    750 * 0 on success otherwise a negative error code
    751 */
    752int ahci_platform_resume_host(struct device *dev)
    753{
    754	struct ata_host *host = dev_get_drvdata(dev);
    755	struct ahci_host_priv *hpriv = host->private_data;
    756	int rc;
    757
    758	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
    759		rc = ahci_reset_controller(host);
    760		if (rc)
    761			return rc;
    762
    763		ahci_init_controller(host);
    764	}
    765
    766	if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS)
    767		ahci_platform_enable_phys(hpriv);
    768
    769	ata_host_resume(host);
    770
    771	return 0;
    772}
    773EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
    774
    775/**
    776 * ahci_platform_suspend - Suspend an ahci-platform device
    777 * @dev: the platform device to suspend
    778 *
    779 * This function suspends the host associated with the device, followed by
    780 * disabling all the resources of the device.
    781 *
    782 * RETURNS:
    783 * 0 on success otherwise a negative error code
    784 */
    785int ahci_platform_suspend(struct device *dev)
    786{
    787	struct ata_host *host = dev_get_drvdata(dev);
    788	struct ahci_host_priv *hpriv = host->private_data;
    789	int rc;
    790
    791	rc = ahci_platform_suspend_host(dev);
    792	if (rc)
    793		return rc;
    794
    795	ahci_platform_disable_resources(hpriv);
    796
    797	return 0;
    798}
    799EXPORT_SYMBOL_GPL(ahci_platform_suspend);
    800
    801/**
    802 * ahci_platform_resume - Resume an ahci-platform device
    803 * @dev: the platform device to resume
    804 *
    805 * This function enables all the resources of the device followed by
    806 * resuming the host associated with the device.
    807 *
    808 * RETURNS:
    809 * 0 on success otherwise a negative error code
    810 */
    811int ahci_platform_resume(struct device *dev)
    812{
    813	struct ata_host *host = dev_get_drvdata(dev);
    814	struct ahci_host_priv *hpriv = host->private_data;
    815	int rc;
    816
    817	rc = ahci_platform_enable_resources(hpriv);
    818	if (rc)
    819		return rc;
    820
    821	rc = ahci_platform_resume_host(dev);
    822	if (rc)
    823		goto disable_resources;
    824
    825	/* We resumed so update PM runtime state */
    826	pm_runtime_disable(dev);
    827	pm_runtime_set_active(dev);
    828	pm_runtime_enable(dev);
    829
    830	return 0;
    831
    832disable_resources:
    833	ahci_platform_disable_resources(hpriv);
    834
    835	return rc;
    836}
    837EXPORT_SYMBOL_GPL(ahci_platform_resume);
    838#endif
    839
    840MODULE_DESCRIPTION("AHCI SATA platform library");
    841MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
    842MODULE_LICENSE("GPL");