diff options
author | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2009-03-27 16:14:38 +0100 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2009-03-27 16:14:38 +0100 |
commit | b92efa9abffc4a634cd2e7a0f81f8aa6310d67c9 (patch) | |
tree | 9847508d9b8d4e585f90db4a453bfbc3700c997e /drivers/ata/sata_nv.c | |
parent | a16fffdd8eb95ebab7dc22414896fe6493951e0e (diff) | |
parent | be0ea69674ed95e1e98cb3687a241badc756d228 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into avr32-arch
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r-- | drivers/ata/sata_nv.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6f146061432..6cda12ba812 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -57,9 +57,9 @@ enum { NV_MMIO_BAR = 5, NV_PORTS = 2, - NV_PIO_MASK = 0x1f, - NV_MWDMA_MASK = 0x07, - NV_UDMA_MASK = 0x7f, + NV_PIO_MASK = ATA_PIO4, + NV_MWDMA_MASK = ATA_MWDMA2, + NV_UDMA_MASK = ATA_UDMA6, NV_PORT0_SCR_REG_OFFSET = 0x00, NV_PORT1_SCR_REG_OFFSET = 0x40, @@ -305,10 +305,10 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); +static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); -static int nv_nf2_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); static int nv_adma_slave_config(struct scsi_device *sdev); @@ -352,6 +352,7 @@ enum nv_host_type NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ CK804, ADMA, + MCP5x, SWNCQ, }; @@ -363,10 +364,10 @@ static const struct pci_device_id nv_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), MCP5x }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, @@ -407,6 +408,7 @@ static struct scsi_host_template nv_swncq_sht = { static struct ata_port_operations nv_common_ops = { .inherits = &ata_bmdma_port_ops, + .lost_interrupt = ATA_OP_NULL, .scr_read = nv_scr_read, .scr_write = nv_scr_write, }; @@ -420,26 +422,33 @@ static struct ata_port_operations nv_generic_ops = { .hardreset = ATA_OP_NULL, }; -/* OSDL bz3352 reports that nf2/3 controllers can't determine device - * signature reliably. Also, the following thread reports detection - * failure on cold boot with the standard debouncing timing. +/* nf2 is ripe with hardreset related problems. + * + * kernel bz#3352 reports nf2/3 controllers can't determine device + * signature reliably. The following thread reports detection failure + * on cold boot with the standard debouncing timing. * * http://thread.gmane.org/gmane.linux.ide/34098 * - * Debounce with hotplug timing and request follow-up SRST. + * And bz#12176 reports that hardreset simply doesn't work on nf2. + * Give up on it and just don't do hardreset. */ static struct ata_port_operations nv_nf2_ops = { - .inherits = &nv_common_ops, + .inherits = &nv_generic_ops, .freeze = nv_nf2_freeze, .thaw = nv_nf2_thaw, - .hardreset = nv_nf2_hardreset, }; -/* CK804 finally gets hardreset right */ +/* For initial probing after boot and hot plugging, hardreset mostly + * works fine on CK804 but curiously, reprobing on the initial port by + * rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS + * in somewhat undeterministic way. Use noclassify hardreset. + */ static struct ata_port_operations nv_ck804_ops = { .inherits = &nv_common_ops, .freeze = nv_ck804_freeze, .thaw = nv_ck804_thaw, + .hardreset = nv_noclassify_hardreset, .host_stop = nv_ck804_host_stop, }; @@ -467,8 +476,19 @@ static struct ata_port_operations nv_adma_ops = { .host_stop = nv_adma_host_stop, }; +/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to + * work, hardreset should be used and hardreset can't report proper + * signature, which suggests that mcp5x is closer to nf2 as long as + * reset quirkiness is concerned. Define separate ops for mcp5x with + * nv_noclassify_hardreset(). + */ +static struct ata_port_operations nv_mcp5x_ops = { + .inherits = &nv_common_ops, + .hardreset = nv_noclassify_hardreset, +}; + static struct ata_port_operations nv_swncq_ops = { - .inherits = &nv_generic_ops, + .inherits = &nv_mcp5x_ops, .qc_defer = ata_std_qc_defer, .qc_prep = nv_swncq_qc_prep, @@ -531,6 +551,15 @@ static const struct ata_port_info nv_port_info[] = { .port_ops = &nv_adma_ops, .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), }, + /* MCP5x */ + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_mcp5x_ops, + .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), + }, /* SWNCQ */ { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | @@ -1530,6 +1559,17 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) return 0; } +static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + bool online; + int rc; + + rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, + &online, NULL); + return online ? -EAGAIN : rc; +} + static void nv_nf2_freeze(struct ata_port *ap) { void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; @@ -1554,17 +1594,6 @@ static void nv_nf2_thaw(struct ata_port *ap) iowrite8(mask, scr_addr + NV_INT_ENABLE); } -static int nv_nf2_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - bool online; - int rc; - - rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, - &online, NULL); - return online ? -EAGAIN : rc; -} - static void nv_ck804_freeze(struct ata_port *ap) { void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; @@ -2355,14 +2384,9 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (type == CK804 && adma_enabled) { dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; - } - - if (type == SWNCQ) { - if (swncq_enabled) - dev_printk(KERN_NOTICE, &pdev->dev, - "Using SWNCQ mode\n"); - else - type = GENERIC; + } else if (type == MCP5x && swncq_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); + type = SWNCQ; } ppi[0] = &nv_port_info[type]; @@ -2500,7 +2524,7 @@ static void __exit nv_exit(void) module_init(nv_init); module_exit(nv_exit); module_param_named(adma, adma_enabled, bool, 0444); -MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); +MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)"); module_param_named(swncq, swncq_enabled, bool, 0444); MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)"); |