aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sata_mv.c
diff options
context:
space:
mode:
authorBrett Russ <russb@emc.com>2005-10-05 17:08:42 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-10-05 17:16:52 -0400
commitafb0edd922c7ed6e73678730921dfcccebec17e8 (patch)
treecbe655b60569c7a649da8f1b8d6527aa1fca8322 /drivers/scsi/sata_mv.c
parenta939c9631527053aa38aa8795a6f7203c7f20b69 (diff)
[PATCH] libata: Marvell spinlock fixes and simplification
This should fix up lockups that people were seeing due to improper spinlock placement. Also, the start/stop DMA routines put guarded trust in the cached state of DMA. Signed-off-by: Brett Russ <russb@emc.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi/sata_mv.c')
-rw-r--r--drivers/scsi/sata_mv.c58
1 files changed, 24 insertions, 34 deletions
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index ecda7df21142..c3084f8b3ee7 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -35,7 +35,7 @@
35#include <asm/io.h> 35#include <asm/io.h>
36 36
37#define DRV_NAME "sata_mv" 37#define DRV_NAME "sata_mv"
38#define DRV_VERSION "0.22" 38#define DRV_VERSION "0.23"
39 39
40enum { 40enum {
41 /* BAR's are enumerated in terms of pci_resource_start() terms */ 41 /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -406,40 +406,30 @@ static void mv_irq_clear(struct ata_port *ap)
406{ 406{
407} 407}
408 408
409static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp, 409static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
410 struct ata_port *ap)
411{ 410{
412 unsigned long flags; 411 if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
413 412 writelfl(EDMA_EN, base + EDMA_CMD_OFS);
414 spin_lock_irqsave(&ap->host_set->lock, flags); 413 pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
415 414 }
416 writelfl(EDMA_EN, base + EDMA_CMD_OFS); 415 assert(EDMA_EN & readl(base + EDMA_CMD_OFS));
417 pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
418
419 spin_unlock_irqrestore(&ap->host_set->lock, flags);
420} 416}
421 417
422static void mv_stop_dma(struct ata_port *ap) 418static void mv_stop_dma(struct ata_port *ap)
423{ 419{
424 void __iomem *port_mmio = mv_ap_base(ap); 420 void __iomem *port_mmio = mv_ap_base(ap);
425 struct mv_port_priv *pp = ap->private_data; 421 struct mv_port_priv *pp = ap->private_data;
426 unsigned long flags;
427 u32 reg; 422 u32 reg;
428 int i; 423 int i;
429 424
430 spin_lock_irqsave(&ap->host_set->lock, flags); 425 if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
431 426 /* Disable EDMA if active. The disable bit auto clears.
432 if (!(MV_PP_FLAG_EDMA_DS_ACT & pp->pp_flags) &&
433 ((MV_PP_FLAG_EDMA_EN & pp->pp_flags) ||
434 (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)))) {
435 /* Disable EDMA if we're not already trying to disable it
436 * and it is currently active. The disable bit auto clears.
437 */ 427 */
438 pp->pp_flags |= MV_PP_FLAG_EDMA_DS_ACT;
439 writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); 428 writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
440 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; 429 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
441 } 430 } else {
442 spin_unlock_irqrestore(&ap->host_set->lock, flags); 431 assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
432 }
443 433
444 /* now properly wait for the eDMA to stop */ 434 /* now properly wait for the eDMA to stop */
445 for (i = 1000; i > 0; i--) { 435 for (i = 1000; i > 0; i--) {
@@ -450,12 +440,9 @@ static void mv_stop_dma(struct ata_port *ap)
450 udelay(100); 440 udelay(100);
451 } 441 }
452 442
453 spin_lock_irqsave(&ap->host_set->lock, flags);
454 pp->pp_flags &= ~MV_PP_FLAG_EDMA_DS_ACT;
455 spin_unlock_irqrestore(&ap->host_set->lock, flags);
456
457 if (EDMA_EN & reg) { 443 if (EDMA_EN & reg) {
458 printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); 444 printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id);
445 /* FIXME: Consider doing a reset here to recover */
459 } 446 }
460} 447}
461 448
@@ -716,8 +703,11 @@ static void mv_port_stop(struct ata_port *ap)
716{ 703{
717 struct device *dev = ap->host_set->dev; 704 struct device *dev = ap->host_set->dev;
718 struct mv_port_priv *pp = ap->private_data; 705 struct mv_port_priv *pp = ap->private_data;
706 unsigned long flags;
719 707
708 spin_lock_irqsave(&ap->host_set->lock, flags);
720 mv_stop_dma(ap); 709 mv_stop_dma(ap);
710 spin_unlock_irqrestore(&ap->host_set->lock, flags);
721 711
722 ap->private_data = NULL; 712 ap->private_data = NULL;
723 dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); 713 dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
@@ -867,11 +857,7 @@ static int mv_qc_issue(struct ata_queued_cmd *qc)
867 857
868 mv_inc_q_index(&pp->req_producer); /* now incr producer index */ 858 mv_inc_q_index(&pp->req_producer); /* now incr producer index */
869 859
870 if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { 860 mv_start_dma(port_mmio, pp);
871 /* turn on EDMA if not already on */
872 mv_start_dma(port_mmio, pp, qc->ap);
873 }
874 assert(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
875 861
876 /* and write the request in pointer to kick the EDMA to life */ 862 /* and write the request in pointer to kick the EDMA to life */
877 in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; 863 in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
@@ -921,8 +907,12 @@ static void mv_err_intr(struct ata_port *ap)
921 serr = scr_read(ap, SCR_ERROR); 907 serr = scr_read(ap, SCR_ERROR);
922 scr_write_flush(ap, SCR_ERROR, serr); 908 scr_write_flush(ap, SCR_ERROR, serr);
923 } 909 }
924 DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", 910 if (EDMA_ERR_SELF_DIS & edma_err_cause) {
925 ap->port_no, edma_err_cause, serr); 911 struct mv_port_priv *pp = ap->private_data;
912 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
913 }
914 DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
915 "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
926 916
927 /* Clear EDMA now that SERR cleanup done */ 917 /* Clear EDMA now that SERR cleanup done */
928 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 918 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -1034,7 +1024,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
1034 printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", 1024 printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
1035 readl(mmio + PCI_IRQ_CAUSE_OFS)); 1025 readl(mmio + PCI_IRQ_CAUSE_OFS));
1036 1026
1037 VPRINTK("All regs @ PCI error\n"); 1027 DPRINTK("All regs @ PCI error\n");
1038 mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev)); 1028 mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev));
1039 1029
1040 writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); 1030 writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);