From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, alan@lxorguk.ukuu.org.uk, mlord@pobox.com,
albertcc@tw.ibm.com, uchang@tw.ibm.com, forrest.zhao@intel.com,
brking@us.ibm.com, linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 8/20] libata: reimplement ata_pci_init_one() using new init helpers
Date: Sat, 19 Aug 2006 17:59:32 +0900 [thread overview]
Message-ID: <11559779723326-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11559778241753-git-send-email-htejun@gmail.com>
Reimplement ata_pci_init_one() using new init helpers. New
implementation is split into to functions - ata_pci_host_prepare() and
ata_pci_init_one(). ata_pci_host_prepare() prepares host for the
specified pdev. The split is to give LLDs more flexibility.
ata_pci_host_prepare() can handle all combinations of native and
legacy ports, but ata_pci_init_one() still applies the same
restriction as before for compatibility.
New implementation properly releases legacy resources on remove.
Other than that, there's no behavior change.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-bmdma.c | 204 --------------------------------------------
drivers/ata/libata-core.c | 1
drivers/ata/libata-pci.c | 191 +++++++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 4 +
4 files changed, 195 insertions(+), 205 deletions(-)
diff --git a/drivers/ata/libata-bmdma.c b/drivers/ata/libata-bmdma.c
index 7605028..672df5a 100644
--- a/drivers/ata/libata-bmdma.c
+++ b/drivers/ata/libata-bmdma.c
@@ -865,210 +865,6 @@ ata_pci_init_native_mode(struct pci_dev
return probe_ent;
}
-
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
- struct ata_port_info **port, int port_mask)
-{
- struct ata_probe_ent *probe_ent;
- unsigned long bmdma = pci_resource_start(pdev, 4);
-
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- if (!probe_ent)
- return NULL;
-
- probe_ent->n_ports = 2;
- probe_ent->private_data = port[0]->private_data;
-
- if (port_mask & ATA_PORT_PRIMARY) {
- probe_ent->irq = 14;
- probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
- if (bmdma) {
- probe_ent->port[0].bmdma_addr = bmdma;
- if (inb(bmdma + 2) & 0x80)
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- }
- ata_std_ports(&probe_ent->port[0]);
- } else
- probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
-
- if (port_mask & ATA_PORT_SECONDARY) {
- if (probe_ent->irq)
- probe_ent->irq2 = 15;
- else
- probe_ent->irq = 15;
- probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
- probe_ent->port[1].altstatus_addr =
- probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
- if (bmdma) {
- probe_ent->port[1].bmdma_addr = bmdma + 8;
- if (inb(bmdma + 10) & 0x80)
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- }
- ata_std_ports(&probe_ent->port[1]);
- } else
- probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
-
- return probe_ent;
-}
-
-
-/**
- * ata_pci_init_one - Initialize/register PCI IDE host controller
- * @pdev: Controller to be initialized
- * @port_info: Information from low-level host driver
- * @n_ports: Number of ports attached to host controller
- *
- * This is a helper function which can be called from a driver's
- * xxx_init_one() probe function if the hardware uses traditional
- * IDE taskfile registers.
- *
- * This function calls pci_enable_device(), reserves its register
- * regions, sets the dma mask, enables bus master mode, and calls
- * ata_device_add()
- *
- * ASSUMPTION:
- * Nobody makes a single channel controller that appears solely as
- * the secondary legacy port on PCI.
- *
- * LOCKING:
- * Inherited from PCI layer (may sleep).
- *
- * RETURNS:
- * Zero on success, negative on errno-based value on error.
- */
-
-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
- unsigned int n_ports)
-{
- struct ata_probe_ent *probe_ent = NULL;
- struct ata_port_info *port[2];
- u8 tmp8, mask;
- unsigned int legacy_mode = 0;
- int disable_dev_on_err = 1;
- int rc;
-
- DPRINTK("ENTER\n");
-
- port[0] = port_info[0];
- if (n_ports > 1)
- port[1] = port_info[1];
- else
- port[1] = port[0];
-
- if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- /* TODO: What if one channel is in native mode ... */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
- mask = (1 << 2) | (1 << 0);
- if ((tmp8 & mask) != mask)
- legacy_mode = (1 << 3);
- }
-
- /* FIXME... */
- if ((!legacy_mode) && (n_ports > 2)) {
- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
- n_ports = 2;
- /* For now */
- }
-
- /* FIXME: Really for ATA it isn't safe because the device may be
- multi-purpose and we want to leave it alone if it was already
- enabled. Secondly for shared use as Arjan says we want refcounting
-
- Checking dev->is_enabled is insufficient as this is not set at
- boot for the primary video which is BIOS enabled
- */
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- disable_dev_on_err = 0;
- goto err_out;
- }
-
- if (legacy_mode) {
- if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
- struct resource *conflict, res;
- res.start = ATA_PRIMARY_CMD;
- res.end = ATA_PRIMARY_CMD + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= ATA_PORT_PRIMARY;
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x%0X IDE port busy\n", ATA_PRIMARY_CMD);
- }
- } else
- legacy_mode |= ATA_PORT_PRIMARY;
-
- if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
- struct resource *conflict, res;
- res.start = ATA_SECONDARY_CMD;
- res.end = ATA_SECONDARY_CMD + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= ATA_PORT_SECONDARY;
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x%X IDE port busy\n", ATA_SECONDARY_CMD);
- }
- } else
- legacy_mode |= ATA_PORT_SECONDARY;
- }
-
- /* we have legacy mode, but all ports are unavailable */
- if (legacy_mode == (1 << 3)) {
- rc = -EBUSY;
- goto err_out_regions;
- }
-
- /* FIXME: If we get no DMA mask we should fall back to PIO */
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- if (legacy_mode) {
- probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
- } else {
- if (n_ports == 2)
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- else
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
- }
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return */
- ata_device_add(probe_ent);
-
- kfree(probe_ent);
-
- return 0;
-
-err_out_regions:
- if (legacy_mode & ATA_PORT_PRIMARY)
- release_region(ATA_PRIMARY_CMD, 8);
- if (legacy_mode & ATA_PORT_SECONDARY)
- release_region(ATA_SECONDARY_CMD, 8);
- pci_release_regions(pdev);
-err_out:
- if (disable_dev_on_err)
- pci_disable_device(pdev);
- return rc;
-}
-
/**
* ata_pci_clear_simplex - attempt to kick device out of simplex
* @pdev: PCI device
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b293d47..0509935 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6651,7 +6651,6 @@ #ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
-EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
diff --git a/drivers/ata/libata-pci.c b/drivers/ata/libata-pci.c
index d1e4194..9649a8c 100644
--- a/drivers/ata/libata-pci.c
+++ b/drivers/ata/libata-pci.c
@@ -407,6 +407,133 @@ void ata_pci_free_msix_irqs(struct ata_h
}
/**
+ * ata_pci_host_prepare - prepare PCI native/legacy ATA device for attach
+ * @pdev: target PCI device
+ * @pinfo_ar: array of pointers to ATA port_info
+ * @mask: available port mask
+ * @legacy_mask: legacy port mask
+ * @r_host: out arg for prepared ATA host
+ *
+ * Allocate and initialize ATA host for PCI ATA device @pdev.
+ * Ports of @pdev can be in either native or legacy mode. All
+ * related PCI resources including IRQs are acquired by this
+ * function. Returned ATA host is ready to be attached using
+ * ata_host_attach().
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_pci_host_prepare(struct pci_dev *pdev, struct ata_port_info **pinfo_ar,
+ unsigned int mask, unsigned int legacy_mask,
+ struct ata_host **r_host)
+{
+ struct ata_host *host = NULL;
+ struct ata_port_info dummy_pinfo;
+ const struct ata_port_info *pi[2];
+ irqreturn_t (*handler[2])(int, void *, struct pt_regs *);
+ void *dev_id[2];
+ unsigned int legacy_irq_flags[2];
+ int n_ports, i, rc;
+ const char *reason;
+
+ /* prep and count n_ports */
+ if (pinfo_ar[0])
+ dummy_pinfo = *pinfo_ar[0];
+ else
+ dummy_pinfo = *pinfo_ar[1];
+ dummy_pinfo.port_ops = &ata_dummy_port_ops;
+ pi[0] = &dummy_pinfo;
+ pi[1] = &dummy_pinfo;
+
+ n_ports = 0;
+ if (mask & ATA_PORT_PRIMARY) {
+ pi[0] = pinfo_ar[0];
+ n_ports = 1;
+ }
+ if (mask & ATA_PORT_SECONDARY) {
+ pi[1] = pinfo_ar[1];
+ n_ports = 2;
+ }
+
+ /* allocate host */
+ host = ata_host_alloc_pinfo_ar(&pdev->dev, pi, n_ports);
+ if (!host) {
+ reason = "failed to allocate host";
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /* acquire PCI and legacy resources and init host accordingly */
+ host->legacy_flags |= legacy_mask & ATA_LEGACY_MASK;
+
+ rc = ata_pci_acquire_resources(host, ATA_DMA_MASK, &reason);
+ if (rc)
+ goto err;
+
+ ata_pci_init_ports(host);
+
+ rc = ata_legacy_acquire_resources(host, &reason);
+ if (rc)
+ goto err;
+
+ ata_legacy_init_ports(host);
+
+ /* do we have any port? */
+ for (i = 0; i < host->n_ports; i++)
+ if (!ata_port_is_dummy(host->ports[i]))
+ break;
+
+ if (i == host->n_ports) {
+ reason = "no available port";
+ rc = -ENODEV;
+ goto err;
+ }
+
+ /* request legacy IRQs */
+ for (i = 0; i < 2; i++) {
+ handler[i] = pi[i]->port_ops->irq_handler;
+ dev_id[i] = host;
+ legacy_irq_flags[i] = 0;
+ }
+
+ rc = ata_legacy_request_irqs(host, handler, legacy_irq_flags, dev_id,
+ &reason);
+ if (rc)
+ goto err;
+
+ /* request native IRQ if there is any native port */
+ for (i = 0; i < host->n_ports; i++)
+ if (!(host->legacy_flags & (1 << i)))
+ break;
+
+ if (i < host->n_ports) {
+ rc = ata_pci_request_irq(host, handler[i], IRQF_SHARED,
+ dev_id[i], &reason);
+ if (rc)
+ goto err;
+
+ /* only for info printing */
+ if (!host->irq)
+ host->irq = pdev->irq;
+ else
+ host->irq2 = pdev->irq;
+ }
+
+ pci_set_master(pdev);
+
+ *r_host = host;
+ return 0;
+
+ err:
+ ata_pci_host_destroy(host);
+ dev_printk(KERN_ERR, &pdev->dev, "%s (error=%d)\n", reason, rc);
+ return rc;
+}
+
+/**
* ata_pci_host_destroy - destroy PCI ATA host
* @host: target ATA host
*
@@ -419,6 +546,7 @@ void ata_pci_free_msix_irqs(struct ata_h
void ata_pci_host_destroy(struct ata_host *host)
{
/* free IRQs */
+ ata_legacy_free_irqs(host);
ata_pci_free_msix_irqs(host);
ata_pci_free_irq(host);
@@ -426,10 +554,71 @@ void ata_pci_host_destroy(struct ata_hos
ata_host_stop(host);
/* release resources */
+ ata_legacy_release_resources(host);
ata_pci_release_resources(host);
ata_host_free(host);
}
+/**
+ * ata_pci_init_one - Initialize/register PCI IDE host controller
+ * @pdev: Controller to be initialized
+ * @pinfo_ar: Information from low-level host driver
+ * @n_ports: Number of ports attached to host controller
+ *
+ * This is a helper function which can be called from a driver's
+ * xxx_init_one() probe function if the hardware uses traditional
+ * IDE taskfile registers.
+ *
+ * ASSUMPTION:
+ * Nobody makes a single channel controller that appears solely as
+ * the secondary legacy port on PCI.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, negative on errno-based value on error.
+ */
+int ata_pci_init_one(struct pci_dev *pdev, struct ata_port_info **pinfo_ar,
+ unsigned int n_ports)
+
+{
+ unsigned int mask = ATA_PORT_PRIMARY | ATA_PORT_SECONDARY;
+ unsigned int legacy_mask = 0;
+ struct ata_host *host;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* legacy mode? */
+ if (!(pinfo_ar[0]->flags & ATA_FLAG_NO_LEGACY))
+ legacy_mask = ata_pci_legacy_mask(pdev);
+
+ if (legacy_mask) {
+ /* XXX: all legacy or all native for the time being */
+ BUG_ON(n_ports < 2);
+ legacy_mask |= ATA_PORT_PRIMARY | ATA_PORT_SECONDARY;
+ } else {
+ /* FIXME... */
+ if (n_ports > 2)
+ printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+ if (n_ports < 2)
+ mask &= ~ATA_PORT_SECONDARY;
+ }
+
+ /* prep */
+ rc = ata_pci_host_prepare(pdev, pinfo_ar, mask, legacy_mask, &host);
+ if (rc)
+ return rc;
+
+ /* attach */
+ rc = ata_host_attach(host);
+ if (rc)
+ ata_pci_host_destroy(host);
+
+ return rc;
+}
+
EXPORT_SYMBOL_GPL(ata_pci_legacy_mask);
EXPORT_SYMBOL_GPL(ata_pci_set_dma_mask);
EXPORT_SYMBOL_GPL(ata_pci_acquire_resources);
@@ -439,4 +628,6 @@ EXPORT_SYMBOL_GPL(ata_pci_request_irq);
EXPORT_SYMBOL_GPL(ata_pci_free_irq);
EXPORT_SYMBOL_GPL(ata_pci_request_msix_irqs);
EXPORT_SYMBOL_GPL(ata_pci_free_msix_irqs);
+EXPORT_SYMBOL_GPL(ata_pci_host_prepare);
EXPORT_SYMBOL_GPL(ata_pci_host_destroy);
+EXPORT_SYMBOL_GPL(ata_pci_init_one);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f25fc53..3705d09 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -728,6 +728,10 @@ extern int ata_pci_request_msix_irqs(str
struct ata_msix_entry *ata_msix_tbl, int nr_irqs,
const char **p_reason);
extern void ata_pci_free_msix_irqs(struct ata_host *host);
+extern int ata_pci_host_prepare(struct pci_dev *pdev,
+ struct ata_port_info **pinfo_ar,
+ unsigned int mask, unsigned int legacy_mask,
+ struct ata_host **r_host);
extern void ata_pci_host_destroy(struct ata_host *host);
extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports);
--
1.4.1.1
next prev parent reply other threads:[~2006-08-19 9:27 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-19 8:57 [PATCHSET] libata: implement new initialization model w/ iomap support, take 2 Tejun Heo
2006-08-19 8:59 ` [PATCH 1/20] libata: kill ata_host_stop() Tejun Heo
2006-08-19 14:51 ` Jeff Garzik
2006-08-19 15:29 ` Tejun Heo
2006-09-19 4:46 ` Jeff Garzik
2006-09-19 4:50 ` Tejun Heo
2006-08-19 8:59 ` [PATCH 2/20] libata: implement ata_host_start/stop() Tejun Heo
2006-08-19 8:59 ` [PATCH 5/20] libata: implement several LLD init helpers Tejun Heo
2006-08-22 22:11 ` Brian King
2006-08-27 9:52 ` Tejun Heo
2006-08-30 21:16 ` Brian King
2006-09-19 5:16 ` Jeff Garzik
2006-09-19 5:57 ` Tejun Heo
2006-08-19 8:59 ` [PATCH 3/20] libata: implement ata_host_detach() and ata_host_free() Tejun Heo
2006-09-19 4:59 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 6/20] libata: implement legacy ATA init helpers Tejun Heo
2006-09-19 5:26 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 4/20] libata: separate out ata_host_alloc() and ata_host_attach() Tejun Heo
2006-09-19 5:08 ` Jeff Garzik
2006-09-19 5:48 ` Tejun Heo
2006-08-19 8:59 ` [PATCH 7/20] libata: implement PCI ATA init helpers Tejun Heo
2006-09-19 5:29 ` Jeff Garzik
2006-08-19 8:59 ` Tejun Heo [this message]
2006-09-19 5:32 ` [PATCH 8/20] libata: reimplement ata_pci_init_one() using new " Jeff Garzik
2006-09-19 6:04 ` Tejun Heo
2006-09-19 6:09 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 10/20] libata: reimplement ata_pci_remove_one() using new PCI " Tejun Heo
2006-08-19 8:59 ` [PATCH 12/20] libata: kill old " Tejun Heo
2006-08-19 8:59 ` [PATCH 13/20] libata: kill unused ->host_stop() operation and related functions Tejun Heo
2006-09-19 5:42 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 11/20] libata: use remove_one() for deinit instead of ->host_stop() Tejun Heo
2006-09-19 5:42 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 17/20] libata: make ata_pci_acquire_resources() handle iomap Tejun Heo
2006-09-19 5:47 ` Jeff Garzik
2006-09-19 6:27 ` Tejun Heo
2006-09-19 6:32 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 14/20] libata: use LLD name where possible Tejun Heo
2006-09-19 5:43 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 19/20] libata: kill unused ATA_FLAG_MMIO Tejun Heo
2006-08-19 8:59 ` [PATCH 16/20] libata: make ata_host_alloc() take care of hpriv alloc/free Tejun Heo
2006-09-19 5:45 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 15/20] libata: move ->irq_handler from port_ops to port_info Tejun Heo
2006-09-19 5:43 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 20/20] libata: move scattered PCI ATA functions into liata-pci.c Tejun Heo
2006-09-19 5:50 ` Jeff Garzik
2006-08-22 22:10 ` [PATCHSET] libata: implement new initialization model w/ iomap support, take 2 Brian King
2006-08-27 10:12 ` Tejun Heo
2006-08-30 20:58 ` Brian King
2006-09-01 13:45 ` Tejun Heo
2006-09-07 13:22 ` Brian King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11559779723326-git-send-email-htejun@gmail.com \
--to=htejun@gmail.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=albertcc@tw.ibm.com \
--cc=brking@us.ibm.com \
--cc=forrest.zhao@intel.com \
--cc=jgarzik@pobox.com \
--cc=linux-ide@vger.kernel.org \
--cc=mlord@pobox.com \
--cc=uchang@tw.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.