diff options
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r-- | drivers/ata/sata_nv.c | 70 |
1 files changed, 43 insertions, 27 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6f1460614325..c49ad0e61b6f 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c | |||
@@ -305,10 +305,10 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); | |||
305 | static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); | 305 | static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); |
306 | static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); | 306 | static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); |
307 | 307 | ||
308 | static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, | ||
309 | unsigned long deadline); | ||
308 | static void nv_nf2_freeze(struct ata_port *ap); | 310 | static void nv_nf2_freeze(struct ata_port *ap); |
309 | static void nv_nf2_thaw(struct ata_port *ap); | 311 | static void nv_nf2_thaw(struct ata_port *ap); |
310 | static int nv_nf2_hardreset(struct ata_link *link, unsigned int *class, | ||
311 | unsigned long deadline); | ||
312 | static void nv_ck804_freeze(struct ata_port *ap); | 312 | static void nv_ck804_freeze(struct ata_port *ap); |
313 | static void nv_ck804_thaw(struct ata_port *ap); | 313 | static void nv_ck804_thaw(struct ata_port *ap); |
314 | static int nv_adma_slave_config(struct scsi_device *sdev); | 314 | static int nv_adma_slave_config(struct scsi_device *sdev); |
@@ -352,6 +352,7 @@ enum nv_host_type | |||
352 | NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ | 352 | NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ |
353 | CK804, | 353 | CK804, |
354 | ADMA, | 354 | ADMA, |
355 | MCP5x, | ||
355 | SWNCQ, | 356 | SWNCQ, |
356 | }; | 357 | }; |
357 | 358 | ||
@@ -363,10 +364,10 @@ static const struct pci_device_id nv_pci_tbl[] = { | |||
363 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, | 364 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, |
364 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, | 365 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, |
365 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, | 366 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, |
366 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ }, | 367 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), MCP5x }, |
367 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ }, | 368 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), MCP5x }, |
368 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ }, | 369 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), MCP5x }, |
369 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ }, | 370 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), MCP5x }, |
370 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, | 371 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, |
371 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, | 372 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, |
372 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, | 373 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, |
@@ -432,7 +433,7 @@ static struct ata_port_operations nv_nf2_ops = { | |||
432 | .inherits = &nv_common_ops, | 433 | .inherits = &nv_common_ops, |
433 | .freeze = nv_nf2_freeze, | 434 | .freeze = nv_nf2_freeze, |
434 | .thaw = nv_nf2_thaw, | 435 | .thaw = nv_nf2_thaw, |
435 | .hardreset = nv_nf2_hardreset, | 436 | .hardreset = nv_noclassify_hardreset, |
436 | }; | 437 | }; |
437 | 438 | ||
438 | /* CK804 finally gets hardreset right */ | 439 | /* CK804 finally gets hardreset right */ |
@@ -467,8 +468,19 @@ static struct ata_port_operations nv_adma_ops = { | |||
467 | .host_stop = nv_adma_host_stop, | 468 | .host_stop = nv_adma_host_stop, |
468 | }; | 469 | }; |
469 | 470 | ||
471 | /* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to | ||
472 | * work, hardreset should be used and hardreset can't report proper | ||
473 | * signature, which suggests that mcp5x is closer to nf2 as long as | ||
474 | * reset quirkiness is concerned. Define separate ops for mcp5x with | ||
475 | * nv_noclassify_hardreset(). | ||
476 | */ | ||
477 | static struct ata_port_operations nv_mcp5x_ops = { | ||
478 | .inherits = &nv_common_ops, | ||
479 | .hardreset = nv_noclassify_hardreset, | ||
480 | }; | ||
481 | |||
470 | static struct ata_port_operations nv_swncq_ops = { | 482 | static struct ata_port_operations nv_swncq_ops = { |
471 | .inherits = &nv_generic_ops, | 483 | .inherits = &nv_mcp5x_ops, |
472 | 484 | ||
473 | .qc_defer = ata_std_qc_defer, | 485 | .qc_defer = ata_std_qc_defer, |
474 | .qc_prep = nv_swncq_qc_prep, | 486 | .qc_prep = nv_swncq_qc_prep, |
@@ -531,6 +543,15 @@ static const struct ata_port_info nv_port_info[] = { | |||
531 | .port_ops = &nv_adma_ops, | 543 | .port_ops = &nv_adma_ops, |
532 | .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), | 544 | .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), |
533 | }, | 545 | }, |
546 | /* MCP5x */ | ||
547 | { | ||
548 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | ||
549 | .pio_mask = NV_PIO_MASK, | ||
550 | .mwdma_mask = NV_MWDMA_MASK, | ||
551 | .udma_mask = NV_UDMA_MASK, | ||
552 | .port_ops = &nv_mcp5x_ops, | ||
553 | .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), | ||
554 | }, | ||
534 | /* SWNCQ */ | 555 | /* SWNCQ */ |
535 | { | 556 | { |
536 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 557 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
@@ -1530,6 +1551,17 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) | |||
1530 | return 0; | 1551 | return 0; |
1531 | } | 1552 | } |
1532 | 1553 | ||
1554 | static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, | ||
1555 | unsigned long deadline) | ||
1556 | { | ||
1557 | bool online; | ||
1558 | int rc; | ||
1559 | |||
1560 | rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, | ||
1561 | &online, NULL); | ||
1562 | return online ? -EAGAIN : rc; | ||
1563 | } | ||
1564 | |||
1533 | static void nv_nf2_freeze(struct ata_port *ap) | 1565 | static void nv_nf2_freeze(struct ata_port *ap) |
1534 | { | 1566 | { |
1535 | void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; | 1567 | void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; |
@@ -1554,17 +1586,6 @@ static void nv_nf2_thaw(struct ata_port *ap) | |||
1554 | iowrite8(mask, scr_addr + NV_INT_ENABLE); | 1586 | iowrite8(mask, scr_addr + NV_INT_ENABLE); |
1555 | } | 1587 | } |
1556 | 1588 | ||
1557 | static int nv_nf2_hardreset(struct ata_link *link, unsigned int *class, | ||
1558 | unsigned long deadline) | ||
1559 | { | ||
1560 | bool online; | ||
1561 | int rc; | ||
1562 | |||
1563 | rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, | ||
1564 | &online, NULL); | ||
1565 | return online ? -EAGAIN : rc; | ||
1566 | } | ||
1567 | |||
1568 | static void nv_ck804_freeze(struct ata_port *ap) | 1589 | static void nv_ck804_freeze(struct ata_port *ap) |
1569 | { | 1590 | { |
1570 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; | 1591 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; |
@@ -2355,14 +2376,9 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2355 | if (type == CK804 && adma_enabled) { | 2376 | if (type == CK804 && adma_enabled) { |
2356 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); | 2377 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); |
2357 | type = ADMA; | 2378 | type = ADMA; |
2358 | } | 2379 | } else if (type == MCP5x && swncq_enabled) { |
2359 | 2380 | dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); | |
2360 | if (type == SWNCQ) { | 2381 | type = SWNCQ; |
2361 | if (swncq_enabled) | ||
2362 | dev_printk(KERN_NOTICE, &pdev->dev, | ||
2363 | "Using SWNCQ mode\n"); | ||
2364 | else | ||
2365 | type = GENERIC; | ||
2366 | } | 2382 | } |
2367 | 2383 | ||
2368 | ppi[0] = &nv_port_info[type]; | 2384 | ppi[0] = &nv_port_info[type]; |