|
@@ -49,7 +49,7 @@
|
|
#include <linux/libata.h>
|
|
#include <linux/libata.h>
|
|
|
|
|
|
#define DRV_NAME "sata_nv"
|
|
#define DRV_NAME "sata_nv"
|
|
-#define DRV_VERSION "3.2"
|
|
|
|
|
|
+#define DRV_VERSION "3.3"
|
|
|
|
|
|
#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL
|
|
#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL
|
|
|
|
|
|
@@ -213,12 +213,21 @@ struct nv_adma_port_priv {
|
|
dma_addr_t cpb_dma;
|
|
dma_addr_t cpb_dma;
|
|
struct nv_adma_prd *aprd;
|
|
struct nv_adma_prd *aprd;
|
|
dma_addr_t aprd_dma;
|
|
dma_addr_t aprd_dma;
|
|
|
|
+ void __iomem * ctl_block;
|
|
|
|
+ void __iomem * gen_block;
|
|
|
|
+ void __iomem * notifier_clear_block;
|
|
u8 flags;
|
|
u8 flags;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct nv_host_priv {
|
|
|
|
+ unsigned long type;
|
|
|
|
+};
|
|
|
|
+
|
|
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
|
|
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
|
|
|
|
|
|
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
|
|
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
|
|
|
|
+static void nv_remove_one (struct pci_dev *pdev);
|
|
|
|
+static int nv_pci_device_resume(struct pci_dev *pdev);
|
|
static void nv_ck804_host_stop(struct ata_host *host);
|
|
static void nv_ck804_host_stop(struct ata_host *host);
|
|
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
|
|
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
|
|
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
|
|
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
|
|
@@ -239,6 +248,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
|
|
static void nv_adma_irq_clear(struct ata_port *ap);
|
|
static void nv_adma_irq_clear(struct ata_port *ap);
|
|
static int nv_adma_port_start(struct ata_port *ap);
|
|
static int nv_adma_port_start(struct ata_port *ap);
|
|
static void nv_adma_port_stop(struct ata_port *ap);
|
|
static void nv_adma_port_stop(struct ata_port *ap);
|
|
|
|
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
|
|
|
|
+static int nv_adma_port_resume(struct ata_port *ap);
|
|
static void nv_adma_error_handler(struct ata_port *ap);
|
|
static void nv_adma_error_handler(struct ata_port *ap);
|
|
static void nv_adma_host_stop(struct ata_host *host);
|
|
static void nv_adma_host_stop(struct ata_host *host);
|
|
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
|
|
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
|
|
@@ -284,7 +295,9 @@ static struct pci_driver nv_pci_driver = {
|
|
.name = DRV_NAME,
|
|
.name = DRV_NAME,
|
|
.id_table = nv_pci_tbl,
|
|
.id_table = nv_pci_tbl,
|
|
.probe = nv_init_one,
|
|
.probe = nv_init_one,
|
|
- .remove = ata_pci_remove_one,
|
|
|
|
|
|
+ .suspend = ata_pci_device_suspend,
|
|
|
|
+ .resume = nv_pci_device_resume,
|
|
|
|
+ .remove = nv_remove_one,
|
|
};
|
|
};
|
|
|
|
|
|
static struct scsi_host_template nv_sht = {
|
|
static struct scsi_host_template nv_sht = {
|
|
@@ -303,6 +316,8 @@ static struct scsi_host_template nv_sht = {
|
|
.slave_configure = ata_scsi_slave_config,
|
|
.slave_configure = ata_scsi_slave_config,
|
|
.slave_destroy = ata_scsi_slave_destroy,
|
|
.slave_destroy = ata_scsi_slave_destroy,
|
|
.bios_param = ata_std_bios_param,
|
|
.bios_param = ata_std_bios_param,
|
|
|
|
+ .suspend = ata_scsi_device_suspend,
|
|
|
|
+ .resume = ata_scsi_device_resume,
|
|
};
|
|
};
|
|
|
|
|
|
static struct scsi_host_template nv_adma_sht = {
|
|
static struct scsi_host_template nv_adma_sht = {
|
|
@@ -321,6 +336,8 @@ static struct scsi_host_template nv_adma_sht = {
|
|
.slave_configure = nv_adma_slave_config,
|
|
.slave_configure = nv_adma_slave_config,
|
|
.slave_destroy = ata_scsi_slave_destroy,
|
|
.slave_destroy = ata_scsi_slave_destroy,
|
|
.bios_param = ata_std_bios_param,
|
|
.bios_param = ata_std_bios_param,
|
|
|
|
+ .suspend = ata_scsi_device_suspend,
|
|
|
|
+ .resume = ata_scsi_device_resume,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct ata_port_operations nv_generic_ops = {
|
|
static const struct ata_port_operations nv_generic_ops = {
|
|
@@ -429,6 +446,8 @@ static const struct ata_port_operations nv_adma_ops = {
|
|
.scr_write = nv_scr_write,
|
|
.scr_write = nv_scr_write,
|
|
.port_start = nv_adma_port_start,
|
|
.port_start = nv_adma_port_start,
|
|
.port_stop = nv_adma_port_stop,
|
|
.port_stop = nv_adma_port_stop,
|
|
|
|
+ .port_suspend = nv_adma_port_suspend,
|
|
|
|
+ .port_resume = nv_adma_port_resume,
|
|
.host_stop = nv_adma_host_stop,
|
|
.host_stop = nv_adma_host_stop,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -467,6 +486,7 @@ static struct ata_port_info nv_port_info[] = {
|
|
{
|
|
{
|
|
.sht = &nv_adma_sht,
|
|
.sht = &nv_adma_sht,
|
|
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
|
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
|
|
|
+ ATA_FLAG_HRST_TO_RESUME |
|
|
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
|
|
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
|
|
.pio_mask = NV_PIO_MASK,
|
|
.pio_mask = NV_PIO_MASK,
|
|
.mwdma_mask = NV_MWDMA_MASK,
|
|
.mwdma_mask = NV_MWDMA_MASK,
|
|
@@ -483,32 +503,10 @@ MODULE_VERSION(DRV_VERSION);
|
|
|
|
|
|
static int adma_enabled = 1;
|
|
static int adma_enabled = 1;
|
|
|
|
|
|
-static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio,
|
|
|
|
- unsigned int port_no)
|
|
|
|
-{
|
|
|
|
- mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE;
|
|
|
|
- return mmio;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap)
|
|
|
|
-{
|
|
|
|
- return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline void __iomem *nv_adma_gen_block(struct ata_port *ap)
|
|
|
|
-{
|
|
|
|
- return (ap->host->mmio_base + NV_ADMA_GEN);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap)
|
|
|
|
-{
|
|
|
|
- return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void nv_adma_register_mode(struct ata_port *ap)
|
|
static void nv_adma_register_mode(struct ata_port *ap)
|
|
{
|
|
{
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
u16 tmp;
|
|
u16 tmp;
|
|
|
|
|
|
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
|
|
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
|
|
@@ -522,8 +520,8 @@ static void nv_adma_register_mode(struct ata_port *ap)
|
|
|
|
|
|
static void nv_adma_mode(struct ata_port *ap)
|
|
static void nv_adma_mode(struct ata_port *ap)
|
|
{
|
|
{
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
u16 tmp;
|
|
u16 tmp;
|
|
|
|
|
|
if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
|
|
if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
|
|
@@ -684,7 +682,7 @@ static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
|
|
For NCQ commands the current status may have nothing to do with
|
|
For NCQ commands the current status may have nothing to do with
|
|
the command just completed. */
|
|
the command just completed. */
|
|
if(qc->tf.protocol != ATA_PROT_NCQ)
|
|
if(qc->tf.protocol != ATA_PROT_NCQ)
|
|
- ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4));
|
|
|
|
|
|
+ ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
|
|
|
|
|
|
if(have_err || force_err)
|
|
if(have_err || force_err)
|
|
ata_status |= ATA_ERR;
|
|
ata_status |= ATA_ERR;
|
|
@@ -735,7 +733,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
|
|
|
|
|
|
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
|
|
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
u16 status;
|
|
u16 status;
|
|
u32 gen_ctl;
|
|
u32 gen_ctl;
|
|
int have_global_err = 0;
|
|
int have_global_err = 0;
|
|
@@ -758,7 +756,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
|
|
notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
notifier_clears[i] = notifier | notifier_error;
|
|
notifier_clears[i] = notifier | notifier_error;
|
|
|
|
|
|
- gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
|
|
|
|
|
|
+ gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
|
|
|
|
|
|
if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
|
|
if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
|
|
!notifier_error)
|
|
!notifier_error)
|
|
@@ -816,10 +814,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
|
|
if(notifier_clears[0] || notifier_clears[1]) {
|
|
if(notifier_clears[0] || notifier_clears[1]) {
|
|
/* Note: Both notifier clear registers must be written
|
|
/* Note: Both notifier clear registers must be written
|
|
if either is set, even if one is zero, according to NVIDIA. */
|
|
if either is set, even if one is zero, according to NVIDIA. */
|
|
- writel(notifier_clears[0],
|
|
|
|
- nv_adma_notifier_clear_block(host->ports[0]));
|
|
|
|
- writel(notifier_clears[1],
|
|
|
|
- nv_adma_notifier_clear_block(host->ports[1]));
|
|
|
|
|
|
+ struct nv_adma_port_priv *pp = host->ports[0]->private_data;
|
|
|
|
+ writel(notifier_clears[0], pp->notifier_clear_block);
|
|
|
|
+ pp = host->ports[1]->private_data;
|
|
|
|
+ writel(notifier_clears[1], pp->notifier_clear_block);
|
|
}
|
|
}
|
|
|
|
|
|
spin_unlock(&host->lock);
|
|
spin_unlock(&host->lock);
|
|
@@ -829,7 +827,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
|
|
|
|
|
|
static void nv_adma_irq_clear(struct ata_port *ap)
|
|
static void nv_adma_irq_clear(struct ata_port *ap)
|
|
{
|
|
{
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
|
|
+ struct nv_adma_port_priv *pp = ap->private_data;
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
u16 status = readw(mmio + NV_ADMA_STAT);
|
|
u16 status = readw(mmio + NV_ADMA_STAT);
|
|
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
|
|
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
|
|
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
@@ -838,7 +837,7 @@ static void nv_adma_irq_clear(struct ata_port *ap)
|
|
/* clear ADMA status */
|
|
/* clear ADMA status */
|
|
writew(status, mmio + NV_ADMA_STAT);
|
|
writew(status, mmio + NV_ADMA_STAT);
|
|
writel(notifier | notifier_error,
|
|
writel(notifier | notifier_error,
|
|
- nv_adma_notifier_clear_block(ap));
|
|
|
|
|
|
+ pp->notifier_clear_block);
|
|
|
|
|
|
/** clear legacy status */
|
|
/** clear legacy status */
|
|
outb(inb(dma_stat_addr), dma_stat_addr);
|
|
outb(inb(dma_stat_addr), dma_stat_addr);
|
|
@@ -920,7 +919,7 @@ static int nv_adma_port_start(struct ata_port *ap)
|
|
int rc;
|
|
int rc;
|
|
void *mem;
|
|
void *mem;
|
|
dma_addr_t mem_dma;
|
|
dma_addr_t mem_dma;
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
|
|
+ void __iomem *mmio;
|
|
u16 tmp;
|
|
u16 tmp;
|
|
|
|
|
|
VPRINTK("ENTER\n");
|
|
VPRINTK("ENTER\n");
|
|
@@ -935,6 +934,13 @@ static int nv_adma_port_start(struct ata_port *ap)
|
|
goto err_out;
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ mmio = ap->host->mmio_base + NV_ADMA_PORT +
|
|
|
|
+ ap->port_no * NV_ADMA_PORT_SIZE;
|
|
|
|
+ pp->ctl_block = mmio;
|
|
|
|
+ pp->gen_block = ap->host->mmio_base + NV_ADMA_GEN;
|
|
|
|
+ pp->notifier_clear_block = pp->gen_block +
|
|
|
|
+ NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
|
|
|
|
+
|
|
mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
|
|
mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
|
|
&mem_dma, GFP_KERNEL);
|
|
&mem_dma, GFP_KERNEL);
|
|
|
|
|
|
@@ -975,9 +981,9 @@ static int nv_adma_port_start(struct ata_port *ap)
|
|
/* clear CPB fetch count */
|
|
/* clear CPB fetch count */
|
|
writew(0, mmio + NV_ADMA_CPB_COUNT);
|
|
writew(0, mmio + NV_ADMA_CPB_COUNT);
|
|
|
|
|
|
- /* clear GO for register mode */
|
|
|
|
|
|
+ /* clear GO for register mode, enable interrupt */
|
|
tmp = readw(mmio + NV_ADMA_CTL);
|
|
tmp = readw(mmio + NV_ADMA_CTL);
|
|
- writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
|
|
|
|
|
|
+ writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
|
|
|
|
|
|
tmp = readw(mmio + NV_ADMA_CTL);
|
|
tmp = readw(mmio + NV_ADMA_CTL);
|
|
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
|
|
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
|
|
@@ -999,7 +1005,7 @@ static void nv_adma_port_stop(struct ata_port *ap)
|
|
{
|
|
{
|
|
struct device *dev = ap->host->dev;
|
|
struct device *dev = ap->host->dev;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
|
|
|
|
VPRINTK("ENTER\n");
|
|
VPRINTK("ENTER\n");
|
|
|
|
|
|
@@ -1011,6 +1017,55 @@ static void nv_adma_port_stop(struct ata_port *ap)
|
|
ata_port_stop(ap);
|
|
ata_port_stop(ap);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
|
|
|
|
+{
|
|
|
|
+ struct nv_adma_port_priv *pp = ap->private_data;
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
|
|
+
|
|
|
|
+ /* Go to register mode - clears GO */
|
|
|
|
+ nv_adma_register_mode(ap);
|
|
|
|
+
|
|
|
|
+ /* clear CPB fetch count */
|
|
|
|
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
|
|
|
|
+
|
|
|
|
+ /* disable interrupt, shut down port */
|
|
|
|
+ writew(0, mmio + NV_ADMA_CTL);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nv_adma_port_resume(struct ata_port *ap)
|
|
|
|
+{
|
|
|
|
+ struct nv_adma_port_priv *pp = ap->private_data;
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
|
|
+ u16 tmp;
|
|
|
|
+
|
|
|
|
+ /* set CPB block location */
|
|
|
|
+ writel(pp->cpb_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW);
|
|
|
|
+ writel((pp->cpb_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
|
|
|
|
+
|
|
|
|
+ /* clear any outstanding interrupt conditions */
|
|
|
|
+ writew(0xffff, mmio + NV_ADMA_STAT);
|
|
|
|
+
|
|
|
|
+ /* initialize port variables */
|
|
|
|
+ pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
|
|
|
|
+
|
|
|
|
+ /* clear CPB fetch count */
|
|
|
|
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
|
|
|
|
+
|
|
|
|
+ /* clear GO for register mode, enable interrupt */
|
|
|
|
+ tmp = readw(mmio + NV_ADMA_CTL);
|
|
|
|
+ writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
|
|
|
|
+
|
|
|
|
+ tmp = readw(mmio + NV_ADMA_CTL);
|
|
|
|
+ writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
|
|
|
|
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
|
|
|
|
+ udelay(1);
|
|
|
|
+ writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
|
|
|
|
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
|
|
static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
|
|
static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
|
|
{
|
|
{
|
|
@@ -1056,15 +1111,6 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
|
|
for (i = 0; i < probe_ent->n_ports; i++)
|
|
for (i = 0; i < probe_ent->n_ports; i++)
|
|
nv_adma_setup_port(probe_ent, i);
|
|
nv_adma_setup_port(probe_ent, i);
|
|
|
|
|
|
- for (i = 0; i < probe_ent->n_ports; i++) {
|
|
|
|
- void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);
|
|
|
|
- u16 tmp;
|
|
|
|
-
|
|
|
|
- /* enable interrupt, clear reset if not already clear */
|
|
|
|
- tmp = readw(mmio + NV_ADMA_CTL);
|
|
|
|
- writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1118,8 +1164,6 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
|
|
NV_CPB_CTL_APRD_VALID |
|
|
NV_CPB_CTL_APRD_VALID |
|
|
NV_CPB_CTL_IEN;
|
|
NV_CPB_CTL_IEN;
|
|
|
|
|
|
- VPRINTK("qc->flags = 0x%lx\n", qc->flags);
|
|
|
|
-
|
|
|
|
if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
|
|
if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
|
|
(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
|
|
(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
|
|
nv_adma_register_mode(qc->ap);
|
|
nv_adma_register_mode(qc->ap);
|
|
@@ -1137,6 +1181,8 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
|
|
if (qc->tf.protocol == ATA_PROT_NCQ)
|
|
if (qc->tf.protocol == ATA_PROT_NCQ)
|
|
ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;
|
|
ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;
|
|
|
|
|
|
|
|
+ VPRINTK("qc->flags = 0x%lx\n", qc->flags);
|
|
|
|
+
|
|
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
|
|
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
|
|
|
|
|
|
nv_adma_fill_sg(qc, cpb);
|
|
nv_adma_fill_sg(qc, cpb);
|
|
@@ -1150,7 +1196,7 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
|
|
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
|
|
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
|
|
{
|
|
{
|
|
struct nv_adma_port_priv *pp = qc->ap->private_data;
|
|
struct nv_adma_port_priv *pp = qc->ap->private_data;
|
|
- void __iomem *mmio = nv_adma_ctl_block(qc->ap);
|
|
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
|
|
|
|
VPRINTK("ENTER\n");
|
|
VPRINTK("ENTER\n");
|
|
|
|
|
|
@@ -1335,13 +1381,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
|
|
{
|
|
{
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
struct nv_adma_port_priv *pp = ap->private_data;
|
|
if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
|
|
if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
|
|
- void __iomem *mmio = nv_adma_ctl_block(ap);
|
|
|
|
|
|
+ void __iomem *mmio = pp->ctl_block;
|
|
int i;
|
|
int i;
|
|
u16 tmp;
|
|
u16 tmp;
|
|
|
|
|
|
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
|
|
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
|
|
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
|
|
- u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
|
|
|
|
|
|
+ u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
|
|
u32 status = readw(mmio + NV_ADMA_STAT);
|
|
u32 status = readw(mmio + NV_ADMA_STAT);
|
|
|
|
|
|
ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
|
|
ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
|
|
@@ -1386,6 +1432,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
static int printed_version = 0;
|
|
static int printed_version = 0;
|
|
struct ata_port_info *ppi[2];
|
|
struct ata_port_info *ppi[2];
|
|
struct ata_probe_ent *probe_ent;
|
|
struct ata_probe_ent *probe_ent;
|
|
|
|
+ struct nv_host_priv *hpriv;
|
|
int pci_dev_busy = 0;
|
|
int pci_dev_busy = 0;
|
|
int rc;
|
|
int rc;
|
|
u32 bar;
|
|
u32 bar;
|
|
@@ -1400,7 +1447,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
if (pci_resource_start(pdev, bar) == 0)
|
|
if (pci_resource_start(pdev, bar) == 0)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
- if ( !printed_version++)
|
|
|
|
|
|
+ if (!printed_version++)
|
|
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
|
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
|
|
|
|
|
rc = pci_enable_device(pdev);
|
|
rc = pci_enable_device(pdev);
|
|
@@ -1432,6 +1479,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
|
|
rc = -ENOMEM;
|
|
rc = -ENOMEM;
|
|
|
|
|
|
|
|
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
|
|
|
|
+ if (!hpriv)
|
|
|
|
+ goto err_out_regions;
|
|
|
|
+
|
|
ppi[0] = ppi[1] = &nv_port_info[type];
|
|
ppi[0] = ppi[1] = &nv_port_info[type];
|
|
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
|
|
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
|
|
if (!probe_ent)
|
|
if (!probe_ent)
|
|
@@ -1442,6 +1493,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
rc = -EIO;
|
|
rc = -EIO;
|
|
goto err_out_free_ent;
|
|
goto err_out_free_ent;
|
|
}
|
|
}
|
|
|
|
+ probe_ent->private_data = hpriv;
|
|
|
|
+ hpriv->type = type;
|
|
|
|
|
|
base = (unsigned long)probe_ent->mmio_base;
|
|
base = (unsigned long)probe_ent->mmio_base;
|
|
|
|
|
|
@@ -1486,6 +1539,60 @@ err_out:
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void nv_remove_one (struct pci_dev *pdev)
|
|
|
|
+{
|
|
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
|
|
+ struct nv_host_priv *hpriv = host->private_data;
|
|
|
|
+
|
|
|
|
+ ata_pci_remove_one(pdev);
|
|
|
|
+ kfree(hpriv);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nv_pci_device_resume(struct pci_dev *pdev)
|
|
|
|
+{
|
|
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
|
|
+ struct nv_host_priv *hpriv = host->private_data;
|
|
|
|
+
|
|
|
|
+ ata_pci_device_do_resume(pdev);
|
|
|
|
+
|
|
|
|
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
|
|
|
|
+ if(hpriv->type >= CK804) {
|
|
|
|
+ u8 regval;
|
|
|
|
+
|
|
|
|
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val);
|
|
|
|
+ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
|
|
|
|
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
|
|
|
|
+ }
|
|
|
|
+ if(hpriv->type == ADMA) {
|
|
|
|
+ u32 tmp32;
|
|
|
|
+ struct nv_adma_port_priv *pp;
|
|
|
|
+ /* enable/disable ADMA on the ports appropriately */
|
|
|
|
+ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
|
|
|
|
+
|
|
|
|
+ pp = host->ports[0]->private_data;
|
|
|
|
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
|
|
|
|
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
|
|
|
|
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
|
|
|
|
+ else
|
|
|
|
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN |
|
|
|
|
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
|
|
|
|
+ pp = host->ports[1]->private_data;
|
|
|
|
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
|
|
|
|
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN |
|
|
|
|
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
|
|
|
|
+ else
|
|
|
|
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT1_EN |
|
|
|
|
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
|
|
|
|
+
|
|
|
|
+ pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ata_host_resume(host);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void nv_ck804_host_stop(struct ata_host *host)
|
|
static void nv_ck804_host_stop(struct ata_host *host)
|
|
{
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
@@ -1502,18 +1609,8 @@ static void nv_ck804_host_stop(struct ata_host *host)
|
|
static void nv_adma_host_stop(struct ata_host *host)
|
|
static void nv_adma_host_stop(struct ata_host *host)
|
|
{
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
- int i;
|
|
|
|
u32 tmp32;
|
|
u32 tmp32;
|
|
|
|
|
|
- for (i = 0; i < host->n_ports; i++) {
|
|
|
|
- void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i);
|
|
|
|
- u16 tmp;
|
|
|
|
-
|
|
|
|
- /* disable interrupt */
|
|
|
|
- tmp = readw(mmio + NV_ADMA_CTL);
|
|
|
|
- writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* disable ADMA on the ports */
|
|
/* disable ADMA on the ports */
|
|
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
|
|
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
|
|
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
|
|
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
|