drivers/ata/ahci_dwc.c

Source file repositories/reference/linux-study-clean/drivers/ata/ahci_dwc.c

File Facts

System
Linux kernel
Corpus path
drivers/ata/ahci_dwc.c
Extension
.c
Size
11327 bytes
Lines
433
Domain
Driver Families
Bucket
drivers/ata
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ahci_dwc_plat_data {
	unsigned int pflags;
	unsigned int hflags;
	int (*init)(struct ahci_host_priv *hpriv);
	int (*reinit)(struct ahci_host_priv *hpriv);
	void (*clear)(struct ahci_host_priv *hpriv);
};

struct ahci_dwc_host_priv {
	const struct ahci_dwc_plat_data *pdata;
	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;
	dpriv->pdata = device_get_match_data(&pdev->dev);
	if (!dpriv->pdata)
		return ERR_PTR(-EINVAL);

	hpriv = ahci_platform_get_resources(pdev, dpriv->pdata->pflags);
	if (IS_ERR(hpriv))
		return hpriv;

	hpriv->flags |= dpriv->pdata->hflags;
	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;

Annotation

Implementation Notes