linux/drivers/ata/ahci.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  ahci.c - AHCI SATA support
 *
 *  Maintained by:  Tejun Heo <[email protected]>
 *    		    Please ALWAYS copy [email protected]
 *		    on emails.
 *
 *  Copyright 2004-2005 Red Hat, Inc.
 *
 * libata documentation is available via 'make {ps|pdf}docs',
 * as Documentation/driver-api/libata.rst
 *
 * AHCI hardware documentation:
 * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
 * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <linux/ahci-remap.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include "ahci.h"

#define DRV_NAME
#define DRV_VERSION

enum {};

enum board_ids {};

static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static void ahci_remove_one(struct pci_dev *dev);
static void ahci_shutdown_one(struct pci_dev *dev);
static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
				 unsigned long deadline);
static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
			      unsigned long deadline);
static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
static bool is_mcp89_apple(struct pci_dev *pdev);
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
				unsigned long deadline);
#ifdef CONFIG_PM
static int ahci_pci_device_runtime_suspend(struct device *dev);
static int ahci_pci_device_runtime_resume(struct device *dev);
#ifdef CONFIG_PM_SLEEP
static int ahci_pci_device_suspend(struct device *dev);
static int ahci_pci_device_resume(struct device *dev);
#endif
#endif /* CONFIG_PM */

static const struct scsi_host_template ahci_sht =;

static struct ata_port_operations ahci_vt8251_ops =;

static struct ata_port_operations ahci_p5wdh_ops =;

static struct ata_port_operations ahci_avn_ops =;

static const struct ata_port_info ahci_port_info[] =;

static const struct pci_device_id ahci_pci_tbl[] =;

static const struct dev_pm_ops ahci_pci_pm_ops =;

static struct pci_driver ahci_pci_driver =;

#if IS_ENABLED(CONFIG_PATA_MARVELL)
static int marvell_enable;
#else
static int marvell_enable = 1;
#endif
module_param(marvell_enable, int, 0644);
MODULE_PARM_DESC();

static int mobile_lpm_policy =;
module_param(mobile_lpm_policy, int, 0644);
MODULE_PARM_DESC();

static char *ahci_mask_port_map;
module_param_named(mask_port_map, ahci_mask_port_map, charp, 0444);
MODULE_PARM_DESC();

static void ahci_apply_port_map_mask(struct device *dev,
				     struct ahci_host_priv *hpriv, char *mask_s)
{}

static void ahci_get_port_map_mask(struct device *dev,
				   struct ahci_host_priv *hpriv)
{}

static void ahci_pci_save_initial_config(struct pci_dev *pdev,
					 struct ahci_host_priv *hpriv)
{}

static int ahci_pci_reset_controller(struct ata_host *host)
{}

static void ahci_pci_init_controller(struct ata_host *host)
{}

static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
				 unsigned long deadline)
{}

static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
				unsigned long deadline)
{}

/*
 * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
 *
 * It has been observed with some SSDs that the timing of events in the
 * link synchronization phase can leave the port in a state that can not
 * be recovered by a SATA-hard-reset alone.  The failing signature is
 * SStatus.DET stuck at 1 ("Device presence detected but Phy
 * communication not established").  It was found that unloading and
 * reloading the driver when this problem occurs allows the drive
 * connection to be recovered (DET advanced to 0x3).  The critical
 * component of reloading the driver is that the port state machines are
 * reset by bouncing "port enable" in the AHCI PCS configuration
 * register.  So, reproduce that effect by bouncing a port whenever we
 * see DET==1 after a reset.
 */
static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
			      unsigned long deadline)
{}


#ifdef CONFIG_PM
static void ahci_pci_disable_interrupts(struct ata_host *host)
{}

static int ahci_pci_device_runtime_suspend(struct device *dev)
{}

static int ahci_pci_device_runtime_resume(struct device *dev)
{}

#ifdef CONFIG_PM_SLEEP
static int ahci_pci_device_suspend(struct device *dev)
{}

static int ahci_pci_device_resume(struct device *dev)
{}
#endif

#endif /* CONFIG_PM */

static int ahci_configure_dma_masks(struct pci_dev *pdev,
				    struct ahci_host_priv *hpriv)
{}

static void ahci_pci_print_info(struct ata_host *host)
{}

/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
 * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
 * support PMP and the 4726 either directly exports the device
 * attached to the first downstream port or acts as a hardware storage
 * controller and emulate a single ATA device (can be RAID 0/1 or some
 * other configuration).
 *
 * When there's no device attached to the first downstream port of the
 * 4726, "Config Disk" appears, which is a pseudo ATA device to
 * configure the 4726.  However, ATA emulation of the device is very
 * lame.  It doesn't send signature D2H Reg FIS after the initial
 * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
 *
 * The following function works around the problem by always using
 * hardreset on the port and not depending on receiving signature FIS
 * afterward.  If signature FIS isn't received soon, ATA class is
 * assumed without follow-up softreset.
 */
static void ahci_p5wdh_workaround(struct ata_host *host)
{}

/*
 * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
 * booting in BIOS compatibility mode.  We restore the registers but not ID.
 */
static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
{}

static bool is_mcp89_apple(struct pci_dev *pdev)
{}

/* only some SB600 ahci controllers can do 64bit DMA */
static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
{}

static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
{}

static bool ahci_broken_suspend(struct pci_dev *pdev)
{}

static bool ahci_broken_lpm(struct pci_dev *pdev)
{}

static bool ahci_broken_online(struct pci_dev *pdev)
{}

#ifdef CONFIG_ATA_ACPI
static void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#else
static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif

/*
 * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
 * as DUMMY, or detected but eventually get a "link down" and never get up
 * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the
 * port_map may hold a value of 0x00.
 *
 * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports
 * and can significantly reduce the occurrence of the problem.
 *
 * https://bugzilla.kernel.org/show_bug.cgi?id=189471
 */
static void acer_sa5_271_workaround(struct ahci_host_priv *hpriv,
				    struct pci_dev *pdev)
{}

#ifdef CONFIG_ARM64
/*
 * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
 * Workaround is to make sure all pending IRQs are served before leaving
 * handler.
 */
static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
{
	struct ata_host *host = dev_instance;
	struct ahci_host_priv *hpriv;
	unsigned int rc = 0;
	void __iomem *mmio;
	u32 irq_stat, irq_masked;
	unsigned int handled = 1;

	hpriv = host->private_data;
	mmio = hpriv->mmio;
	irq_stat = readl(mmio + HOST_IRQ_STAT);
	if (!irq_stat)
		return IRQ_NONE;

	do {
		irq_masked = irq_stat & hpriv->port_map;
		spin_lock(&host->lock);
		rc = ahci_handle_port_intr(host, irq_masked);
		if (!rc)
			handled = 0;
		writel(irq_stat, mmio + HOST_IRQ_STAT);
		irq_stat = readl(mmio + HOST_IRQ_STAT);
		spin_unlock(&host->lock);
	} while (irq_stat);

	return IRQ_RETVAL(handled);
}
#endif

static void ahci_remap_check(struct pci_dev *pdev, int bar,
		struct ahci_host_priv *hpriv)
{}

static int ahci_get_irq_vector(struct ata_host *host, int port)
{}

static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
			struct ahci_host_priv *hpriv)
{}

static void ahci_mark_external_port(struct ata_port *ap)
{}

static void ahci_update_initial_lpm_policy(struct ata_port *ap)
{}

static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
{}

static ssize_t remapped_nvme_show(struct device *dev,
				  struct device_attribute *attr,
				  char *buf)
{}

static DEVICE_ATTR_RO(remapped_nvme);

static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{}

static void ahci_shutdown_one(struct pci_dev *pdev)
{}

static void ahci_remove_one(struct pci_dev *pdev)
{}

module_pci_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
MODULE_VERSION();