linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 4/6] sata_nv: better irq handlers
Date: Sat, 17 Jun 2006 15:49:56 +0900	[thread overview]
Message-ID: <115052699637-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11505269953650-git-send-email-htejun@gmail.com>

nf2/3 and ck804 have irq status register.  Implement better irq
handler for those flavors of nv.  This patch makes different flavors
of nv controllers use different irq handlers by using separate
port_info for each flavor.

This change also makes following EH and hotplug updates easier to
integrate.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/sata_nv.c |  211 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 194 insertions(+), 17 deletions(-)

7472c9c3ac075355e09ec44776040d633d7338df
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 1cb7b44..94cb179 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -78,8 +78,13 @@ enum {
 };
 
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t nv_interrupt (int irq, void *dev_instance,
-				 struct pt_regs *regs);
+static void nv_ck804_host_stop(struct ata_host_set *host_set);
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+					struct pt_regs *regs);
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+				    struct pt_regs *regs);
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+				      struct pt_regs *regs);
 static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
@@ -154,7 +159,7 @@ static struct scsi_host_template nv_sht 
 	.bios_param		= ata_std_bios_param,
 };
 
-static const struct ata_port_operations nv_ops = {
+static const struct ata_port_operations nv_generic_ops = {
 	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -170,7 +175,7 @@ static const struct ata_port_operations 
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
 	.data_xfer		= ata_pio_data_xfer,
-	.irq_handler		= nv_interrupt,
+	.irq_handler		= nv_generic_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
@@ -179,6 +184,56 @@ static const struct ata_port_operations 
 	.host_stop		= ata_pci_host_stop,
 };
 
+static const struct ata_port_operations nv_nf2_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.data_xfer		= ata_pio_data_xfer,
+	.irq_handler		= nv_nf2_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= nv_scr_read,
+	.scr_write		= nv_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+	.host_stop		= ata_pci_host_stop,
+};
+
+static const struct ata_port_operations nv_ck804_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.data_xfer		= ata_pio_data_xfer,
+	.irq_handler		= nv_ck804_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= nv_scr_read,
+	.scr_write		= nv_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+	.host_stop		= nv_ck804_host_stop,
+};
+
 /* FIXME: The hardware provides the necessary SATA PHY controls
  * to support ATA_FLAG_SATA_RESET.  However, it is currently
  * necessary to disable that flag, to solve misdetection problems.
@@ -187,16 +242,43 @@ static const struct ata_port_operations 
  * This problem really needs to be investigated further.  But in the
  * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
  */
-static struct ata_port_info nv_port_info = {
-	.sht		= &nv_sht,
-	.host_flags	= ATA_FLAG_SATA |
-			  /* ATA_FLAG_SATA_RESET | */
-			  ATA_FLAG_SRST |
-			  ATA_FLAG_NO_LEGACY,
-	.pio_mask	= NV_PIO_MASK,
-	.mwdma_mask	= NV_MWDMA_MASK,
-	.udma_mask	= NV_UDMA_MASK,
-	.port_ops	= &nv_ops,
+static struct ata_port_info nv_port_info[] = {
+	/* generic */
+	{
+		.sht		= &nv_sht,
+		.host_flags	= ATA_FLAG_SATA |
+				  /* ATA_FLAG_SATA_RESET | */
+				  ATA_FLAG_SRST |
+				  ATA_FLAG_NO_LEGACY,
+		.pio_mask	= NV_PIO_MASK,
+		.mwdma_mask	= NV_MWDMA_MASK,
+		.udma_mask	= NV_UDMA_MASK,
+		.port_ops	= &nv_generic_ops,
+	},
+	/* nforce2/3 */
+	{
+		.sht		= &nv_sht,
+		.host_flags	= ATA_FLAG_SATA |
+				  /* ATA_FLAG_SATA_RESET | */
+				  ATA_FLAG_SRST |
+				  ATA_FLAG_NO_LEGACY,
+		.pio_mask	= NV_PIO_MASK,
+		.mwdma_mask	= NV_MWDMA_MASK,
+		.udma_mask	= NV_UDMA_MASK,
+		.port_ops	= &nv_nf2_ops,
+	},
+	/* ck804 */
+	{
+		.sht		= &nv_sht,
+		.host_flags	= ATA_FLAG_SATA |
+				  /* ATA_FLAG_SATA_RESET | */
+				  ATA_FLAG_SRST |
+				  ATA_FLAG_NO_LEGACY,
+		.pio_mask	= NV_PIO_MASK,
+		.mwdma_mask	= NV_MWDMA_MASK,
+		.udma_mask	= NV_UDMA_MASK,
+		.port_ops	= &nv_ck804_ops,
+	},
 };
 
 MODULE_AUTHOR("NVIDIA");
@@ -205,8 +287,8 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static irqreturn_t nv_interrupt (int irq, void *dev_instance,
-				 struct pt_regs *regs)
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+					struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
 	unsigned int i;
@@ -239,6 +321,79 @@ static irqreturn_t nv_interrupt (int irq
 	return IRQ_RETVAL(handled);
 }
 
+static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
+{
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	int handled;
+
+	/* bail out if not our interrupt */
+	if (!(irq_stat & NV_INT_DEV))
+		return 0;
+
+	/* DEV interrupt w/ no active qc? */
+	if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+		ata_check_status(ap);
+		return 1;
+	}
+
+	/* handle interrupt */
+	handled = ata_host_intr(ap, qc);
+	if (unlikely(!handled)) {
+		/* spurious, clear it */
+		ata_check_status(ap);
+	}
+
+	return 1;
+}
+
+static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
+{
+	int i, handled = 0;
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap = host_set->ports[i];
+
+		if (ap && !(ap->flags & ATA_FLAG_DISABLED))
+			handled += nv_host_intr(ap, irq_stat);
+
+		irq_stat >>= NV_INT_PORT_SHIFT;
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+				    struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned long flags;
+	u8 irq_stat;
+	irqreturn_t ret;
+
+	spin_lock_irqsave(&host_set->lock, flags);
+	irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+	ret = nv_do_interrupt(host_set, irq_stat);
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return ret;
+}
+
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+				      struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned long flags;
+	u8 irq_stat;
+	irqreturn_t ret;
+
+	spin_lock_irqsave(&host_set->lock, flags);
+	irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
+	ret = nv_do_interrupt(host_set, irq_stat);
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return ret;
+}
+
 static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
 	if (sc_reg > SCR_CONTROL)
@@ -294,7 +449,7 @@ static int nv_init_one (struct pci_dev *
 
 	rc = -ENOMEM;
 
-	ppi = &nv_port_info;
+	ppi = &nv_port_info[ent->driver_data];
 	probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 	if (!probe_ent)
 		goto err_out_regions;
@@ -310,6 +465,15 @@ static int nv_init_one (struct pci_dev *
 	probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
 	probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
 
+	/* enable SATA space for CK804 */
+	if (ent->driver_data == CK804) {
+		u8 regval;
+
+		pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+		regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+		pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+	}
+
 	pci_set_master(pdev);
 
 	rc = ata_device_add(probe_ent);
@@ -333,6 +497,19 @@ err_out:
 	return rc;
 }
 
+static void nv_ck804_host_stop(struct ata_host_set *host_set)
+{
+	struct pci_dev *pdev = to_pci_dev(host_set->dev);
+	u8 regval;
+
+	/* disable SATA space for CK804 */
+	pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+	regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+	pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+
+	ata_pci_host_stop(host_set);
+}
+
 static int __init nv_init(void)
 {
 	return pci_module_init(&nv_pci_driver);
-- 
1.3.2



      parent reply	other threads:[~2006-06-17  6:50 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-17  6:49 [PATCHSET] sata_nv: convert to new EH and add hotplug support, take 2 Tejun Heo
2006-06-17  6:49 ` [PATCH 1/6] sata_nv: kill not-working hotplug code Tejun Heo
2006-06-20  9:09   ` Jeff Garzik
2006-06-20  9:14     ` Tejun Heo
2006-06-17  6:49 ` [PATCH 2/6] sata_nv: kill struct nv_host_desc and nv_host Tejun Heo
2006-06-17  6:49 ` [PATCH 3/6] sata_nv: simplify constants Tejun Heo
2006-06-17  6:49 ` [PATCH 5/6] sata_nv: convert to new EH Tejun Heo
2006-06-17  6:49 ` [PATCH 6/6] sata_nv: add hotplug support Tejun Heo
2006-06-17  6:49 ` Tejun Heo [this message]

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=115052699637-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).