All of lore.kernel.org
 help / color / mirror / Atom feed
From: Albert Lee <albertcc@tw.ibm.com>
To: Jeff Garzik <jgarzik@pobox.com>
Cc: Erik Mouw <erik@harddisk-recovery.com>,
	Alan Cox <alan@lxorguk.ukuu.org.uk>,
	linux-ide@vger.kernel.org, rene.herman@keyaccess.nl,
	Unicorn Chang <uchang@tw.ibm.com>, Doug Maxey <dwm@maxeymade.com>,
	Tejun Heo <htejun@gmail.com>
Subject: [PATCH/RFC 1/2] libata: make both legacy ports share one host_set
Date: Fri, 26 May 2006 14:28:57 +0800	[thread overview]
Message-ID: <4476A029.8060303@tw.ibm.com> (raw)
In-Reply-To: <4476991E.5060506@tw.ibm.com>

Patch 1/2: 
- make both legacy ports share one host_set
- use signed irq (-1) if variable not used
- host_set->irq is preserved for shared irq case(PCI native mode).
- ap->ioaddr.irq is added for per-port non-shared irq case(legacy mode).
- ATA_FLAG_LEGACY added to flag the legacy ports

Signed-off-by: Unicorn Chang <uchang@tw.ibm.com>
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
---
The host_set is shared between the 2 legacy ports
for the ATA_HOST_SIMPLEX to work.
The per-port irq is also freed for the pata_amd unloading to load.
Briefly tested on x86 box.

For your review, thanks.

--- upstream0/include/linux/libata.h	2006-05-25 10:45:36.000000000 +0800
+++ 1_legacy_irq/include/linux/libata.h	2006-05-26 09:19:40.000000000 +0800
@@ -149,8 +149,9 @@ enum {
 	ATA_FLAG_NO_ATAPI	= (1 << 6), /* No ATAPI support */
 	ATA_FLAG_PIO_DMA	= (1 << 7), /* PIO cmds via DMA */
 	ATA_FLAG_PIO_LBA48	= (1 << 8), /* Host DMA engine is LBA28 only */
-	ATA_FLAG_PIO_POLLING	= (1 << 10), /* use polling PIO if LLD
+	ATA_FLAG_PIO_POLLING	= (1 << 9), /* use polling PIO if LLD
 					      * doesn't handle PIO interrupts */
+	ATA_FLAG_LEGACY		= (1 << 10), /* port is legacy */
 	ATA_FLAG_NCQ		= (1 << 11), /* host supports NCQ */
 
 	ATA_FLAG_DEBUGMSG	= (1 << 14),
@@ -301,6 +302,7 @@ struct ata_ioports {
 	unsigned long		ctl_addr;
 	unsigned long		bmdma_addr;
 	unsigned long		scr_addr;
+	long			irq;
 };
 
 struct ata_probe_ent {
@@ -310,12 +312,11 @@ struct ata_probe_ent {
 	struct scsi_host_template *sht;
 	struct ata_ioports	port[ATA_MAX_PORTS];
 	unsigned int		n_ports;
-	unsigned int		hard_port_no;
 	unsigned int		pio_mask;
 	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		legacy_mode;
-	unsigned long		irq;
+	long			irq;
 	unsigned int		irq_flags;
 	unsigned long		host_flags;
 	unsigned long		host_set_flags;
@@ -326,7 +327,7 @@ struct ata_probe_ent {
 struct ata_host_set {
 	spinlock_t		lock;
 	struct device 		*dev;
-	unsigned long		irq;
+	long			irq;
 	void __iomem		*mmio_base;
 	unsigned int		n_ports;
 	void			*private_data;
--- upstream0/drivers/scsi/libata-core.c	2006-05-25 10:45:21.000000000 +0800
+++ 1_legacy_irq/drivers/scsi/libata-core.c	2006-05-26 09:19:40.000000000 +0800
@@ -4776,11 +4776,36 @@ irqreturn_t ata_interrupt (int irq, void
 	/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
 	spin_lock_irqsave(&host_set->lock, flags);
 
+	if (irq != host_set->irq) {
+		/* per-port irq */
+		for (i = 0; i < host_set->n_ports; i++) {
+			struct ata_port *ap = host_set->ports[i];
+
+			if (ap && (ap->flags & ATA_FLAG_LEGACY) &&
+			    (ap->ioaddr.irq == irq) &&
+			    !(ap->flags & ATA_FLAG_DISABLED)) {
+				struct ata_queued_cmd *qc;
+
+				qc = ata_qc_from_tag(ap, ap->active_tag);
+				if (qc &&
+				    (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+				    (qc->flags & ATA_QCFLAG_ACTIVE))
+					handled |= ata_host_intr(ap, qc);
+				break;
+			}
+		}
+
+		spin_unlock_irqrestore(&host_set->lock, flags);
+
+		return IRQ_RETVAL(handled);
+	}
+
+	/* shared irq */
 	for (i = 0; i < host_set->n_ports; i++) {
 		struct ata_port *ap;
 
 		ap = host_set->ports[i];
-		if (ap &&
+		if (ap && !(ap->flags & ATA_FLAG_LEGACY) &&
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
@@ -5148,8 +5173,7 @@ static void ata_host_init(struct ata_por
 	ap->host_set = host_set;
 	ap->dev = ent->dev;
 	ap->port_no = port_no;
-	ap->hard_port_no =
-		ent->legacy_mode ? ent->hard_port_no : port_no;
+	ap->hard_port_no = port_no;
 	ap->pio_mask = ent->pio_mask;
 	ap->mwdma_mask = ent->mwdma_mask;
 	ap->udma_mask = ent->udma_mask;
@@ -5282,6 +5306,7 @@ int ata_device_add(const struct ata_prob
 	for (i = 0; i < ent->n_ports; i++) {
 		struct ata_port *ap;
 		unsigned long xfer_mode_mask;
+		unsigned long irq;
 
 		ap = ata_host_add(ent, host_set, i);
 		if (!ap)
@@ -5292,6 +5317,12 @@ int ata_device_add(const struct ata_prob
 				(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
 				(ap->pio_mask << ATA_SHIFT_PIO);
 
+		if (ent->legacy_mode) {
+			irq = ap->ioaddr.irq;
+			ap->flags |= ATA_FLAG_LEGACY;
+		} else
+			irq = ent->irq;
+
 		/* print per-port info to dmesg */
 		ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
 				"ctl 0x%lX bmdma 0x%lX irq %lu\n",
@@ -5300,21 +5331,28 @@ int ata_device_add(const struct ata_prob
 				ap->ioaddr.cmd_addr,
 				ap->ioaddr.ctl_addr,
 				ap->ioaddr.bmdma_addr,
-				ent->irq);
+				irq);
 
 		ata_chk_status(ap);
 		host_set->ops->irq_clear(ap);
 		ata_eh_freeze_port(ap);	/* freeze port before requesting IRQ */
+
+		if (ap->flags & ATA_FLAG_LEGACY)
+			/* obtain legacy per-port irq */
+			if (request_irq(irq, ent->port_ops->irq_handler, 0,
+				DRV_NAME, host_set))
+				goto err_out;
 		count++;
 	}
 
 	if (!count)
 		goto err_free_ret;
 
-	/* obtain irq, that is shared between channels */
-	if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
-			DRV_NAME, host_set))
-		goto err_out;
+	if (!ent->legacy_mode)
+		/* obtain irq, that is shared between channels */
+		if (request_irq(ent->irq, ent->port_ops->irq_handler,
+				ent->irq_flags, DRV_NAME, host_set))
+			goto err_out;
 
 	/* perform each probe synchronously */
 	DPRINTK("probe begin\n");
@@ -5387,31 +5425,35 @@ void ata_host_set_remove(struct ata_host
 {
 	struct ata_port *ap;
 	unsigned int i;
+	int native = 0;
 
 	for (i = 0; i < host_set->n_ports; i++) {
 		ap = host_set->ports[i];
 		scsi_remove_host(ap->host);
 	}
 
-	free_irq(host_set->irq, host_set);
-
 	for (i = 0; i < host_set->n_ports; i++) {
 		ap = host_set->ports[i];
 
 		ata_scsi_release(ap->host);
 
-		if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+		if (ap->flags & ATA_FLAG_LEGACY) {
 			struct ata_ioports *ioaddr = &ap->ioaddr;
 
-			if (ioaddr->cmd_addr == 0x1f0)
-				release_region(0x1f0, 8);
-			else if (ioaddr->cmd_addr == 0x170)
-				release_region(0x170, 8);
-		}
+			WARN_ON(!(ioaddr->cmd_addr == 0x1f0 ||
+				  ioaddr->cmd_addr == 0x170));
+
+			release_region(ioaddr->cmd_addr, 8);
+			free_irq(ioaddr->irq, host_set);
+		} else
+			native++;
 
 		scsi_host_put(ap->host);
 	}
 
+	if (native)
+		free_irq(host_set->irq, host_set);
+
 	if (host_set->ops->host_stop)
 		host_set->ops->host_stop(host_set);
 
--- upstream0/drivers/scsi/libata-bmdma.c	2006-05-25 10:45:21.000000000 +0800
+++ 1_legacy_irq/drivers/scsi/libata-bmdma.c	2006-05-26 09:19:40.000000000 +0800
@@ -879,7 +879,7 @@ ata_pci_init_native_mode(struct pci_dev 
 		if (bmdma) {
 			bmdma += 8;
 			if(inb(bmdma + 2) & 0x80)
-			probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+				probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
 			probe_ent->port[p].bmdma_addr = bmdma;
 		}
 		ata_std_ports(&probe_ent->port[p]);
@@ -891,46 +891,67 @@ ata_pci_init_native_mode(struct pci_dev 
 }
 
 
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
-				struct ata_port_info *port, int port_num)
+/**
+ *	ata_pci_init_legacy_mode - Initialize legacy-mode driver
+ *	@pdev:  pci device to be initialized
+ *	@port:  array[2] of pointers to port info structures.
+ *	@ports: bitmap of ports present
+ *
+ *	Utility function which allocates and initializes an
+ *	ata_probe_ent structure for a standard dual-port
+ *	PIO-based IDE controller.  The returned ata_probe_ent
+ *	structure can be passed to ata_device_add().  The returned
+ *	ata_probe_ent structure should then be freed with kfree().
+ */
+static struct ata_probe_ent *ata_pci_init_legacy_mode(struct pci_dev *pdev,
+				struct ata_port_info **port, int ports)
 {
-	struct ata_probe_ent *probe_ent;
+	struct ata_probe_ent *probe_ent =
+		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+	int p = 0;
 	unsigned long bmdma;
 
-	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
 	if (!probe_ent)
 		return NULL;
 
 	probe_ent->legacy_mode = 1;
-	probe_ent->n_ports = 1;
-	probe_ent->hard_port_no = port_num;
-	probe_ent->private_data = port->private_data;
-
-	switch(port_num)
-	{
-		case 0:
-			probe_ent->irq = 14;
-			probe_ent->port[0].cmd_addr = 0x1f0;
-			probe_ent->port[0].altstatus_addr =
-			probe_ent->port[0].ctl_addr = 0x3f6;
-			break;
-		case 1:
-			probe_ent->irq = 15;
-			probe_ent->port[0].cmd_addr = 0x170;
-			probe_ent->port[0].altstatus_addr =
-			probe_ent->port[0].ctl_addr = 0x376;
-			break;
+	probe_ent->irq = -1;
+	probe_ent->private_data = port[0]->private_data;
+
+	if (ports & ATA_PORT_PRIMARY) {
+		probe_ent->port[p].irq = 14;
+		probe_ent->port[p].cmd_addr = 0x1f0;
+		probe_ent->port[p].altstatus_addr =
+			probe_ent->port[p].ctl_addr = 0x3f6;
+
+		bmdma = pci_resource_start(pdev, 4);
+		if (bmdma) {
+			probe_ent->port[p].bmdma_addr = bmdma;
+			if (inb(bmdma + 2) & 0x80)
+				probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+		}
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
 	}
 
-	bmdma = pci_resource_start(pdev, 4);
-	if (bmdma != 0) {
-		bmdma += 8 * port_num;
-		probe_ent->port[0].bmdma_addr = bmdma;
-		if (inb(bmdma + 2) & 0x80)
-			probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+	if (ports & ATA_PORT_SECONDARY) {
+		probe_ent->port[p].irq = 15;
+		probe_ent->port[p].cmd_addr = 0x170;
+		probe_ent->port[p].altstatus_addr =
+			probe_ent->port[p].ctl_addr = 0x376;
+
+		bmdma = pci_resource_start(pdev, 4);
+		if (bmdma) {
+			bmdma += 8;
+			probe_ent->port[p].bmdma_addr = bmdma;
+			if(inb(bmdma + 2) & 0x80)
+				probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+		}
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
 	}
-	ata_std_ports(&probe_ent->port[0]);
 
+	probe_ent->n_ports = p;
 	return probe_ent;
 }
 
@@ -959,10 +980,10 @@ static struct ata_probe_ent *ata_pci_ini
 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, *probe_ent2 = NULL;
+	struct ata_probe_ent *probe_ent = NULL;
 	struct ata_port_info *port[2];
 	u8 tmp8, mask;
-	unsigned int legacy_mode = 0;
+	int legacy_mode = 0;
 	int disable_dev_on_err = 1;
 	int rc;
 
@@ -1054,17 +1075,14 @@ int ata_pci_init_one (struct pci_dev *pd
 		goto err_out_regions;
 
 	if (legacy_mode) {
-		if (legacy_mode & (1 << 0))
-			probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
-		if (legacy_mode & (1 << 1))
-			probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+		probe_ent = ata_pci_init_legacy_mode(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 && !probe_ent2) {
+	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
@@ -1072,16 +1090,9 @@ int ata_pci_init_one (struct pci_dev *pd
 	pci_set_master(pdev);
 
 	/* FIXME: check ata_device_add return */
-	if (legacy_mode) {
-		if (legacy_mode & (1 << 0))
-			ata_device_add(probe_ent);
-		if (legacy_mode & (1 << 1))
-			ata_device_add(probe_ent2);
-	} else
-		ata_device_add(probe_ent);
+	ata_device_add(probe_ent);
 
 	kfree(probe_ent);
-	kfree(probe_ent2);
 
 	return 0;
 



  reply	other threads:[~2006-05-26  6:29 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-05-24 16:50 2.6.17-rc4 + libata-pata Oops while reloading pata_amd module Erik Mouw
2006-05-26  5:39 ` Albert Lee
2006-05-26  5:58   ` [PATCH/RFC 0/2] libata: legacy mode fixes Albert Lee
2006-05-26  6:28     ` Albert Lee [this message]
2006-05-26  6:33     ` [PATCH/RFC 2/2] libata: replace ap->hard_port_no with ap->port_no Albert Lee
2006-05-27  0:02     ` [PATCH/RFC 0/2] libata: legacy mode fixes Jeff Garzik
2006-05-30  3:36       ` Albert Lee

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=4476A029.8060303@tw.ibm.com \
    --to=albertcc@tw.ibm.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=albertl@mail.com \
    --cc=dwm@maxeymade.com \
    --cc=erik@harddisk-recovery.com \
    --cc=htejun@gmail.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    --cc=rene.herman@keyaccess.nl \
    --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.