2006-03-17 23:23:47

by Bill Rugolsky Jr.

[permalink] [raw]
Subject: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Jeff,

Here is an incomplete attempt to get the sata_nv ADMA code working.

I made another pass through my merge of the sata_nv driver to fix and
clean up a few things. I've only made the minimal changes necessary
to get it into a testable state; methinks it could do with a lot of
refactoring and cleanup, instead of all the
"if (host->...host_type == ADMA)" tests.

There are several FIXMEs from the original code.

I added an "adma" boolean flag to simplify testing the different code paths.

It boots OK with ADMA enabled on the disk attached to port 0, but under
heavy I/O it will stall for tens of seconds. Moderate I/O to ports 2 and 3
generates some timeouts:

ata3: command 0x25 timeout, stat 0x50
ata4: command 0x25 timeout, stat 0x50
ata3: command 0x25 timeout, stat 0x50
ata3: command 0x35 timeout, stat 0x50
ata3: command 0x25 timeout, stat 0x50
ata3: command 0x35 timeout, stat 0x50
ata3: command 0x35 timeout, stat 0x50
ata3: command 0x35 timeout, stat 0x50
ata3: command 0x35 timeout, stat 0x50
ata3: command 0x25 timeout, stat 0x50

I haven't yet bothered to enable debugging in the driver.

I'm currently running the merged driver with ADMA turned off; it should
have no functional changes.

Regards,

Bill Rugolsky

sata_nv.c | 1119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 1075 insertions(+), 44 deletions(-)

--


--- linux-2.6.16-rc6-git4/drivers/scsi/sata_nv.c~ 2006-03-15 17:19:18.000000000 -0500
+++ linux-2.6.16-rc6-git4/drivers/scsi/sata_nv.c 2006-03-17 18:13:17.000000000 -0500
@@ -29,6 +29,10 @@
* NV-specific details such as register offsets, SATA phy location,
* hotplug info, etc.
*
+ * 0.11-alpha
+ * - Added support for ADMA. Disabled by default. Use the module
+ * option adma=1 to enable it for supported chipsets.
+ *
* 0.10
* - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
* drive. Also made the check_hotplug() callbacks return whether there
@@ -68,11 +72,14 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
+#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>

+//#define DEBUG
+
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.11-alpha"

#define NV_PORTS 2
#define NV_PIO_MASK 0x1f
@@ -121,6 +128,140 @@
// For PCI config register 20
#define NV_MCP_SATA_CFG_20 0x50
#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN 0x04
+#define NV_MCP_SATA_CFG_20_PORT0_EN (1 << 17)
+#define NV_MCP_SATA_CFG_20_PORT1_EN (1 << 16)
+#define NV_MCP_SATA_CFG_20_PORT0_PWB_EN (1 << 14)
+#define NV_MCP_SATA_CFG_20_PORT1_PWB_EN (1 << 12)
+
+//#define NV_ADMA_NCQ
+
+#ifdef NV_ADMA_NCQ
+#define NV_ADMA_CAN_QUEUE ATA_MAX_QUEUE
+#else
+#define NV_ADMA_CAN_QUEUE ATA_DEF_QUEUE
+#endif
+
+#define NV_ADMA_CPB_SZ 128
+#define NV_ADMA_APRD_SZ 16
+#define NV_ADMA_SGTBL_LEN (1024 - NV_ADMA_CPB_SZ) / NV_ADMA_APRD_SZ
+#define NV_ADMA_SGTBL_SZ NV_ADMA_SGTBL_LEN * NV_ADMA_APRD_SZ
+#define NV_ADMA_PORT_PRIV_DMA_SZ NV_ADMA_CAN_QUEUE * (NV_ADMA_CPB_SZ + NV_ADMA_SGTBL_SZ)
+//#define NV_ADMA_MAX_CPBS 32
+
+// BAR5 offset to ADMA general registers
+#define NV_ADMA_GEN 0x400
+#define NV_ADMA_GEN_CTL 0x00
+#define NV_ADMA_NOTIFIER_CLEAR 0x30
+
+#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
+
+// BAR5 offset to ADMA ports
+#define NV_ADMA_PORT 0x480
+
+// size of ADMA port register space
+#define NV_ADMA_PORT_SIZE 0x100
+
+// ADMA port registers
+#define NV_ADMA_CTL 0x40
+#define NV_ADMA_CPB_COUNT 0x42
+#define NV_ADMA_NEXT_CPB_IDX 0x43
+#define NV_ADMA_STAT 0x44
+#define NV_ADMA_CPB_BASE_LOW 0x48
+#define NV_ADMA_CPB_BASE_HIGH 0x4C
+#define NV_ADMA_APPEND 0x50
+#define NV_ADMA_NOTIFIER 0x68
+#define NV_ADMA_NOTIFIER_ERROR 0x6C
+
+// NV_ADMA_CTL register bits
+#define NV_ADMA_CTL_HOTPLUG_IEN (1 << 0)
+#define NV_ADMA_CTL_CHANNEL_RESET (1 << 5)
+#define NV_ADMA_CTL_GO (1 << 7)
+#define NV_ADMA_CTL_AIEN (1 << 8)
+#define NV_ADMA_CTL_READ_NON_COHERENT (2 << 11)
+#define NV_ADMA_CTL_WRITE_NON_COHERENT (1 << 12)
+
+// CPB response flag bits
+#define NV_CPB_RESP_DONE (1 << 0)
+#define NV_CPB_RESP_ATA_ERR (1 << 3)
+#define NV_CPB_RESP_CMD_ERR (1 << 4)
+#define NV_CPB_RESP_CPB_ERR (1 << 7)
+
+// CPB control flag bits
+#define NV_CPB_CTL_CPB_VALID (1 << 0)
+#define NV_CPB_CTL_QUEUE (1 << 1)
+#define NV_CPB_CTL_APRD_VALID (1 << 2)
+#define NV_CPB_CTL_IEN (1 << 3)
+#define NV_CPB_CTL_FPDMA (1 << 4)
+
+// APRD flags
+#define NV_APRD_WRITE (1 << 1)
+#define NV_APRD_END (1 << 2)
+#define NV_APRD_CONT (1 << 3)
+
+// NV_ADMA_STAT flags
+#define NV_ADMA_STAT_TIMEOUT (1 << 0)
+#define NV_ADMA_STAT_HOTUNPLUG (1 << 1)
+#define NV_ADMA_STAT_HOTPLUG (1 << 2)
+#define NV_ADMA_STAT_CPBERR (1 << 4)
+#define NV_ADMA_STAT_SERROR (1 << 5)
+#define NV_ADMA_STAT_CMD_COMPLETE (1 << 6)
+#define NV_ADMA_STAT_IDLE (1 << 8)
+#define NV_ADMA_STAT_LEGACY (1 << 9)
+#define NV_ADMA_STAT_STOPPED (1 << 10)
+#define NV_ADMA_STAT_DONE (1 << 12)
+#define NV_ADMA_STAT_ERR (NV_ADMA_STAT_CPBERR | NV_ADMA_STAT_TIMEOUT)
+
+// port flags
+#define NV_ADMA_PORT_REGISTER_MODE (1 << 0)
+
+#ifndef min
+#define min(x,y) ((x) < (y) ? x : y)
+#endif
+
+struct nv_adma_prd {
+ u64 addr;
+ u32 len;
+ u8 flags;
+ u8 packet_len;
+ u16 reserved;
+};
+
+enum nv_adma_regbits {
+ CMDEND = (1 << 15), /* end of command list */
+ WNB = (1 << 14), /* wait-not-BSY */
+ IGN = (1 << 13), /* ignore this entry */
+ CS1n = (1 << (4 + 8)), /* std. PATA signals follow... */
+ DA2 = (1 << (2 + 8)),
+ DA1 = (1 << (1 + 8)),
+ DA0 = (1 << (0 + 8)),
+};
+
+struct nv_adma_cpb {
+ u8 resp_flags; //0
+ u8 reserved1; //1
+ u8 ctl_flags; //2
+ // len is length of taskfile in 64 bit words
+ u8 len; //3
+ u8 tag; //4
+ u8 next_cpb_idx; //5
+ u16 reserved2; //6-7
+ u16 tf[12]; //8-31
+ struct nv_adma_prd aprd[5]; //32-111
+ u64 next_aprd; //112-119
+ u64 reserved3; //120-127
+};
+
+
+struct nv_adma_port_priv {
+ struct nv_adma_cpb *cpb;
+ // u8 cpb_idx;
+ u8 flags;
+ u32 notifier;
+ u32 notifier_error;
+ dma_addr_t cpb_dma;
+ struct nv_adma_prd *aprd;
+ dma_addr_t aprd_dma;
+};

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,
@@ -128,36 +269,70 @@ static irqreturn_t nv_interrupt (int irq
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);
static void nv_host_stop (struct ata_host_set *host_set);
+static int nv_port_start(struct ata_port *ap);
+static void nv_port_stop(struct ata_port *ap);
+static int nv_adma_port_start(struct ata_port *ap);
+static void nv_adma_port_stop(struct ata_port *ap);
+static void nv_irq_clear(struct ata_port *ap);
+static void nv_adma_irq_clear(struct ata_port *ap);
static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug(struct ata_host_set *host_set);
static int nv_check_hotplug(struct ata_host_set *host_set);
static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
+static void nv_enable_hotplug_adma(struct ata_probe_ent *probe_ent);
+static void nv_disable_hotplug_adma(struct ata_host_set *host_set);
+static int nv_check_hotplug_adma(struct ata_host_set *host_set);
+static void nv_qc_prep(struct ata_queued_cmd *qc);
+static int nv_qc_issue(struct ata_queued_cmd *qc);
+static int nv_adma_qc_issue(struct ata_queued_cmd *qc);
+static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
+static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb);
+static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb);
+static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, struct scatterlist *sg, int idx, struct nv_adma_prd *aprd);
+static void nv_adma_register_mode(struct ata_port *ap);
+static void nv_adma_mode(struct ata_port *ap);
+static u8 nv_bmdma_status(struct ata_port *ap);
+static u8 nv_adma_bmdma_status(struct ata_port *ap);
+static void nv_bmdma_stop(struct ata_queued_cmd *qc);
+static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc);
+static void nv_eng_timeout(struct ata_port *ap);
+static void nv_adma_eng_timeout(struct ata_port *ap);
+#ifdef DEBUG
+static void nv_adma_dump_cpb(struct nv_adma_cpb *cpb);
+static void nv_adma_dump_aprd(struct nv_adma_prd *aprd);
+static void nv_adma_dump_cpb_tf(u16 tf);
+static void nv_adma_dump_port(struct ata_port *ap);
+static void nv_adma_dump_iomem(void __iomem *m, int len);
+#endif
+
+
+static int adma_enabled;

enum nv_host_type
{
- GENERIC,
- NFORCE2,
- NFORCE3,
- CK804
+ GENERIC = 0x0,
+ NFORCE = 0x1,
+ CK804 = 0x2,
+ ADMA = 0x4
};

static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
@@ -193,13 +368,7 @@ static struct nv_host_desc nv_device_tbl
.check_hotplug = NULL,
},
{
- .host_type = NFORCE2,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
- {
- .host_type = NFORCE3,
+ .host_type = NFORCE,
.enable_hotplug = nv_enable_hotplug,
.disable_hotplug= nv_disable_hotplug,
.check_hotplug = nv_check_hotplug,
@@ -209,6 +378,11 @@ static struct nv_host_desc nv_device_tbl
.disable_hotplug= nv_disable_hotplug_ck804,
.check_hotplug = nv_check_hotplug_ck804,
},
+ { .host_type = ADMA,
+ .enable_hotplug = nv_enable_hotplug_adma,
+ .disable_hotplug= nv_disable_hotplug_adma,
+ .check_hotplug = nv_check_hotplug_adma,
+ },
};

struct nv_host
@@ -253,20 +427,187 @@ static const struct ata_port_operations
.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,
+ .bmdma_stop = nv_bmdma_stop,
+ .bmdma_status = nv_bmdma_status,
+ .qc_prep = nv_qc_prep,
+ .qc_issue = nv_qc_issue,
+ .eng_timeout = nv_eng_timeout,
.irq_handler = nv_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
+ .irq_clear = nv_irq_clear,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
+ .port_start = nv_port_start,
+ .port_stop = nv_port_stop,
.host_stop = nv_host_stop,
};

+static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb)
+{
+ unsigned int idx = 0;
+
+ cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB);
+
+ if ((tf->flags & ATA_TFLAG_LBA48) == 0) {
+ cpb[idx++] = cpu_to_le16(IGN);
+ cpb[idx++] = cpu_to_le16(IGN);
+ cpb[idx++] = cpu_to_le16(IGN);
+ cpb[idx++] = cpu_to_le16(IGN);
+ cpb[idx++] = cpu_to_le16(IGN);
+ }
+ else {
+ cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature);
+ cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah);
+ }
+ cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature);
+ cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah);
+
+ cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND);
+
+ return idx;
+}
+
+static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio,
+ unsigned int port_no)
+{
+ mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE;
+ return mmio;
+}
+
+static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap)
+{
+ return __nv_adma_ctl_block(ap->host_set->mmio_base, ap->port_no);
+}
+
+static inline void __iomem *nv_adma_gen_block(struct ata_port *ap)
+{
+ return (ap->host_set->mmio_base + NV_ADMA_GEN);
+}
+
+static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap)
+{
+ return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no));
+}
+
+static inline void nv_adma_reset_channel(struct ata_port *ap)
+{
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ u16 tmp;
+
+ // clear CPB fetch count
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
+
+ // clear GO
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+ udelay(1);
+ writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+}
+
+static inline int nv_adma_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
+ u16 status;
+ u32 gen_ctl;
+ u16 flags;
+ int have_err = 0;
+ int handled = 0;
+
+ status = readw(mmio + NV_ADMA_STAT);
+
+ // if in ATA register mode, use standard ata interrupt handler
+ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
+ VPRINTK("in ATA register mode\n");
+ return ata_host_intr(ap, qc);
+ }
+
+ gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
+ if (!NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no)) {
+ return 0;
+ }
+
+ if (!pp->notifier && !pp->notifier_error) {
+ if (status) {
+ VPRINTK("XXX no notifier, but status 0x%x\n", status);
+#ifdef DEBUG
+ nv_adma_dump_port(ap);
+ nv_adma_dump_cpb(cpb);
+#endif
+ } else {
+ return 0;
+ }
+ }
+ if (pp->notifier_error) {
+ have_err = 1;
+ handled = 1;
+ }
+
+ if (status & NV_ADMA_STAT_TIMEOUT) {
+ VPRINTK("timeout, stat = 0x%x\n", status);
+ have_err = 1;
+ handled = 1;
+ }
+ if (status & NV_ADMA_STAT_CPBERR) {
+ VPRINTK("CPB error, stat = 0x%x\n", status);
+ have_err = 1;
+ handled = 1;
+ }
+ if (status & NV_ADMA_STAT_STOPPED) {
+ VPRINTK("ADMA stopped, stat = 0x%x, resp_flags = 0x%x\n", status, cpb->resp_flags);
+ if (!(status & NV_ADMA_STAT_DONE)) {
+ have_err = 1;
+ handled = 1;
+ }
+ }
+ if (status & NV_ADMA_STAT_CMD_COMPLETE) {
+ VPRINTK("ADMA command complete, stat = 0x%x\n", status);
+ }
+ if (status & NV_ADMA_STAT_DONE) {
+ flags = cpb->resp_flags;
+ VPRINTK("CPB done, stat = 0x%x, flags = 0x%x\n", status, flags);
+ handled = 1;
+ if (!(status & NV_ADMA_STAT_IDLE)) {
+ VPRINTK("XXX CPB done, but not idle\n");
+ }
+ if (flags & NV_CPB_RESP_DONE) {
+ VPRINTK("CPB flags done, flags = 0x%x\n", flags);
+ }
+ if (flags & NV_CPB_RESP_ATA_ERR) {
+ VPRINTK("CPB flags ATA err, flags = 0x%x\n", flags);
+ have_err = 1;
+ }
+ if (flags & NV_CPB_RESP_CMD_ERR) {
+ VPRINTK("CPB flags CMD err, flags = 0x%x\n", flags);
+ have_err = 1;
+ }
+ if (flags & NV_CPB_RESP_CPB_ERR) {
+ VPRINTK("CPB flags CPB err, flags = 0x%x\n", flags);
+ have_err = 1;
+ }
+ }
+
+ // clear status
+ writew(status, mmio + NV_ADMA_STAT);
+
+ if (handled) {
+ u8 ata_status = readb(mmio + (ATA_REG_STATUS * 4));
+ qc->err_mask |= ac_err_mask(have_err ? (ata_status | ATA_ERR) : ata_status);
+ ata_qc_complete(qc);
+ }
+
+ return handled; /* irq handled */
+}
+
/* 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.
@@ -275,6 +616,7 @@ 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 |
@@ -293,6 +635,80 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);

+static inline void nv_enable_adma_space (struct pci_dev *pdev)
+{
+ u8 regval;
+
+ VPRINTK("ENTER\n");
+
+ 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);
+}
+
+static inline void nv_disable_adma_space (struct pci_dev *pdev)
+{
+ u8 regval;
+
+ VPRINTK("ENTER\n");
+
+ 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);
+}
+
+static void nv_irq_clear(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ nv_adma_irq_clear(ap);
+ } else {
+ ata_bmdma_irq_clear(ap);
+ }
+}
+
+static void nv_adma_irq_clear(struct ata_port *ap)
+{
+ /* FIXME: TODO */
+}
+
+static u8 nv_bmdma_status(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ return nv_adma_bmdma_status(ap);
+ } else {
+ return ata_bmdma_status(ap);
+ }
+}
+
+static u8 nv_adma_bmdma_status(struct ata_port *ap)
+{
+ // FIXME: This is no different than ata_bmdma_status for PIO
+ return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static void nv_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ nv_adma_bmdma_stop(qc);
+ } else {
+ ata_bmdma_stop(qc);
+ }
+}
+
+static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ /* FIXME: TODO */
+}
+
static irqreturn_t nv_interrupt (int irq, void *dev_instance,
struct pt_regs *regs)
{
@@ -305,26 +721,48 @@ static irqreturn_t nv_interrupt (int irq
spin_lock_irqsave(&host_set->lock, flags);

for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap;
+ struct ata_port *ap = host_set->ports[i];

- ap = host_set->ports[i];
if (ap &&
!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
struct ata_queued_cmd *qc;

+ if (host->host_desc->host_type == ADMA) {
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ // read notifiers
+ pp->notifier = readl(mmio + NV_ADMA_NOTIFIER);
+ pp->notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+ }
+
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
- handled += ata_host_intr(ap, qc);
- else
+ if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (host->host_desc->host_type == ADMA)
+ handled += nv_adma_host_intr(ap, qc);
+ else
+ handled += ata_host_intr(ap, qc);
+ } else {
// No request pending? Clear interrupt status
// anyway, in case there's one pending.
ap->ops->check_status(ap);
+ }
+
}

}

if (host->host_desc->check_hotplug)
- handled += host->host_desc->check_hotplug(host_set);
+ (void) host->host_desc->check_hotplug(host_set);
+
+ // clear notifier
+ if (handled && host->host_desc->host_type == ADMA) {
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+ struct nv_adma_port_priv *pp = ap->private_data;
+ writel(pp->notifier | pp->notifier_error,
+ nv_adma_notifier_clear_block(ap));
+ }
+ }

spin_unlock_irqrestore(&host_set->lock, flags);

@@ -335,14 +773,22 @@ static u32 nv_scr_read (struct ata_port
{
struct ata_host_set *host_set = ap->host_set;
struct nv_host *host = host_set->private_data;
+ u32 val = 0;
+
+ VPRINTK("ENTER\n");
+
+ VPRINTK("reading SCR reg %d, got 0x%08x\n", sc_reg, val);

if (sc_reg > SCR_CONTROL)
return 0xffffffffU;

if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
- return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ val = readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
else
- return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+
+ VPRINTK("reading SCR reg %d, got 0x%08x\n", sc_reg, val);
+ return val;
}

static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
@@ -350,6 +796,9 @@ static void nv_scr_write (struct ata_por
struct ata_host_set *host_set = ap->host_set;
struct nv_host *host = host_set->private_data;

+ VPRINTK("ENTER\n");
+
+ VPRINTK("writing SCR reg %d with 0x%08x\n", sc_reg, val);
if (sc_reg > SCR_CONTROL)
return;

@@ -364,6 +813,8 @@ static void nv_host_stop (struct ata_hos
struct nv_host *host = host_set->private_data;
struct pci_dev *pdev = to_pci_dev(host_set->dev);

+ VPRINTK("ENTER\n");
+
// Disable hotplug event interrupts.
if (host->host_desc->disable_hotplug)
host->host_desc->disable_hotplug(host_set);
@@ -374,16 +825,218 @@ static void nv_host_stop (struct ata_hos
pci_iounmap(pdev, host_set->mmio_base);
}

+static int nv_port_start(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ return nv_adma_port_start(ap);
+ } else {
+ return ata_port_start(ap);
+ }
+}
+
+static void nv_port_stop(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ nv_adma_port_stop(ap);
+ } else {
+ ata_port_stop(ap);
+ }
+}
+
+static int nv_adma_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host_set->dev;
+ struct nv_adma_port_priv *pp;
+ int rc;
+ void *mem;
+ dma_addr_t mem_dma;
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+
+ VPRINTK("ENTER\n");
+
+ nv_adma_reset_channel(ap);
+
+#ifdef DEBUG
+ VPRINTK("after reset:\n");
+ nv_adma_dump_port(ap);
+#endif
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ memset(pp, 0, sizeof(*pp));
+
+ mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
+ &mem_dma, GFP_KERNEL);
+
+ VPRINTK("dma memory: vaddr = 0x%08x, paddr = 0x%08x\n", (u32)mem, (u32)mem_dma);
+
+ if (!mem) {
+ rc = -ENOMEM;
+ goto err_out_kfree;
+ }
+ memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ);
+
+ /*
+ * First item in chunk of DMA memory:
+ * 128-byte command parameter block (CPB)
+ * one for each command tag
+ */
+ pp->cpb = mem;
+ pp->cpb_dma = mem_dma;
+
+ VPRINTK("cpb = 0x%08x, cpb_dma = 0x%08x\n", (u32)pp->cpb, (u32)pp->cpb_dma);
+
+ writel(mem_dma, mmio + NV_ADMA_CPB_BASE_LOW);
+ writel(0, mmio + NV_ADMA_CPB_BASE_HIGH);
+
+ mem += NV_ADMA_CAN_QUEUE * NV_ADMA_CPB_SZ;
+ mem_dma += NV_ADMA_CAN_QUEUE * NV_ADMA_CPB_SZ;
+
+ /*
+ * Second item: block of ADMA_SGTBL_LEN s/g entries
+ */
+ pp->aprd = mem;
+ pp->aprd_dma = mem_dma;
+
+ VPRINTK("aprd = 0x%08x, aprd_dma = 0x%08x\n", (u32)pp->aprd, (u32)pp->aprd_dma);
+
+ ap->private_data = pp;
+
+ // clear any outstanding interrupt conditions
+ writew(0xffff, mmio + NV_ADMA_STAT);
+
+ // initialize port variables
+ // pp->cpb_idx = 0;
+ pp->flags = NV_ADMA_PORT_REGISTER_MODE;
+
+ // make sure controller is in ATA register mode
+ nv_adma_register_mode(ap);
+
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+static void nv_adma_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host_set->dev;
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+
+ VPRINTK("ENTER\n");
+
+ writew(0, mmio + NV_ADMA_CTL);
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma);
+ kfree(pp);
+ ata_port_stop(ap);
+}
+
+
+static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+{
+ void __iomem *mmio = probe_ent->mmio_base;
+ struct ata_ioports *ioport = &probe_ent->port[port];
+
+ VPRINTK("ENTER\n");
+
+ mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+
+ ioport->cmd_addr = (unsigned long) mmio;
+ ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4);
+ ioport->error_addr =
+ ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4);
+ ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4);
+ ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4);
+ ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4);
+ ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4);
+ ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4);
+ ioport->status_addr =
+ ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4);
+ ioport->altstatus_addr =
+ ioport->ctl_addr = (unsigned long) mmio + 0x20;
+}
+
+static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+{
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ unsigned int i;
+ u32 tmp32;
+
+ VPRINTK("ENTER\n");
+
+ probe_ent->n_ports = NV_PORTS;
+
+ nv_enable_adma_space(pdev);
+
+ // enable ADMA on the ports
+ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
+ tmp32 |= NV_MCP_SATA_CFG_20_PORT0_EN |
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN |
+ NV_MCP_SATA_CFG_20_PORT1_EN |
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN;
+
+ pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
+
+ for (i = 0; i < probe_ent->n_ports; i++)
+ nv_adma_setup_port(probe_ent, i);
+
+ for (i = 0; i < probe_ent->n_ports; i++) {
+ void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);
+ u16 tmp;
+
+ /* enable interrupt, clear reset if not already clear */
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+ }
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+
+static struct nv_host_desc *nv_find_host_desc(unsigned int host_type)
+{
+ int i;
+
+ for (i = 0 ; i < (sizeof nv_device_tbl)/(sizeof nv_device_tbl[0]); i++)
+ if (nv_device_tbl[i].host_type == host_type)
+ return &nv_device_tbl[i];
+ return NULL;
+}
+
+
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
struct nv_host *host;
struct ata_port_info *ppi;
struct ata_probe_ent *probe_ent;
+ struct nv_host_desc *host_desc;
int pci_dev_busy = 0;
int rc;
u32 bar;

+ VPRINTK("ENTER\n");
+
// Make sure this is a SATA controller by counting the number of bars
// (NVIDIA SATA controllers will always have six bars). Otherwise,
// it's an IDE controller and we ignore it.
@@ -414,6 +1067,23 @@ static int nv_init_one (struct pci_dev *
rc = -ENOMEM;

ppi = &nv_port_info;
+
+ if (adma_enabled && (ent->driver_data & ADMA))
+ host_desc = nv_find_host_desc(ADMA);
+ else
+ host_desc = nv_find_host_desc(ent->driver_data & ~ADMA);
+
+ if (host_desc->host_type == ADMA) {
+ // ADMA overrides
+ ppi->host_flags |= ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
+#ifdef NV_ADMA_NCQ
+ ppi->host_flags |= ATA_FLAG_NCQ;
+#endif
+ ppi->sht->can_queue = NV_ADMA_CAN_QUEUE;
+ ppi->sht->sg_tablesize = NV_ADMA_SGTBL_LEN;
+// ppi->port_ops->irq_handler = nv_adma_interrupt;
+ }
+
probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
goto err_out_regions;
@@ -423,7 +1093,7 @@ static int nv_init_one (struct pci_dev *
goto err_out_free_ent;

memset(host, 0, sizeof(struct nv_host));
- host->host_desc = &nv_device_tbl[ent->driver_data];
+ host->host_desc = host_desc;

probe_ent->private_data = host;

@@ -440,6 +1110,7 @@ static int nv_init_one (struct pci_dev *
}

base = (unsigned long)probe_ent->mmio_base;
+ VPRINTK("BAR5 base is at 0x%x\n", (u32)base);

probe_ent->port[0].scr_addr =
base + NV_PORT0_SCR_REG_OFFSET;
@@ -455,6 +1126,12 @@ static int nv_init_one (struct pci_dev *

pci_set_master(pdev);

+ if (host_desc->host_type == ADMA) {
+ rc = nv_adma_host_init(probe_ent);
+ if (rc)
+ goto err_out_iounmap;
+ }
+
rc = ata_device_add(probe_ent);
if (rc != NV_PORTS)
goto err_out_iounmap;
@@ -483,6 +1160,239 @@ err_out:
return rc;
}

+static void nv_eng_timeout(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ nv_adma_eng_timeout(ap);
+ } else {
+ return ata_eng_timeout(ap);
+ }
+}
+
+static void nv_adma_eng_timeout(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ u8 drv_stat;
+
+ VPRINTK("ENTER\n");
+
+ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
+ ata_eng_timeout(ap);
+ goto out;
+ }
+
+
+ if (!qc) {
+ printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+ ap->id);
+ goto out;
+ }
+
+
+// spin_lock_irqsave(&host_set->lock, flags);
+
+ qc->scsidone = scsi_finish_command;
+
+ drv_stat = ata_chk_status(ap);
+
+ printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+ ap->id, qc->tf.command, drv_stat);
+
+ // reset channel
+ nv_adma_reset_channel(ap);
+
+ /* complete taskfile transaction */
+ qc->err_mask |= ac_err_mask(drv_stat);
+ ata_qc_complete(qc);
+
+// spin_unlock_irqrestore(&host_set->lock, flags);
+
+out:
+ DPRINTK("EXIT\n");
+}
+
+static void nv_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ nv_adma_qc_prep(qc);
+ } else {
+ ata_qc_prep(qc);
+ }
+}
+
+static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
+ struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
+
+ VPRINTK("ENTER\n");
+
+ VPRINTK("qc->flags = 0x%x\n", (u32)qc->flags);
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+ ata_qc_prep(qc);
+ return;
+ }
+
+ memset(cpb, 0, sizeof(struct nv_adma_cpb));
+
+ cpb->ctl_flags = NV_CPB_CTL_CPB_VALID |
+ NV_CPB_CTL_APRD_VALID |
+ NV_CPB_CTL_IEN;
+ cpb->len = 3;
+ cpb->tag = qc->tag;
+ cpb->next_cpb_idx = 0;
+
+#ifdef NV_ADMA_NCQ
+ // turn on NCQ flags for NCQ commands
+ if (qc->flags & ATA_QCFLAG_NCQ)
+ cpb->ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;
+#endif
+
+ nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
+
+ nv_adma_fill_sg(qc, cpb);
+}
+
+static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
+{
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
+ unsigned int idx;
+ struct nv_adma_prd *aprd;
+ struct scatterlist *sg;
+
+ VPRINTK("ENTER\n");
+
+ idx = 0;
+
+ ata_for_each_sg(sg, qc) {
+ aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[idx-5];
+ nv_adma_fill_aprd(qc, sg, idx, aprd);
+ idx++;
+ }
+ if (idx > 5) {
+ cpb->next_aprd = (u64)(pp->aprd_dma + NV_ADMA_APRD_SZ * qc->tag);
+ }
+}
+
+static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
+ struct scatterlist *sg,
+ int idx,
+ struct nv_adma_prd *aprd)
+{
+ u32 sg_len, addr, flags;
+
+ memset(aprd, 0, sizeof(struct nv_adma_prd));
+
+ addr = sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ flags = 0;
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= NV_APRD_WRITE;
+ if (idx == qc->n_elem - 1) {
+ flags |= NV_APRD_END;
+ } else if (idx != 4) {
+ flags |= NV_APRD_CONT;
+ }
+
+ aprd->addr = cpu_to_le32(addr);
+ aprd->len = cpu_to_le32(sg_len); /* len in bytes */
+ aprd->flags = cpu_to_le32(flags);
+}
+
+static void nv_adma_register_mode(struct ata_port *ap)
+{
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ u16 tmp;
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+
+ pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
+}
+
+static void nv_adma_mode(struct ata_port *ap)
+{
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ u16 tmp;
+
+ if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
+ return;
+ }
+
+#if 0
+ nv_adma_reset_channel(ap);
+#endif
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+
+ pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE;
+}
+
+static int nv_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA) {
+ return nv_adma_qc_issue(qc);
+ } else {
+ return ata_qc_issue_prot(qc);
+ }
+}
+
+static int nv_adma_qc_issue(struct ata_queued_cmd *qc)
+{
+#if 0
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
+#endif
+ void __iomem *mmio = nv_adma_ctl_block(qc->ap);
+
+ VPRINTK("ENTER\n");
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+ VPRINTK("no dmamap, using ATA register mode: 0x%x\n", (u32)qc->flags);
+ // use ATA register mode
+ nv_adma_register_mode(qc->ap);
+ return ata_qc_issue_prot(qc);
+ } else {
+ nv_adma_mode(qc->ap);
+ }
+
+#if 0
+ nv_adma_dump_port(qc->ap);
+ nv_adma_dump_cpb(&pp->cpb[qc->tag]);
+ if (qc->n_elem > 5) {
+ int i;
+ for (i = 0; i < qc->n_elem - 5; i++) {
+ nv_adma_dump_aprd(&pp->aprd[i]);
+ }
+ }
+#endif
+
+ //
+ // write append register, command tag in lower 8 bits
+ // and (number of cpbs to append -1) in top 8 bits
+ //
+ mb();
+ writew(qc->tag, mmio + NV_ADMA_APPEND);
+
+ VPRINTK("EXIT\n");
+
+ return 0;
+}
+
static void nv_enable_hotplug(struct ata_probe_ent *probe_ent)
{
u8 intr_mask;
@@ -543,11 +1453,8 @@ static void nv_enable_hotplug_ck804(stru
{
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
u8 intr_mask;
- 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);
+ nv_enable_adma_space(pdev);

writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804);

@@ -561,7 +1468,6 @@ static void nv_disable_hotplug_ck804(str
{
struct pci_dev *pdev = to_pci_dev(host_set->dev);
u8 intr_mask;
- u8 regval;

intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804);

@@ -569,9 +1475,7 @@ static void nv_disable_hotplug_ck804(str

writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_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);
+ nv_disable_adma_space(pdev);
}

static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
@@ -606,6 +1510,65 @@ static int nv_check_hotplug_ck804(struct
return 0;
}

+static void nv_enable_hotplug_adma(struct ata_probe_ent *probe_ent)
+{
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ unsigned int i;
+ u16 tmp;
+
+ nv_enable_adma_space(pdev);
+
+ for (i = 0; i < probe_ent->n_ports; i++) {
+ void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);
+ writew(NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG,
+ mmio + NV_ADMA_STAT);
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
+
+ }
+}
+
+static void nv_disable_hotplug_adma(struct ata_host_set *host_set)
+{
+ unsigned int i;
+ u16 tmp;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ void __iomem *mmio = __nv_adma_ctl_block(host_set->mmio_base, i);
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp & ~NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
+
+ }
+}
+
+static int nv_check_hotplug_adma(struct ata_host_set *host_set)
+{
+ unsigned int i;
+ u16 adma_status;
+ int hotplugged = 0;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ void __iomem *mmio = __nv_adma_ctl_block(host_set->mmio_base, i);
+ adma_status = readw(mmio + NV_ADMA_STAT);
+ if (adma_status & NV_ADMA_STAT_HOTPLUG) {
+ printk(KERN_WARNING "nv_sata: "
+ "port %d device added\n", i);
+ writew(NV_ADMA_STAT_HOTPLUG, mmio + NV_ADMA_STAT);
+ hotplugged = 1;
+ }
+ if (adma_status & NV_ADMA_STAT_HOTUNPLUG) {
+ printk(KERN_WARNING "nv_sata: "
+ "port %d device removed\n", i);
+ writew(NV_ADMA_STAT_HOTUNPLUG, mmio + NV_ADMA_STAT);
+ hotplugged = 1;
+ }
+ }
+
+ return hotplugged;
+}
+
static int __init nv_init(void)
{
return pci_module_init(&nv_pci_driver);
@@ -618,3 +1581,71 @@ static void __exit nv_exit(void)

module_init(nv_init);
module_exit(nv_exit);
+module_param_named(adma, adma_enabled, bool, 0);
+MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
+
+
+#ifdef DEBUG
+static void nv_adma_dump_aprd(struct nv_adma_prd *aprd)
+{
+ printk("%016llx %08x %02x %s %s %s\n",
+ aprd->addr,
+ aprd->len,
+ aprd->flags,
+ (aprd->flags & NV_APRD_WRITE) ? "WRITE" : " ",
+ (aprd->flags & NV_APRD_END) ? "END" : " ",
+ (aprd->flags & NV_APRD_CONT) ? "CONT" : " ");
+}
+static void nv_adma_dump_iomem(void __iomem *m, int len)
+{
+ int i, j;
+
+ for (i = 0; i < len/16; i++) {
+ printk(KERN_WARNING "%02x: ", 16*i);
+ for (j = 0; j < 16; j++) {
+ printk("%02x%s", (u32)readb(m + 16*i + j),
+ (j == 7) ? "-" : " ");
+ }
+ printk("\n");
+ }
+}
+
+static void nv_adma_dump_cpb_tf(u16 tf)
+{
+ printk("0x%04x %s %s %s 0x%02x 0x%02x\n",
+ tf,
+ (tf & CMDEND) ? "END" : " ",
+ (tf & WNB) ? "WNB" : " ",
+ (tf & IGN) ? "IGN" : " ",
+ ((tf >> 8) & 0x1f),
+ (tf & 0xff));
+}
+
+static void nv_adma_dump_port(struct ata_port *ap)
+{
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ nv_adma_dump_iomem(mmio, NV_ADMA_PORT_SIZE);
+}
+
+static void nv_adma_dump_cpb(struct nv_adma_cpb *cpb)
+{
+ int i;
+
+ printk("resp_flags: 0x%02x\n", cpb->resp_flags);
+ printk("ctl_flags: 0x%02x\n", cpb->ctl_flags);
+ printk("len: 0x%02x\n", cpb->len);
+ printk("tag: 0x%02x\n", cpb->tag);
+ printk("next_cpb_idx: 0x%02x\n", cpb->next_cpb_idx);
+ printk("tf:\n");
+ for (i=0; i<12; i++) {
+ nv_adma_dump_cpb_tf(cpb->tf[i]);
+ }
+ printk("aprd:\n");
+ for (i=0; i<5; i++) {
+ nv_adma_dump_aprd(&cpb->aprd[i]);
+ }
+ printk("next_aprd: 0x%016llx\n", cpb->next_aprd);
+}
+
+#endif
+


2006-03-18 00:57:03

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Bill Rugolsky Jr. wrote:
> Jeff,
>
> Here is an incomplete attempt to get the sata_nv ADMA code working.
>
> I made another pass through my merge of the sata_nv driver to fix and
> clean up a few things. I've only made the minimal changes necessary
> to get it into a testable state; methinks it could do with a lot of
> refactoring and cleanup, instead of all the
> "if (host->...host_type == ADMA)" tests.
>
> There are several FIXMEs from the original code.
>
> I added an "adma" boolean flag to simplify testing the different code paths.

Could I get you to diff against the attached version?

Jeff




Attachments:
sata_nv.c (40.18 kB)

2006-03-18 08:06:23

by Bill Rugolsky Jr.

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

On Fri, Mar 17, 2006 at 07:56:53PM -0500, Jeff Garzik wrote:
> Could I get you to diff against the attached version?

Certainly.

I took the opportunity to modify my source file to fix a pair of typos in
the pci_device_id changes, and make cosmetic changes by switching to enums
rather than #defines, removing unnecessary braces around single statements,
and fixing whitespace. That reduced the noise considerably, and made the
NV_ADMA_CTL_READ_NON_COHERENT difference manifest.

-Bill

--- sata_nv.c.garzik 2006-03-18 01:50:18.518554000 -0500
+++ sata_nv.c 2006-03-18 02:53:18.000000000 -0500
@@ -29,6 +29,38 @@
* NV-specific details such as register offsets, SATA phy location,
* hotplug info, etc.
*
+ * 0.11
+ * - Added support for ADMA. Disabled by default. Use the module
+ * option adma=on to enable it for supported chipsets.
+ *
+ * 0.10
+ * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
+ * drive. Also made the check_hotplug() callbacks return whether there
+ * was a hotplug interrupt or not. This was not the source of the
+ * spurious interrupts, but is the right thing to do anyway.
+ *
+ * 0.09
+ * - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
+ *
+ * 0.08
+ * - Added support for MCP51 and MCP55.
+ *
+ * 0.07
+ * - Added support for RAID class code.
+ *
+ * 0.06
+ * - Added generic SATA support by using a pci_device_id that filters on
+ * the IDE storage class code.
+ *
+ * 0.03
+ * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using
+ * mmio_base, which is only set for the CK804/MCP04 case.
+ *
+ * 0.02
+ * - Added support for CK804 SATA controller.
+ *
+ * 0.01
+ * - Initial revision.
*/

#include <linux/config.h>
@@ -47,7 +79,7 @@
//#define DEBUG

#define DRV_NAME "sata_nv"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.11-alpha"

enum {
NV_PORTS = 2,
@@ -148,7 +180,7 @@ enum {
NV_ADMA_CTL_CHANNEL_RESET = (1 << 5),
NV_ADMA_CTL_GO = (1 << 7),
NV_ADMA_CTL_AIEN = (1 << 8),
- NV_ADMA_CTL_READ_NON_COHERENT = (1 << 11),
+ NV_ADMA_CTL_READ_NON_COHERENT = (2 << 11),
NV_ADMA_CTL_WRITE_NON_COHERENT = (1 << 12),

// CPB response flag bits
@@ -186,6 +218,10 @@ enum {
NV_ADMA_PORT_REGISTER_MODE = (1 << 0),
};

+#ifndef min
+#define min(x,y) ((x) < (y) ? x : y)
+#endif
+
struct nv_adma_prd {
u64 addr;
u32 len;
@@ -237,18 +273,23 @@ static irqreturn_t nv_interrupt (int irq
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);
static void nv_host_stop (struct ata_host_set *host_set);
+static int nv_port_start(struct ata_port *ap);
+static void nv_port_stop(struct ata_port *ap);
static int nv_adma_port_start(struct ata_port *ap);
static void nv_adma_port_stop(struct ata_port *ap);
+static void nv_irq_clear(struct ata_port *ap);
static void nv_adma_irq_clear(struct ata_port *ap);
static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug(struct ata_host_set *host_set);
-static void nv_check_hotplug(struct ata_host_set *host_set);
+static int nv_check_hotplug(struct ata_host_set *host_set);
static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
static void nv_enable_hotplug_adma(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug_adma(struct ata_host_set *host_set);
-static void nv_check_hotplug_adma(struct ata_host_set *host_set);
+static int nv_check_hotplug_adma(struct ata_host_set *host_set);
+static void nv_qc_prep(struct ata_queued_cmd *qc);
+static int nv_qc_issue(struct ata_queued_cmd *qc);
static int nv_adma_qc_issue(struct ata_queued_cmd *qc);
static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb);
@@ -256,8 +297,11 @@ static void nv_adma_fill_sg(struct ata_q
static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, struct scatterlist *sg, int idx, struct nv_adma_prd *aprd);
static void nv_adma_register_mode(struct ata_port *ap);
static void nv_adma_mode(struct ata_port *ap);
+static u8 nv_bmdma_status(struct ata_port *ap);
static u8 nv_adma_bmdma_status(struct ata_port *ap);
+static void nv_bmdma_stop(struct ata_queued_cmd *qc);
static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc);
+static void nv_eng_timeout(struct ata_port *ap);
static void nv_adma_eng_timeout(struct ata_port *ap);
#ifdef DEBUG
static void nv_adma_dump_cpb(struct nv_adma_cpb *cpb);
@@ -267,40 +311,40 @@ static void nv_adma_dump_port(struct ata
static void nv_adma_dump_iomem(void __iomem *m, int len);
#endif

+
+static int adma_enabled;
+
enum nv_host_type
{
- GENERIC,
- NFORCE2,
- NFORCE3,
- CK804,
- MCP51,
- MCP55,
- ADMA
+ GENERIC = 0x0,
+ NFORCE = 0x1,
+ CK804 = 0x2,
+ ADMA = 0x4
};

static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADMA },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADMA },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADMA },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADMA },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 | ADMA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
@@ -317,7 +361,7 @@ struct nv_host_desc
enum nv_host_type host_type;
void (*enable_hotplug)(struct ata_probe_ent *probe_ent);
void (*disable_hotplug)(struct ata_host_set *host_set);
- void (*check_hotplug)(struct ata_host_set *host_set);
+ int (*check_hotplug)(struct ata_host_set *host_set);

};
static struct nv_host_desc nv_device_tbl[] = {
@@ -328,13 +372,7 @@ static struct nv_host_desc nv_device_tbl
.check_hotplug = NULL,
},
{
- .host_type = NFORCE2,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
- {
- .host_type = NFORCE3,
+ .host_type = NFORCE,
.enable_hotplug = nv_enable_hotplug,
.disable_hotplug= nv_disable_hotplug,
.check_hotplug = nv_check_hotplug,
@@ -344,16 +382,6 @@ static struct nv_host_desc nv_device_tbl
.disable_hotplug= nv_disable_hotplug_ck804,
.check_hotplug = nv_check_hotplug_ck804,
},
- { .host_type = MCP51,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
- { .host_type = MCP55,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
{ .host_type = ADMA,
.enable_hotplug = nv_enable_hotplug_adma,
.disable_hotplug= nv_disable_hotplug_adma,
@@ -393,25 +421,6 @@ static struct scsi_host_template nv_sht
.bios_param = ata_std_bios_param,
};

-static struct scsi_host_template nv_adma_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = NV_ADMA_SGTBL_LEN,
- .max_sectors = ATA_MAX_SECTORS,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .bios_param = ata_std_bios_param,
-};
-
static const struct ata_port_operations nv_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
@@ -422,41 +431,17 @@ static const struct ata_port_operations
.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,
- .irq_handler = nv_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_host_stop,
-};
-
-static const struct ata_port_operations nv_adma_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 = nv_adma_bmdma_stop,
- .bmdma_status = nv_adma_bmdma_status,
- .qc_prep = nv_adma_qc_prep,
- .qc_issue = nv_adma_qc_issue,
- .eng_timeout = nv_adma_eng_timeout,
+ .bmdma_stop = nv_bmdma_stop,
+ .bmdma_status = nv_bmdma_status,
+ .qc_prep = nv_qc_prep,
+ .qc_issue = nv_qc_issue,
+ .eng_timeout = nv_eng_timeout,
.irq_handler = nv_interrupt,
- .irq_clear = nv_adma_irq_clear,
+ .irq_clear = nv_irq_clear,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
- .port_start = nv_adma_port_start,
- .port_stop = nv_adma_port_stop,
+ .port_start = nv_port_start,
+ .port_stop = nv_port_stop,
.host_stop = nv_host_stop,
};

@@ -646,19 +631,6 @@ static struct ata_port_info nv_port_info
.port_ops = &nv_ops,
};

-static struct ata_port_info nv_adma_port_info = {
- .sht = &nv_adma_sht,
- .host_flags = ATA_FLAG_SATA |
- /* ATA_FLAG_SATA_RESET | */
- ATA_FLAG_SRST |
- ATA_FLAG_MMIO |
- ATA_FLAG_NO_LEGACY,
- .pio_mask = NV_PIO_MASK,
- .mwdma_mask = NV_MWDMA_MASK,
- .udma_mask = NV_UDMA_MASK,
- .port_ops = &nv_adma_ops,
-};
-
MODULE_AUTHOR("NVIDIA");
MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
MODULE_LICENSE("GPL");
@@ -687,19 +659,53 @@ static inline void nv_disable_adma_space
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
}

+static void nv_irq_clear(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ nv_adma_irq_clear(ap);
+ else
+ ata_bmdma_irq_clear(ap);
+}
+
static void nv_adma_irq_clear(struct ata_port *ap)
{
- /* TODO */
+ /* FIXME: TODO */
+}
+
+static u8 nv_bmdma_status(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ return nv_adma_bmdma_status(ap);
+ else
+ return ata_bmdma_status(ap);
}

static u8 nv_adma_bmdma_status(struct ata_port *ap)
{
+ // FIXME: This is no different than ata_bmdma_status for PIO
return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}

+static void nv_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ nv_adma_bmdma_stop(qc);
+ else
+ ata_bmdma_stop(qc);
+}
+
static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
{
- /* TODO */
+ /* FIXME: TODO */
}

static irqreturn_t nv_interrupt (int irq, void *dev_instance,
@@ -715,16 +721,18 @@ static irqreturn_t nv_interrupt (int irq

for (i = 0; i < host_set->n_ports; i++) {
struct ata_port *ap = host_set->ports[i];
- struct nv_adma_port_priv *pp = ap->private_data;

if (ap &&
!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
- void __iomem *mmio = nv_adma_ctl_block(ap);
struct ata_queued_cmd *qc;

- // read notifiers
- pp->notifier = readl(mmio + NV_ADMA_NOTIFIER);
- pp->notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+ if (host->host_desc->host_type == ADMA) {
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = nv_adma_ctl_block(ap);
+ // read notifiers
+ pp->notifier = readl(mmio + NV_ADMA_NOTIFIER);
+ pp->notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+ }

qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
@@ -732,16 +740,21 @@ static irqreturn_t nv_interrupt (int irq
handled += nv_adma_host_intr(ap, qc);
else
handled += ata_host_intr(ap, qc);
+ } else {
+ // No request pending? Clear interrupt status
+ // anyway, in case there's one pending.
+ ap->ops->check_status(ap);
}
}

}

if (host->host_desc->check_hotplug)
- host->host_desc->check_hotplug(host_set);
+ // FIXME: do something with the return value
+ (void) host->host_desc->check_hotplug(host_set);

// clear notifier
- if (handled) {
+ if (handled && host->host_desc->host_type == ADMA) {
for (i = 0; i < host_set->n_ports; i++) {
struct ata_port *ap = host_set->ports[i];
struct nv_adma_port_priv *pp = ap->private_data;
@@ -811,6 +824,28 @@ static void nv_host_stop (struct ata_hos
pci_iounmap(pdev, host_set->mmio_base);
}

+static int nv_port_start(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ return nv_adma_port_start(ap);
+ else
+ return ata_port_start(ap);
+}
+
+static void nv_port_stop(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ nv_adma_port_stop(ap);
+ else
+ ata_port_stop(ap);
+}
+
static int nv_adma_port_start(struct ata_port *ap)
{
struct device *dev = ap->host_set->dev;
@@ -975,6 +1010,17 @@ static int nv_adma_host_init(struct ata_
return 0;
}

+static struct nv_host_desc *nv_find_host_desc(unsigned int host_type)
+{
+ int i;
+
+ for (i = 0 ; i < (sizeof nv_device_tbl)/(sizeof nv_device_tbl[0]); i++)
+ if (nv_device_tbl[i].host_type == host_type)
+ return &nv_device_tbl[i];
+ return NULL;
+}
+
+
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1017,18 +1063,23 @@ static int nv_init_one (struct pci_dev *

rc = -ENOMEM;

- host_desc = &nv_device_tbl[ent->driver_data];
+ ppi = &nv_port_info;
+
+ if (adma_enabled && (ent->driver_data & ADMA))
+ host_desc = nv_find_host_desc(ADMA);
+ else
+ host_desc = nv_find_host_desc(ent->driver_data & ~ADMA);

- /* select ADMA or legacy PCI IDE BMDMA controller operation */
if (host_desc->host_type == ADMA) {
+ // ADMA overrides
+ ppi->host_flags |= ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
#ifdef NV_ADMA_NCQ
ppi->host_flags |= ATA_FLAG_NCQ;
- ppi->sht->can_queue = NV_ADMA_CAN_QUEUE;
#endif
-
- ppi = &nv_adma_port_info;
- } else
- ppi = &nv_port_info;
+ ppi->sht->can_queue = NV_ADMA_CAN_QUEUE;
+ ppi->sht->sg_tablesize = NV_ADMA_SGTBL_LEN;
+// ppi->port_ops->irq_handler = nv_adma_interrupt;
+ }

probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
@@ -1072,7 +1123,7 @@ static int nv_init_one (struct pci_dev *

pci_set_master(pdev);

- if (ent->driver_data == ADMA) {
+ if (host_desc->host_type == ADMA) {
rc = nv_adma_host_init(probe_ent);
if (rc)
goto err_out_iounmap;
@@ -1106,6 +1157,17 @@ err_out:
return rc;
}

+static void nv_eng_timeout(struct ata_port *ap)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ nv_adma_eng_timeout(ap);
+ else
+ ata_eng_timeout(ap);
+}
+
static void nv_adma_eng_timeout(struct ata_port *ap)
{
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -1149,6 +1211,17 @@ out:
DPRINTK("EXIT\n");
}

+static void nv_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ nv_adma_qc_prep(qc);
+ else
+ ata_qc_prep(qc);
+}
+
static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
@@ -1259,6 +1332,17 @@ static void nv_adma_mode(struct ata_port
pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE;
}

+static int nv_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_host_set *host_set = qc->ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
+ if (host->host_desc->host_type == ADMA)
+ return nv_adma_qc_issue(qc);
+ else
+ return ata_qc_issue_prot(qc);
+}
+
static int nv_adma_qc_issue(struct ata_queued_cmd *qc)
{
#if 0
@@ -1281,9 +1365,8 @@ static int nv_adma_qc_issue(struct ata_q
nv_adma_dump_cpb(&pp->cpb[qc->tag]);
if (qc->n_elem > 5) {
int i;
- for (i = 0; i < qc->n_elem - 5; i++) {
+ for (i = 0; i < qc->n_elem - 5; i++)
nv_adma_dump_aprd(&pp->aprd[i]);
- }
}
#endif

@@ -1323,7 +1406,7 @@ static void nv_disable_hotplug(struct at
outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
}

-static void nv_check_hotplug(struct ata_host_set *host_set)
+static int nv_check_hotplug(struct ata_host_set *host_set)
{
u8 intr_status;

@@ -1348,7 +1431,9 @@ static void nv_check_hotplug(struct ata_
if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
printk(KERN_WARNING "nv_sata: "
"Secondary device removed\n");
+ return 1;
}
+ return 0;
}

static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
@@ -1380,7 +1465,7 @@ static void nv_disable_hotplug_ck804(str
nv_disable_adma_space(pdev);
}

-static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
{
u8 intr_status;

@@ -1405,7 +1490,9 @@ static void nv_check_hotplug_ck804(struc
if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
printk(KERN_WARNING "nv_sata: "
"Secondary device removed\n");
+ return 1;
}
+ return 0;
}

static void nv_enable_hotplug_adma(struct ata_probe_ent *probe_ent)
@@ -1439,10 +1526,11 @@ static void nv_disable_hotplug_adma(stru
}
}

-static void nv_check_hotplug_adma(struct ata_host_set *host_set)
+static int nv_check_hotplug_adma(struct ata_host_set *host_set)
{
unsigned int i;
u16 adma_status;
+ int hotplugged = 0;

for (i = 0; i < host_set->n_ports; i++) {
void __iomem *mmio = __nv_adma_ctl_block(host_set->mmio_base, i);
@@ -1451,13 +1539,16 @@ static void nv_check_hotplug_adma(struct
printk(KERN_WARNING "nv_sata: "
"port %d device added\n", i);
writew(NV_ADMA_STAT_HOTPLUG, mmio + NV_ADMA_STAT);
+ hotplugged = 1;
}
if (adma_status & NV_ADMA_STAT_HOTUNPLUG) {
printk(KERN_WARNING "nv_sata: "
"port %d device removed\n", i);
writew(NV_ADMA_STAT_HOTUNPLUG, mmio + NV_ADMA_STAT);
+ hotplugged = 1;
}
}
+ return hotplugged;
}

static int __init nv_init(void)
@@ -1472,6 +1563,9 @@ static void __exit nv_exit(void)

module_init(nv_init);
module_exit(nv_exit);
+module_param_named(adma, adma_enabled, bool, 0);
+MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
+

#ifdef DEBUG
static void nv_adma_dump_aprd(struct nv_adma_prd *aprd)
@@ -1525,13 +1619,11 @@ static void nv_adma_dump_cpb(struct nv_a
printk("tag: 0x%02x\n", cpb->tag);
printk("next_cpb_idx: 0x%02x\n", cpb->next_cpb_idx);
printk("tf:\n");
- for (i=0; i<12; i++) {
+ for (i=0; i<12; i++)
nv_adma_dump_cpb_tf(cpb->tf[i]);
- }
printk("aprd:\n");
- for (i=0; i<5; i++) {
+ for (i=0; i<5; i++)
nv_adma_dump_aprd(&cpb->aprd[i]);
- }
printk("next_aprd: 0x%016llx\n", cpb->next_aprd);
}

2006-03-18 08:56:36

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Bill Rugolsky Jr. wrote:
> On Fri, Mar 17, 2006 at 07:56:53PM -0500, Jeff Garzik wrote:
>
>>Could I get you to diff against the attached version?
>
>
> Certainly.
>
> I took the opportunity to modify my source file to fix a pair of typos in
> the pci_device_id changes, and make cosmetic changes by switching to enums
> rather than #defines, removing unnecessary braces around single statements,
> and fixing whitespace. That reduced the noise considerably, and made the
> NV_ADMA_CTL_READ_NON_COHERENT difference manifest.

OK, can you try the attached sata_nv.c? Does it perform to the level
that yours does?

It should contain all the functional changes in your patch, while
ignoring all the noise such as

+ if (host->host_desc->host_type == ADMA)
+ return nv_adma_port_start(ap);
+ else
+ return ata_port_start(ap);

and the hotplug return code changes.

I also intentionally excluded the READ_NON_COHERENT and
ap->ops->check_status() paranoia function call, to see if those actually
solve some problems.

Jeff



Attachments:
sata_nv.c (40.48 kB)

2006-03-19 23:23:20

by Bill Rugolsky Jr.

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

On Sat, Mar 18, 2006 at 03:56:28AM -0500, Jeff Garzik wrote:
> OK, can you try the attached sata_nv.c? Does it perform to the level
> that yours does?

Yes, the results are approximately the same. Booting from port 0 (sda)
with ADMA enabled still results in timeouts on port 3 (sdc) while
running tars on the RAID1 array on ports 2&3.

ata4: command 0x25 timeout, stat 0x50
ata4: command 0x25 timeout, stat 0x50
( xterm-3349 |#0): new 355 us maximum-latency wakeup.
( watchdog/0-4 |#0): new 468 us maximum-latency wakeup.
ata4: command 0x35 timeout, stat 0x50
ata4: command 0x35 timeout, stat 0x50
ata4: command 0x35 timeout, stat 0x50
ata4: command 0x35 timeout, stat 0x50
ata4: command 0x35 timeout, stat 0x50
ata4: command 0x35 timeout, stat 0x50

After a while, syncing the filesystems hangs the sync process, though
the system continues to function, and I can log in on another VC.

The good news: no long latencies from the status inb() during the
period that it is functional! :-p

Booting without ADMA gives the usual stable behavior, with the long
latencies from the status inb().

I was a little disconcerted when I saw this this in the trace with ADMA
disabled,

tar-21466 0dnh. 3979us : nv_check_hotplug_adma (nv_interrupt)

until I realized that this

if (!adma_enabled && host_desc->host_type == ADMA)
host_desc->host_type--;

only alters the outcome of the "host_desc->host_type == ADMA" test, but
still uses the ADMA-based hotplug functions.

-Bill

2006-03-21 01:28:17

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Bill Rugolsky Jr. wrote:
> On Sat, Mar 18, 2006 at 03:56:28AM -0500, Jeff Garzik wrote:
>
>>OK, can you try the attached sata_nv.c? Does it perform to the level
>>that yours does?
>
>
> Yes, the results are approximately the same. Booting from port 0 (sda)
> with ADMA enabled still results in timeouts on port 3 (sdc) while
> running tars on the RAID1 array on ports 2&3.

Thanks a lot for testing.

I've stored the sata_nv updates I sent you in the 'nv-adma' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git


> ata4: command 0x25 timeout, stat 0x50
> ata4: command 0x25 timeout, stat 0x50
> ( xterm-3349 |#0): new 355 us maximum-latency wakeup.
> ( watchdog/0-4 |#0): new 468 us maximum-latency wakeup.
> ata4: command 0x35 timeout, stat 0x50
> ata4: command 0x35 timeout, stat 0x50
> ata4: command 0x35 timeout, stat 0x50
> ata4: command 0x35 timeout, stat 0x50
> ata4: command 0x35 timeout, stat 0x50
> ata4: command 0x35 timeout, stat 0x50
>
> After a while, syncing the filesystems hangs the sync process, though
> the system continues to function, and I can log in on another VC.

hmmm. Sounds like some attention should be paid to the error handling
portion of the code.


> The good news: no long latencies from the status inb() during the
> period that it is functional! :-p

heh :)

Dumb question, to be certain that I understood your first paragraph:
you do indeed see at least -some- success talking to devices on port 1,
2, 3... ? i.e. not just port 0 works?


> Booting without ADMA gives the usual stable behavior, with the long
> latencies from the status inb().

Weird. Well, now that we appear to have narrowed the non-ADMA case down
to inb(), I'm going to punt this one as not-my-problem ;-)


> I was a little disconcerted when I saw this this in the trace with ADMA
> disabled,
>
> tar-21466 0dnh. 3979us : nv_check_hotplug_adma (nv_interrupt)
>
> until I realized that this
>
> if (!adma_enabled && host_desc->host_type == ADMA)
> host_desc->host_type--;
>
> only alters the outcome of the "host_desc->host_type == ADMA" test, but
> still uses the ADMA-based hotplug functions.

Yep. That's part of my general plan to eliminate all the

if (adma)
foo
else
bar

type code in favor to create separate ADMA and non-ADMA hooks.
Particularly in the key hot paths, sata_nv should avoid asking "are we
ADMA?" all the time.

Jeff


2006-03-21 12:48:06

by Bill Rugolsky Jr.

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

On Mon, Mar 20, 2006 at 08:28:13PM -0500, Jeff Garzik wrote:
> Thanks a lot for testing.
>
> I've stored the sata_nv updates I sent you in the 'nv-adma' branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git

OK, I'll pull from there for further testing.

> Dumb question, to be certain that I understood your first paragraph:
> you do indeed see at least -some- success talking to devices on port 1,
> 2, 3... ? i.e. not just port 0 works?

I can start up the RAID1's on ports 2 and 3, activate the VG on top
of /dev/md5, mount the filesystems, and use them. I was able to
cp -a the mounted root filesystem from /dev/md2 to a subdir on /dev/sda1.

It was only when I started up a few copies of "tar cf /dev/zero ... &"
that the timeouts began.

> Weird. Well, now that we appear to have narrowed the non-ADMA case down
> to inb(), I'm going to punt this one as not-my-problem ;-)

Roger. I'll stare at it a bit longer, but I probably need to order three
SATA adapters. Any recommendations? These Tyan 2895 machines all have
2-4 74GB WD Raptors in them. I don't really need expensive 3ware or
Areca cards for these workstations, just reasonable latencies.

Thanks.

-Bill

2006-03-27 01:14:39

by Matt Heler

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Hey Jeff,

Using Bill's original patch I was able to boot up perfectly with adma support
enabled on my workstation. Even after several stress tests (
tar -cf /dev/null . , and dd if=/dev/sda of=/dev/null ), everything seems to
be a-ok. However when I tried the sata_nv.c file that you sent to Bill, I
kept on getting hardlocks, and thus was unable to stress test your version.

Also for note, I heve not received any of the timeout problems reported by
Bill. Nor have I had any latency problems with adma enabled.

Matt Heler

On Monday 20 March 2006 8:28 pm, Jeff Garzik wrote:
> Bill Rugolsky Jr. wrote:
> > On Sat, Mar 18, 2006 at 03:56:28AM -0500, Jeff Garzik wrote:
> >>OK, can you try the attached sata_nv.c? Does it perform to the level
> >>that yours does?
> >
> > Yes, the results are approximately the same. Booting from port 0 (sda)
> > with ADMA enabled still results in timeouts on port 3 (sdc) while
> > running tars on the RAID1 array on ports 2&3.
>
> Thanks a lot for testing.
>
> I've stored the sata_nv updates I sent you in the 'nv-adma' branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
>
> > ata4: command 0x25 timeout, stat 0x50
> > ata4: command 0x25 timeout, stat 0x50
> > ( xterm-3349 |#0): new 355 us maximum-latency wakeup.
> > ( watchdog/0-4 |#0): new 468 us maximum-latency wakeup.
> > ata4: command 0x35 timeout, stat 0x50
> > ata4: command 0x35 timeout, stat 0x50
> > ata4: command 0x35 timeout, stat 0x50
> > ata4: command 0x35 timeout, stat 0x50
> > ata4: command 0x35 timeout, stat 0x50
> > ata4: command 0x35 timeout, stat 0x50
> >
> > After a while, syncing the filesystems hangs the sync process, though
> > the system continues to function, and I can log in on another VC.
>
> hmmm. Sounds like some attention should be paid to the error handling
> portion of the code.
>
> > The good news: no long latencies from the status inb() during the
> > period that it is functional! :-p
>
> heh :)
>
> Dumb question, to be certain that I understood your first paragraph:
> you do indeed see at least -some- success talking to devices on port 1,
> 2, 3... ? i.e. not just port 0 works?
>
> > Booting without ADMA gives the usual stable behavior, with the long
> > latencies from the status inb().
>
> Weird. Well, now that we appear to have narrowed the non-ADMA case down
> to inb(), I'm going to punt this one as not-my-problem ;-)
>
> > I was a little disconcerted when I saw this this in the trace with ADMA
> > disabled,
> >
> > tar-21466 0dnh. 3979us : nv_check_hotplug_adma (nv_interrupt)
> >
> > until I realized that this
> >
> > if (!adma_enabled && host_desc->host_type == ADMA)
> > host_desc->host_type--;
> >
> > only alters the outcome of the "host_desc->host_type == ADMA" test, but
> > still uses the ADMA-based hotplug functions.
>
> Yep. That's part of my general plan to eliminate all the
>
> if (adma)
> foo
> else
> bar
>
> type code in favor to create separate ADMA and non-ADMA hooks.
> Particularly in the key hot paths, sata_nv should avoid asking "are we
> ADMA?" all the time.
>
> Jeff
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2006-03-27 16:08:54

by Bill Rugolsky Jr.

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

On Sun, Mar 26, 2006 at 08:14:35PM -0500, Matt Heler wrote:
> Using Bill's original patch I was able to boot up perfectly with adma support
> enabled on my workstation. Even after several stress tests (
> tar -cf /dev/null . , and dd if=/dev/sda of=/dev/null ), everything seems to
> be a-ok. However when I tried the sata_nv.c file that you sent to Bill, I
> kept on getting hardlocks, and thus was unable to stress test your version.
>
> Also for note, I heve not received any of the timeout problems reported by
> Bill. Nor have I had any latency problems with adma enabled.

Matt,

Nice to see some value falling out of this sata_nv thread. Did you see
latency problems before enabling ADMA?

Would you provide some specifics on your setup?

Which motherboard, #CPUs, BIOS revision, kernel, MD/LVM2/fs?

On two of my Tyan S2895 machines, including the one that I'm using for testing,
lspci says:

00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev f2)
00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3)
00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3)

and dmidecode says:

BIOS Information
Vendor: Phoenix Technologies Ltd.
Version: 2004Q3
Release Date: 10/12/2005

The other, where I first had lost tick problems, says:

00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev a3)
00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev a3)

BIOS Information
Vendor: Phoenix Technologies Ltd.
Version: 2004Q3
Release Date: 06/07/2005


Thanks,

Bill

2006-03-27 21:46:56

by Matt Heler

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Hey Bill,

I spoke abit to soon though regarding that stability.. After booting up X and
running Azerues and kde, my system stalled and locked. However it lasted much
longer then Jeff's version.

I'm running the DFI Lanparty with an Athlon 4400. I also have the following
setup

2x300gb seagate drives 7200.8 in a raid0 format with ext3
2x400gb seagate drives 7200.9 again in a raid0 format with ext3

and lspci gives me the following ::

00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev a3)
00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev a3)


On Monday 27 March 2006 11:08 am, Bill Rugolsky Jr. wrote:
> On Sun, Mar 26, 2006 at 08:14:35PM -0500, Matt Heler wrote:
> > Using Bill's original patch I was able to boot up perfectly with adma
> > support enabled on my workstation. Even after several stress tests (
> > tar -cf /dev/null . , and dd if=/dev/sda of=/dev/null ), everything seems
> > to be a-ok. However when I tried the sata_nv.c file that you sent to
> > Bill, I kept on getting hardlocks, and thus was unable to stress test
> > your version.
> >
> > Also for note, I heve not received any of the timeout problems reported
> > by Bill. Nor have I had any latency problems with adma enabled.
>
> Matt,
>
> Nice to see some value falling out of this sata_nv thread. Did you see
> latency problems before enabling ADMA?
>
> Would you provide some specifics on your setup?
>
> Which motherboard, #CPUs, BIOS revision, kernel, MD/LVM2/fs?
>
> On two of my Tyan S2895 machines, including the one that I'm using for
> testing, lspci says:
>
> 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev f2)
> 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev
> f3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> (rev f3)
>
> and dmidecode says:
>
> BIOS Information
> Vendor: Phoenix Technologies Ltd.
> Version: 2004Q3
> Release Date: 10/12/2005
>
> The other, where I first had lost tick problems, says:
>
> 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
> 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev
> a3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> (rev a3)
>
> BIOS Information
> Vendor: Phoenix Technologies Ltd.
> Version: 2004Q3
> Release Date: 06/07/2005
>
>
> Thanks,
>
> Bill

2006-03-27 22:00:57

by Matt Heler

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

I forgot to include this.. but here's my bios version

Vendor: Phoenix Technologies, LTD
Version: 6.00 PG
Release Date: 06/23/2005

On Monday 27 March 2006 4:46 pm, Matt Heler wrote:
> Hey Bill,
>
> I spoke abit to soon though regarding that stability.. After booting up X
> and running Azerues and kde, my system stalled and locked. However it
> lasted much longer then Jeff's version.
>
> I'm running the DFI Lanparty with an Athlon 4400. I also have the following
> setup
>
> 2x300gb seagate drives 7200.8 in a raid0 format with ext3
> 2x400gb seagate drives 7200.9 again in a raid0 format with ext3
>
> and lspci gives me the following ::
>
> 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
> 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev
> a3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> (rev a3)
>
> On Monday 27 March 2006 11:08 am, Bill Rugolsky Jr. wrote:
> > On Sun, Mar 26, 2006 at 08:14:35PM -0500, Matt Heler wrote:
> > > Using Bill's original patch I was able to boot up perfectly with adma
> > > support enabled on my workstation. Even after several stress tests (
> > > tar -cf /dev/null . , and dd if=/dev/sda of=/dev/null ), everything
> > > seems to be a-ok. However when I tried the sata_nv.c file that you sent
> > > to Bill, I kept on getting hardlocks, and thus was unable to stress
> > > test your version.
> > >
> > > Also for note, I heve not received any of the timeout problems reported
> > > by Bill. Nor have I had any latency problems with adma enabled.
> >
> > Matt,
> >
> > Nice to see some value falling out of this sata_nv thread. Did you see
> > latency problems before enabling ADMA?
> >
> > Would you provide some specifics on your setup?
> >
> > Which motherboard, #CPUs, BIOS revision, kernel, MD/LVM2/fs?
> >
> > On two of my Tyan S2895 machines, including the one that I'm using for
> > testing, lspci says:
> >
> > 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev f2)
> > 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> > (rev f3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA
> > Controller (rev f3)
> >
> > and dmidecode says:
> >
> > BIOS Information
> > Vendor: Phoenix Technologies Ltd.
> > Version: 2004Q3
> > Release Date: 10/12/2005
> >
> > The other, where I first had lost tick problems, says:
> >
> > 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
> > 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> > (rev a3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA
> > Controller (rev a3)
> >
> > BIOS Information
> > Vendor: Phoenix Technologies Ltd.
> > Version: 2004Q3
> > Release Date: 06/07/2005
> >
> >
> > Thanks,
> >
> > Bill
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2006-03-30 01:23:40

by Alexander Samad

[permalink] [raw]
Subject: Re: [PATCH][INCOMPLETE] sata_nv: merge ADMA support

Hi

I was wondering if the patch for sata_nv to hanlde the lost interrupts
has been submitted for inclussion in the kernel.

I have sort of been following this thread, were it seems that the
interrupt problem has been fixed, but they were also going to fix the
adma problem as well.

I did a quick check of 2.6.16 changelog and see no mention for sata_nv.

I seem to suffere from this issue quite often - doing dvd burns across a
network.....

Thanks

On Mon, Mar 27, 2006 at 05:00:53PM -0500, Matt Heler wrote:
> I forgot to include this.. but here's my bios version
>
> Vendor: Phoenix Technologies, LTD
> Version: 6.00 PG
> Release Date: 06/23/2005
>
> On Monday 27 March 2006 4:46 pm, Matt Heler wrote:
> > Hey Bill,
> >
> > I spoke abit to soon though regarding that stability.. After booting up X
> > and running Azerues and kde, my system stalled and locked. However it
> > lasted much longer then Jeff's version.
> >
> > I'm running the DFI Lanparty with an Athlon 4400. I also have the following
> > setup
> >
> > 2x300gb seagate drives 7200.8 in a raid0 format with ext3
> > 2x400gb seagate drives 7200.9 again in a raid0 format with ext3
> >
> > and lspci gives me the following ::
> >
> > 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
> > 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev
> > a3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> > (rev a3)
> >
> > On Monday 27 March 2006 11:08 am, Bill Rugolsky Jr. wrote:
> > > On Sun, Mar 26, 2006 at 08:14:35PM -0500, Matt Heler wrote:
> > > > Using Bill's original patch I was able to boot up perfectly with adma
> > > > support enabled on my workstation. Even after several stress tests (
> > > > tar -cf /dev/null . , and dd if=/dev/sda of=/dev/null ), everything
> > > > seems to be a-ok. However when I tried the sata_nv.c file that you sent
> > > > to Bill, I kept on getting hardlocks, and thus was unable to stress
> > > > test your version.
> > > >
> > > > Also for note, I heve not received any of the timeout problems reported
> > > > by Bill. Nor have I had any latency problems with adma enabled.
> > >
> > > Matt,
> > >
> > > Nice to see some value falling out of this sata_nv thread. Did you see
> > > latency problems before enabling ADMA?
> > >
> > > Would you provide some specifics on your setup?
> > >
> > > Which motherboard, #CPUs, BIOS revision, kernel, MD/LVM2/fs?
> > >
> > > On two of my Tyan S2895 machines, including the one that I'm using for
> > > testing, lspci says:
> > >
> > > 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev f2)
> > > 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> > > (rev f3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA
> > > Controller (rev f3)
> > >
> > > and dmidecode says:
> > >
> > > BIOS Information
> > > Vendor: Phoenix Technologies Ltd.
> > > Version: 2004Q3
> > > Release Date: 10/12/2005
> > >
> > > The other, where I first had lost tick problems, says:
> > >
> > > 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev a2)
> > > 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller
> > > (rev a3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA
> > > Controller (rev a3)
> > >
> > > BIOS Information
> > > Vendor: Phoenix Technologies Ltd.
> > > Version: 2004Q3
> > > Release Date: 06/07/2005
> > >
> > >
> > > Thanks,
> > >
> > > Bill
> >
> > -
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at http://www.tux.org/lkml/
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>


Attachments:
(No filename) (3.90 kB)
signature.asc (191.00 B)
Digital signature
Download all attachments