diff options
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r-- | drivers/ata/sata_nv.c | 77 |
1 files changed, 49 insertions, 28 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6f1460614325..444af0415ca1 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,14 +433,19 @@ 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 | /* For initial probing after boot and hot plugging, hardreset mostly |
440 | * works fine on CK804 but curiously, reprobing on the initial port by | ||
441 | * rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS | ||
442 | * in somewhat undeterministic way. Use noclassify hardreset. | ||
443 | */ | ||
439 | static struct ata_port_operations nv_ck804_ops = { | 444 | static struct ata_port_operations nv_ck804_ops = { |
440 | .inherits = &nv_common_ops, | 445 | .inherits = &nv_common_ops, |
441 | .freeze = nv_ck804_freeze, | 446 | .freeze = nv_ck804_freeze, |
442 | .thaw = nv_ck804_thaw, | 447 | .thaw = nv_ck804_thaw, |
448 | .hardreset = nv_noclassify_hardreset, | ||
443 | .host_stop = nv_ck804_host_stop, | 449 | .host_stop = nv_ck804_host_stop, |
444 | }; | 450 | }; |
445 | 451 | ||
@@ -467,8 +473,19 @@ static struct ata_port_operations nv_adma_ops = { | |||
467 | .host_stop = nv_adma_host_stop, | 473 | .host_stop = nv_adma_host_stop, |
468 | }; | 474 | }; |
469 | 475 | ||
476 | /* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to | ||
477 | * work, hardreset should be used and hardreset can't report proper | ||
478 | * signature, which suggests that mcp5x is closer to nf2 as long as | ||
479 | * reset quirkiness is concerned. Define separate ops for mcp5x with | ||
480 | * nv_noclassify_hardreset(). | ||
481 | */ | ||
482 | static struct ata_port_operations nv_mcp5x_ops = { | ||
483 | .inherits = &nv_common_ops, | ||
484 | .hardreset = nv_noclassify_hardreset, | ||
485 | }; | ||
486 | |||
470 | static struct ata_port_operations nv_swncq_ops = { | 487 | static struct ata_port_operations nv_swncq_ops = { |
471 | .inherits = &nv_generic_ops, | 488 | .inherits = &nv_mcp5x_ops, |
472 | 489 | ||
473 | .qc_defer = ata_std_qc_defer, | 490 | .qc_defer = ata_std_qc_defer, |
474 | .qc_prep = nv_swncq_qc_prep, | 491 | .qc_prep = nv_swncq_qc_prep, |
@@ -531,6 +548,15 @@ static const struct ata_port_info nv_port_info[] = { | |||
531 | .port_ops = &nv_adma_ops, | 548 | .port_ops = &nv_adma_ops, |
532 | .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), | 549 | .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), |
533 | }, | 550 | }, |
551 | /* MCP5x */ | ||
552 | { | ||
553 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | ||
554 | .pio_mask = NV_PIO_MASK, | ||
555 | .mwdma_mask = NV_MWDMA_MASK, | ||
556 | .udma_mask = NV_UDMA_MASK, | ||
557 | .port_ops = &nv_mcp5x_ops, | ||
558 | .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), | ||
559 | }, | ||
534 | /* SWNCQ */ | 560 | /* SWNCQ */ |
535 | { | 561 | { |
536 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 562 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
@@ -1530,6 +1556,17 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) | |||
1530 | return 0; | 1556 | return 0; |
1531 | } | 1557 | } |
1532 | 1558 | ||
1559 | static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, | ||
1560 | unsigned long deadline) | ||
1561 | { | ||
1562 | bool online; | ||
1563 | int rc; | ||
1564 | |||
1565 | rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, | ||
1566 | &online, NULL); | ||
1567 | return online ? -EAGAIN : rc; | ||
1568 | } | ||
1569 | |||
1533 | static void nv_nf2_freeze(struct ata_port *ap) | 1570 | static void nv_nf2_freeze(struct ata_port *ap) |
1534 | { | 1571 | { |
1535 | void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; | 1572 | void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; |
@@ -1554,17 +1591,6 @@ static void nv_nf2_thaw(struct ata_port *ap) | |||
1554 | iowrite8(mask, scr_addr + NV_INT_ENABLE); | 1591 | iowrite8(mask, scr_addr + NV_INT_ENABLE); |
1555 | } | 1592 | } |
1556 | 1593 | ||
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) | 1594 | static void nv_ck804_freeze(struct ata_port *ap) |
1569 | { | 1595 | { |
1570 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; | 1596 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; |
@@ -2355,14 +2381,9 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2355 | if (type == CK804 && adma_enabled) { | 2381 | if (type == CK804 && adma_enabled) { |
2356 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); | 2382 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); |
2357 | type = ADMA; | 2383 | type = ADMA; |
2358 | } | 2384 | } else if (type == MCP5x && swncq_enabled) { |
2359 | 2385 | dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); | |
2360 | if (type == SWNCQ) { | 2386 | type = SWNCQ; |
2361 | if (swncq_enabled) | ||
2362 | dev_printk(KERN_NOTICE, &pdev->dev, | ||
2363 | "Using SWNCQ mode\n"); | ||
2364 | else | ||
2365 | type = GENERIC; | ||
2366 | } | 2387 | } |
2367 | 2388 | ||
2368 | ppi[0] = &nv_port_info[type]; | 2389 | ppi[0] = &nv_port_info[type]; |