Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21b0ad4f authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: add init helpers including ata_pci_prepare_native_host()



These will be used to convert LLDs to new init model.

* Add irq_handler field to port_info.  In new init model, requesting
  IRQ is LLD's responsibility and libata doesn't need to know about
  irq_handler.  Most LLDs can simply register their irq_handler but
  some need different irq_handler depending on specific chip.  The
  added port_info->irq_handler field can be used by LLDs to select
  the matching IRQ handler in such cases.

* Add ata_dummy_port_info.

* Implement ata_pci_prepare_native_host(), a helper to alloc ATA host,
  acquire all resources and init the host in one go.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent d491b27b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6623,6 +6623,10 @@ const struct ata_port_operations ata_dummy_port_ops = {
	.port_stop		= ata_dummy_noret,
};

const struct ata_port_info ata_dummy_port_info = {
	.port_ops		= &ata_dummy_port_ops,
};

/*
 * libata is essentially a library of internal helper functions for
 * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -6634,6 +6638,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
EXPORT_SYMBOL_GPL(sata_deb_timing_long);
EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_info);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_init);
@@ -6727,6 +6732,7 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
#ifdef CONFIG_PM
+65 −2
Original line number Diff line number Diff line
@@ -663,13 +663,12 @@ static int ata_pci_init_bmdma(struct ata_host *host)

	for (i = 0; i < 2; i++) {
		struct ata_port *ap = host->ports[i];
		struct ata_ioports *ioaddr = &ap->ioaddr;
		void __iomem *bmdma = host->iomap[4] + 8 * i;

		if (ata_port_is_dummy(ap))
			continue;

		ioaddr->bmdma_addr = bmdma;
		ap->ioaddr.bmdma_addr = bmdma;
		if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
		    (ioread8(bmdma + 2) & 0x80))
			host->flags |= ATA_HOST_SIMPLEX;
@@ -742,6 +741,70 @@ int ata_pci_init_native_host(struct ata_host *host, unsigned int port_mask)
	return 0;
}

/**
 *	ata_pci_prepare_native_host - helper to prepare native PCI ATA host
 *	@pdev: target PCI device
 *	@ppi: array of port_info
 *	@n_ports: number of ports to allocate
 *	@r_host: out argument for the initialized ATA host
 *
 *	Helper to allocate ATA host for @pdev, acquire all native PCI
 *	resources and initialize it accordingly in one go.
 *
 *	LOCKING:
 *	Inherited from calling layer (may sleep).
 *
 *	RETURNS:
 *	0 on success, -errno otherwise.
 */
int ata_pci_prepare_native_host(struct pci_dev *pdev,
				const struct ata_port_info * const * ppi,
				int n_ports, struct ata_host **r_host)
{
	struct ata_host *host;
	unsigned int port_mask;
	int rc;

	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
		return -ENOMEM;

	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
	if (!host) {
		dev_printk(KERN_ERR, &pdev->dev,
			   "failed to allocate ATA host\n");
		rc = -ENOMEM;
		goto err_out;
	}

	port_mask = ATA_PORT_PRIMARY;
	if (n_ports > 1)
		port_mask |= ATA_PORT_SECONDARY;

	rc = ata_pci_init_native_host(host, port_mask);
	if (rc)
		goto err_out;

	/* init DMA related stuff */
	rc = ata_pci_init_bmdma(host);
	if (rc)
		goto err_bmdma;

	devres_remove_group(&pdev->dev, NULL);
	*r_host = host;
	return 0;

 err_bmdma:
	/* This is necessary because PCI and iomap resources are
	 * merged and releasing the top group won't release the
	 * acquired resources if some of those have been acquired
	 * before entering this function.
	 */
	pcim_iounmap_regions(pdev, 0xf);
 err_out:
	devres_release_group(&pdev->dev, NULL);
	return rc;
}

struct ata_legacy_devres {
	unsigned int	mask;
	unsigned long	cmd_port[2];
+5 −0
Original line number Diff line number Diff line
@@ -668,6 +668,7 @@ struct ata_port_info {
	unsigned long		mwdma_mask;
	unsigned long		udma_mask;
	const struct ata_port_operations *port_ops;
	irq_handler_t		irq_handler;
	void 			*private_data;
};

@@ -690,6 +691,7 @@ extern const unsigned long sata_deb_timing_hotplug[];
extern const unsigned long sata_deb_timing_long[];

extern const struct ata_port_operations ata_dummy_port_ops;
extern const struct ata_port_info ata_dummy_port_info;

static inline const unsigned long *
sata_ehc_deb_timing(struct ata_eh_context *ehc)
@@ -894,6 +896,9 @@ extern struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
extern int ata_pci_init_native_host(struct ata_host *host,
				    unsigned int port_mask);
extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
				const struct ata_port_info * const * ppi,
				int n_ports, struct ata_host **r_host);
extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
#endif /* CONFIG_PCI */