diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/sata_nv.c | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index e2e795e58236..a097595d4dc7 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c | |||
@@ -257,6 +257,8 @@ static void nv_adma_port_stop(struct ata_port *ap); | |||
257 | static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg); | 257 | static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg); |
258 | static int nv_adma_port_resume(struct ata_port *ap); | 258 | static int nv_adma_port_resume(struct ata_port *ap); |
259 | #endif | 259 | #endif |
260 | static void nv_adma_freeze(struct ata_port *ap); | ||
261 | static void nv_adma_thaw(struct ata_port *ap); | ||
260 | static void nv_adma_error_handler(struct ata_port *ap); | 262 | static void nv_adma_error_handler(struct ata_port *ap); |
261 | static void nv_adma_host_stop(struct ata_host *host); | 263 | static void nv_adma_host_stop(struct ata_host *host); |
262 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); | 264 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); |
@@ -444,8 +446,8 @@ static const struct ata_port_operations nv_adma_ops = { | |||
444 | .bmdma_status = ata_bmdma_status, | 446 | .bmdma_status = ata_bmdma_status, |
445 | .qc_prep = nv_adma_qc_prep, | 447 | .qc_prep = nv_adma_qc_prep, |
446 | .qc_issue = nv_adma_qc_issue, | 448 | .qc_issue = nv_adma_qc_issue, |
447 | .freeze = nv_ck804_freeze, | 449 | .freeze = nv_adma_freeze, |
448 | .thaw = nv_ck804_thaw, | 450 | .thaw = nv_adma_thaw, |
449 | .error_handler = nv_adma_error_handler, | 451 | .error_handler = nv_adma_error_handler, |
450 | .post_internal_cmd = nv_adma_post_internal_cmd, | 452 | .post_internal_cmd = nv_adma_post_internal_cmd, |
451 | .data_xfer = ata_data_xfer, | 453 | .data_xfer = ata_data_xfer, |
@@ -815,8 +817,16 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) | |||
815 | u16 status; | 817 | u16 status; |
816 | u32 gen_ctl; | 818 | u32 gen_ctl; |
817 | u32 notifier, notifier_error; | 819 | u32 notifier, notifier_error; |
820 | |||
821 | /* if ADMA is disabled, use standard ata interrupt handler */ | ||
822 | if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) { | ||
823 | u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) | ||
824 | >> (NV_INT_PORT_SHIFT * i); | ||
825 | handled += nv_host_intr(ap, irq_stat); | ||
826 | continue; | ||
827 | } | ||
818 | 828 | ||
819 | /* if in ATA register mode, use standard ata interrupt handler */ | 829 | /* if in ATA register mode, check for standard interrupts */ |
820 | if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { | 830 | if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { |
821 | u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) | 831 | u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) |
822 | >> (NV_INT_PORT_SHIFT * i); | 832 | >> (NV_INT_PORT_SHIFT * i); |
@@ -826,7 +836,6 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) | |||
826 | command is active, to prevent losing interrupts. */ | 836 | command is active, to prevent losing interrupts. */ |
827 | irq_stat |= NV_INT_DEV; | 837 | irq_stat |= NV_INT_DEV; |
828 | handled += nv_host_intr(ap, irq_stat); | 838 | handled += nv_host_intr(ap, irq_stat); |
829 | continue; | ||
830 | } | 839 | } |
831 | 840 | ||
832 | notifier = readl(mmio + NV_ADMA_NOTIFIER); | 841 | notifier = readl(mmio + NV_ADMA_NOTIFIER); |
@@ -912,22 +921,77 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) | |||
912 | return IRQ_RETVAL(handled); | 921 | return IRQ_RETVAL(handled); |
913 | } | 922 | } |
914 | 923 | ||
924 | static void nv_adma_freeze(struct ata_port *ap) | ||
925 | { | ||
926 | struct nv_adma_port_priv *pp = ap->private_data; | ||
927 | void __iomem *mmio = pp->ctl_block; | ||
928 | u16 tmp; | ||
929 | |||
930 | nv_ck804_freeze(ap); | ||
931 | |||
932 | if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) | ||
933 | return; | ||
934 | |||
935 | /* clear any outstanding CK804 notifications */ | ||
936 | writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT), | ||
937 | ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804); | ||
938 | |||
939 | /* Disable interrupt */ | ||
940 | tmp = readw(mmio + NV_ADMA_CTL); | ||
941 | writew( tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN), | ||
942 | mmio + NV_ADMA_CTL); | ||
943 | readw( mmio + NV_ADMA_CTL ); /* flush posted write */ | ||
944 | } | ||
945 | |||
946 | static void nv_adma_thaw(struct ata_port *ap) | ||
947 | { | ||
948 | struct nv_adma_port_priv *pp = ap->private_data; | ||
949 | void __iomem *mmio = pp->ctl_block; | ||
950 | u16 tmp; | ||
951 | |||
952 | nv_ck804_thaw(ap); | ||
953 | |||
954 | if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) | ||
955 | return; | ||
956 | |||
957 | /* Enable interrupt */ | ||
958 | tmp = readw(mmio + NV_ADMA_CTL); | ||
959 | writew( tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN), | ||
960 | mmio + NV_ADMA_CTL); | ||
961 | readw( mmio + NV_ADMA_CTL ); /* flush posted write */ | ||
962 | } | ||
963 | |||
915 | static void nv_adma_irq_clear(struct ata_port *ap) | 964 | static void nv_adma_irq_clear(struct ata_port *ap) |
916 | { | 965 | { |
917 | struct nv_adma_port_priv *pp = ap->private_data; | 966 | struct nv_adma_port_priv *pp = ap->private_data; |
918 | void __iomem *mmio = pp->ctl_block; | 967 | void __iomem *mmio = pp->ctl_block; |
919 | u16 status = readw(mmio + NV_ADMA_STAT); | 968 | u32 notifier_clears[2]; |
920 | u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); | ||
921 | u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); | ||
922 | void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; | ||
923 | 969 | ||
924 | /* clear ADMA status */ | 970 | if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) { |
925 | writew(status, mmio + NV_ADMA_STAT); | 971 | ata_bmdma_irq_clear(ap); |
926 | writel(notifier | notifier_error, | 972 | return; |
927 | pp->notifier_clear_block); | 973 | } |
974 | |||
975 | /* clear any outstanding CK804 notifications */ | ||
976 | writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT), | ||
977 | ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804); | ||
928 | 978 | ||
929 | /** clear legacy status */ | 979 | /* clear ADMA status */ |
930 | iowrite8(ioread8(dma_stat_addr), dma_stat_addr); | 980 | writew(0xffff, mmio + NV_ADMA_STAT); |
981 | |||
982 | /* clear notifiers - note both ports need to be written with | ||
983 | something even though we are only clearing on one */ | ||
984 | if (ap->port_no == 0) { | ||
985 | notifier_clears[0] = 0xFFFFFFFF; | ||
986 | notifier_clears[1] = 0; | ||
987 | } else { | ||
988 | notifier_clears[0] = 0; | ||
989 | notifier_clears[1] = 0xFFFFFFFF; | ||
990 | } | ||
991 | pp = ap->host->ports[0]->private_data; | ||
992 | writel(notifier_clears[0], pp->notifier_clear_block); | ||
993 | pp = ap->host->ports[1]->private_data; | ||
994 | writel(notifier_clears[1], pp->notifier_clear_block); | ||
931 | } | 995 | } |
932 | 996 | ||
933 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc) | 997 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc) |