Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev: libata: Don't fail device revalidation for bad _GTF methods libata: port and host should be stopped before hardware resources are released libata: skip 0xff polling for PATA controllers libata: pata_platform: Support polling-mode configuration. libata: Support PIO polling-only hosts. libata sata_qstor conversion to new error handling (EH). libata sata_qstor workaround for spurious interrupts libata sata_qstor nuke idle state nv_hardreset: update dangling reference to bugzilla entry ata_piix: add SATELLITE PRO U200 to broken suspend list
This commit is contained in:
commit
487350e443
@ -959,6 +959,13 @@ static int piix_broken_suspend(void)
|
|||||||
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
|
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.ident = "Satellite Pro U200",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.ident = "Satellite U205",
|
.ident = "Satellite U205",
|
||||||
.matches = {
|
.matches = {
|
||||||
|
@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm);
|
|||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
* Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't
|
* Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't
|
||||||
* contain valid data. -errno on other errors.
|
* contain valid data.
|
||||||
*/
|
*/
|
||||||
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
|
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
|
||||||
void **ptr_to_free)
|
void **ptr_to_free)
|
||||||
@ -339,7 +339,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
|
|||||||
ata_dev_printk(dev, KERN_WARNING,
|
ata_dev_printk(dev, KERN_WARNING,
|
||||||
"_GTF evaluation failed (AE 0x%x)\n",
|
"_GTF evaluation failed (AE 0x%x)\n",
|
||||||
status);
|
status);
|
||||||
rc = -EIO;
|
|
||||||
}
|
}
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
@ -359,7 +358,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
|
|||||||
ata_dev_printk(dev, KERN_WARNING,
|
ata_dev_printk(dev, KERN_WARNING,
|
||||||
"_GTF unexpected object type 0x%x\n",
|
"_GTF unexpected object type 0x%x\n",
|
||||||
out_obj->type);
|
out_obj->type);
|
||||||
rc = -EINVAL;
|
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +365,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
|
|||||||
ata_dev_printk(dev, KERN_WARNING,
|
ata_dev_printk(dev, KERN_WARNING,
|
||||||
"unexpected _GTF length (%d)\n",
|
"unexpected _GTF length (%d)\n",
|
||||||
out_obj->buffer.length);
|
out_obj->buffer.length);
|
||||||
rc = -EINVAL;
|
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,10 +508,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
|
|||||||
int gtf_count, i, rc;
|
int gtf_count, i, rc;
|
||||||
|
|
||||||
/* get taskfiles */
|
/* get taskfiles */
|
||||||
rc = ata_dev_get_GTF(dev, >f, &ptr_to_free);
|
gtf_count = ata_dev_get_GTF(dev, >f, &ptr_to_free);
|
||||||
if (rc < 0)
|
|
||||||
return rc;
|
|
||||||
gtf_count = rc;
|
|
||||||
|
|
||||||
/* execute them */
|
/* execute them */
|
||||||
for (i = 0, rc = 0; i < gtf_count; i++) {
|
for (i = 0, rc = 0; i < gtf_count; i++) {
|
||||||
|
@ -3373,14 +3373,20 @@ void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline)
|
|||||||
* to clear 0xff after reset. For example, HHD424020F7SV00
|
* to clear 0xff after reset. For example, HHD424020F7SV00
|
||||||
* iVDR needs >= 800ms while. Quantum GoVault needs even more
|
* iVDR needs >= 800ms while. Quantum GoVault needs even more
|
||||||
* than that.
|
* than that.
|
||||||
|
*
|
||||||
|
* Note that some PATA controllers (pata_ali) explode if
|
||||||
|
* status register is read more than once when there's no
|
||||||
|
* device attached.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
if (ap->flags & ATA_FLAG_SATA) {
|
||||||
u8 status = ata_chk_status(ap);
|
while (1) {
|
||||||
|
u8 status = ata_chk_status(ap);
|
||||||
|
|
||||||
if (status != 0xff || time_after(jiffies, deadline))
|
if (status != 0xff || time_after(jiffies, deadline))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
msleep(50);
|
msleep(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6815,19 +6821,6 @@ static void ata_host_release(struct device *gendev, void *res)
|
|||||||
struct ata_host *host = dev_get_drvdata(gendev);
|
struct ata_host *host = dev_get_drvdata(gendev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < host->n_ports; i++) {
|
|
||||||
struct ata_port *ap = host->ports[i];
|
|
||||||
|
|
||||||
if (!ap)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
|
|
||||||
ap->ops->port_stop(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
|
|
||||||
host->ops->host_stop(host);
|
|
||||||
|
|
||||||
for (i = 0; i < host->n_ports; i++) {
|
for (i = 0; i < host->n_ports; i++) {
|
||||||
struct ata_port *ap = host->ports[i];
|
struct ata_port *ap = host->ports[i];
|
||||||
|
|
||||||
@ -6960,6 +6953,24 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
|
|||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ata_host_stop(struct device *gendev, void *res)
|
||||||
|
{
|
||||||
|
struct ata_host *host = dev_get_drvdata(gendev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
WARN_ON(!(host->flags & ATA_HOST_STARTED));
|
||||||
|
|
||||||
|
for (i = 0; i < host->n_ports; i++) {
|
||||||
|
struct ata_port *ap = host->ports[i];
|
||||||
|
|
||||||
|
if (ap->ops->port_stop)
|
||||||
|
ap->ops->port_stop(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host->ops->host_stop)
|
||||||
|
host->ops->host_stop(host);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_host_start - start and freeze ports of an ATA host
|
* ata_host_start - start and freeze ports of an ATA host
|
||||||
* @host: ATA host to start ports for
|
* @host: ATA host to start ports for
|
||||||
@ -6978,6 +6989,8 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
|
|||||||
*/
|
*/
|
||||||
int ata_host_start(struct ata_host *host)
|
int ata_host_start(struct ata_host *host)
|
||||||
{
|
{
|
||||||
|
int have_stop = 0;
|
||||||
|
void *start_dr = NULL;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
|
||||||
if (host->flags & ATA_HOST_STARTED)
|
if (host->flags & ATA_HOST_STARTED)
|
||||||
@ -6989,6 +7002,22 @@ int ata_host_start(struct ata_host *host)
|
|||||||
if (!host->ops && !ata_port_is_dummy(ap))
|
if (!host->ops && !ata_port_is_dummy(ap))
|
||||||
host->ops = ap->ops;
|
host->ops = ap->ops;
|
||||||
|
|
||||||
|
if (ap->ops->port_stop)
|
||||||
|
have_stop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host->ops->host_stop)
|
||||||
|
have_stop = 1;
|
||||||
|
|
||||||
|
if (have_stop) {
|
||||||
|
start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL);
|
||||||
|
if (!start_dr)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < host->n_ports; i++) {
|
||||||
|
struct ata_port *ap = host->ports[i];
|
||||||
|
|
||||||
if (ap->ops->port_start) {
|
if (ap->ops->port_start) {
|
||||||
rc = ap->ops->port_start(ap);
|
rc = ap->ops->port_start(ap);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@ -7001,6 +7030,8 @@ int ata_host_start(struct ata_host *host)
|
|||||||
ata_eh_freeze_port(ap);
|
ata_eh_freeze_port(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (start_dr)
|
||||||
|
devres_add(host->dev, start_dr);
|
||||||
host->flags |= ATA_HOST_STARTED;
|
host->flags |= ATA_HOST_STARTED;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -7011,6 +7042,7 @@ int ata_host_start(struct ata_host *host)
|
|||||||
if (ap->ops->port_stop)
|
if (ap->ops->port_stop)
|
||||||
ap->ops->port_stop(ap);
|
ap->ops->port_stop(ap);
|
||||||
}
|
}
|
||||||
|
devres_free(start_dr);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7178,6 +7210,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
|
|||||||
* request IRQ and register it. This helper takes necessasry
|
* request IRQ and register it. This helper takes necessasry
|
||||||
* arguments and performs the three steps in one go.
|
* arguments and performs the three steps in one go.
|
||||||
*
|
*
|
||||||
|
* An invalid IRQ skips the IRQ registration and expects the host to
|
||||||
|
* have set polling mode on the port. In this case, @irq_handler
|
||||||
|
* should be NULL.
|
||||||
|
*
|
||||||
* LOCKING:
|
* LOCKING:
|
||||||
* Inherited from calling layer (may sleep).
|
* Inherited from calling layer (may sleep).
|
||||||
*
|
*
|
||||||
@ -7194,6 +7230,12 @@ int ata_host_activate(struct ata_host *host, int irq,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* Special case for polling mode */
|
||||||
|
if (!irq) {
|
||||||
|
WARN_ON(irq_handler);
|
||||||
|
return ata_host_register(host, sht);
|
||||||
|
}
|
||||||
|
|
||||||
rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
|
rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
|
||||||
dev_driver_string(host->dev), host);
|
dev_driver_string(host->dev), host);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Generic platform device PATA driver
|
* Generic platform device PATA driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Paul Mundt
|
* Copyright (C) 2006 - 2007 Paul Mundt
|
||||||
*
|
*
|
||||||
* Based on pata_pcmcia:
|
* Based on pata_pcmcia:
|
||||||
*
|
*
|
||||||
@ -22,7 +22,7 @@
|
|||||||
#include <linux/pata_platform.h>
|
#include <linux/pata_platform.h>
|
||||||
|
|
||||||
#define DRV_NAME "pata_platform"
|
#define DRV_NAME "pata_platform"
|
||||||
#define DRV_VERSION "1.1"
|
#define DRV_VERSION "1.2"
|
||||||
|
|
||||||
static int pio_mask = 1;
|
static int pio_mask = 1;
|
||||||
|
|
||||||
@ -120,15 +120,20 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
|
|||||||
* Register a platform bus IDE interface. Such interfaces are PIO and we
|
* Register a platform bus IDE interface. Such interfaces are PIO and we
|
||||||
* assume do not support IRQ sharing.
|
* assume do not support IRQ sharing.
|
||||||
*
|
*
|
||||||
* Platform devices are expected to contain 3 resources per port:
|
* Platform devices are expected to contain at least 2 resources per port:
|
||||||
*
|
*
|
||||||
* - I/O Base (IORESOURCE_IO or IORESOURCE_MEM)
|
* - I/O Base (IORESOURCE_IO or IORESOURCE_MEM)
|
||||||
* - CTL Base (IORESOURCE_IO or IORESOURCE_MEM)
|
* - CTL Base (IORESOURCE_IO or IORESOURCE_MEM)
|
||||||
|
*
|
||||||
|
* and optionally:
|
||||||
|
*
|
||||||
* - IRQ (IORESOURCE_IRQ)
|
* - IRQ (IORESOURCE_IRQ)
|
||||||
*
|
*
|
||||||
* If the base resources are both mem types, the ioremap() is handled
|
* If the base resources are both mem types, the ioremap() is handled
|
||||||
* here. For IORESOURCE_IO, it's assumed that there's no remapping
|
* here. For IORESOURCE_IO, it's assumed that there's no remapping
|
||||||
* necessary.
|
* necessary.
|
||||||
|
*
|
||||||
|
* If no IRQ resource is present, PIO polling mode is used instead.
|
||||||
*/
|
*/
|
||||||
static int __devinit pata_platform_probe(struct platform_device *pdev)
|
static int __devinit pata_platform_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
@ -137,11 +142,12 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
|
|||||||
struct ata_port *ap;
|
struct ata_port *ap;
|
||||||
struct pata_platform_info *pp_info;
|
struct pata_platform_info *pp_info;
|
||||||
unsigned int mmio;
|
unsigned int mmio;
|
||||||
|
int irq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simple resource validation ..
|
* Simple resource validation ..
|
||||||
*/
|
*/
|
||||||
if (unlikely(pdev->num_resources != 3)) {
|
if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) {
|
||||||
dev_err(&pdev->dev, "invalid number of resources\n");
|
dev_err(&pdev->dev, "invalid number of resources\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -172,6 +178,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
|
|||||||
mmio = (( io_res->flags == IORESOURCE_MEM) &&
|
mmio = (( io_res->flags == IORESOURCE_MEM) &&
|
||||||
(ctl_res->flags == IORESOURCE_MEM));
|
(ctl_res->flags == IORESOURCE_MEM));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And the IRQ
|
||||||
|
*/
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0)
|
||||||
|
irq = 0; /* no irq */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that that's out of the way, wire up the port..
|
* Now that that's out of the way, wire up the port..
|
||||||
*/
|
*/
|
||||||
@ -184,6 +197,14 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
|
|||||||
ap->pio_mask = pio_mask;
|
ap->pio_mask = pio_mask;
|
||||||
ap->flags |= ATA_FLAG_SLAVE_POSS;
|
ap->flags |= ATA_FLAG_SLAVE_POSS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use polling mode if there's no IRQ
|
||||||
|
*/
|
||||||
|
if (!irq) {
|
||||||
|
ap->flags |= ATA_FLAG_PIO_POLLING;
|
||||||
|
ata_port_desc(ap, "no IRQ, using PIO polling");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the MMIO case
|
* Handle the MMIO case
|
||||||
*/
|
*/
|
||||||
@ -213,9 +234,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
|
|||||||
(unsigned long long)ctl_res->start);
|
(unsigned long long)ctl_res->start);
|
||||||
|
|
||||||
/* activate */
|
/* activate */
|
||||||
return ata_host_activate(host, platform_get_irq(pdev, 0),
|
return ata_host_activate(host, irq, irq ? ata_interrupt : NULL,
|
||||||
ata_interrupt, pp_info ? pp_info->irq_flags
|
pp_info ? pp_info->irq_flags : 0,
|
||||||
: 0, &pata_platform_sht);
|
&pata_platform_sht);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1629,7 +1629,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class,
|
|||||||
|
|
||||||
/* SATA hardreset fails to retrieve proper device signature on
|
/* SATA hardreset fails to retrieve proper device signature on
|
||||||
* some controllers. Don't classify on hardreset. For more
|
* some controllers. Don't classify on hardreset. For more
|
||||||
* info, see http://bugme.osdl.org/show_bug.cgi?id=3352
|
* info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
|
||||||
*/
|
*/
|
||||||
return sata_std_hardreset(link, &dummy, deadline);
|
return sata_std_hardreset(link, &dummy, deadline);
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ enum {
|
|||||||
QS_DMA_BOUNDARY = ~0UL
|
QS_DMA_BOUNDARY = ~0UL
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
|
typedef enum { qs_state_mmio, qs_state_pkt } qs_state_t;
|
||||||
|
|
||||||
struct qs_port_priv {
|
struct qs_port_priv {
|
||||||
u8 *pkt;
|
u8 *pkt;
|
||||||
@ -116,14 +116,15 @@ static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
|
|||||||
static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
|
static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||||
static int qs_port_start(struct ata_port *ap);
|
static int qs_port_start(struct ata_port *ap);
|
||||||
static void qs_host_stop(struct ata_host *host);
|
static void qs_host_stop(struct ata_host *host);
|
||||||
static void qs_phy_reset(struct ata_port *ap);
|
|
||||||
static void qs_qc_prep(struct ata_queued_cmd *qc);
|
static void qs_qc_prep(struct ata_queued_cmd *qc);
|
||||||
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
|
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
|
||||||
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
|
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
|
||||||
static void qs_bmdma_stop(struct ata_queued_cmd *qc);
|
static void qs_bmdma_stop(struct ata_queued_cmd *qc);
|
||||||
static u8 qs_bmdma_status(struct ata_port *ap);
|
static u8 qs_bmdma_status(struct ata_port *ap);
|
||||||
static void qs_irq_clear(struct ata_port *ap);
|
static void qs_irq_clear(struct ata_port *ap);
|
||||||
static void qs_eng_timeout(struct ata_port *ap);
|
static void qs_freeze(struct ata_port *ap);
|
||||||
|
static void qs_thaw(struct ata_port *ap);
|
||||||
|
static void qs_error_handler(struct ata_port *ap);
|
||||||
|
|
||||||
static struct scsi_host_template qs_ata_sht = {
|
static struct scsi_host_template qs_ata_sht = {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
@ -150,11 +151,12 @@ static const struct ata_port_operations qs_ata_ops = {
|
|||||||
.check_atapi_dma = qs_check_atapi_dma,
|
.check_atapi_dma = qs_check_atapi_dma,
|
||||||
.exec_command = ata_exec_command,
|
.exec_command = ata_exec_command,
|
||||||
.dev_select = ata_std_dev_select,
|
.dev_select = ata_std_dev_select,
|
||||||
.phy_reset = qs_phy_reset,
|
|
||||||
.qc_prep = qs_qc_prep,
|
.qc_prep = qs_qc_prep,
|
||||||
.qc_issue = qs_qc_issue,
|
.qc_issue = qs_qc_issue,
|
||||||
.data_xfer = ata_data_xfer,
|
.data_xfer = ata_data_xfer,
|
||||||
.eng_timeout = qs_eng_timeout,
|
.freeze = qs_freeze,
|
||||||
|
.thaw = qs_thaw,
|
||||||
|
.error_handler = qs_error_handler,
|
||||||
.irq_clear = qs_irq_clear,
|
.irq_clear = qs_irq_clear,
|
||||||
.irq_on = ata_irq_on,
|
.irq_on = ata_irq_on,
|
||||||
.scr_read = qs_scr_read,
|
.scr_read = qs_scr_read,
|
||||||
@ -169,8 +171,6 @@ static const struct ata_port_info qs_port_info[] = {
|
|||||||
/* board_2068_idx */
|
/* board_2068_idx */
|
||||||
{
|
{
|
||||||
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||||
ATA_FLAG_SATA_RESET |
|
|
||||||
//FIXME ATA_FLAG_SRST |
|
|
||||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
|
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
|
||||||
.pio_mask = 0x10, /* pio4 */
|
.pio_mask = 0x10, /* pio4 */
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
@ -219,7 +219,9 @@ static void qs_irq_clear(struct ata_port *ap)
|
|||||||
static inline void qs_enter_reg_mode(struct ata_port *ap)
|
static inline void qs_enter_reg_mode(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
|
u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
|
||||||
|
struct qs_port_priv *pp = ap->private_data;
|
||||||
|
|
||||||
|
pp->state = qs_state_mmio;
|
||||||
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
|
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
|
||||||
readb(chan + QS_CCT_CTR0); /* flush */
|
readb(chan + QS_CCT_CTR0); /* flush */
|
||||||
}
|
}
|
||||||
@ -233,23 +235,28 @@ static inline void qs_reset_channel_logic(struct ata_port *ap)
|
|||||||
qs_enter_reg_mode(ap);
|
qs_enter_reg_mode(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qs_phy_reset(struct ata_port *ap)
|
static void qs_freeze(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct qs_port_priv *pp = ap->private_data;
|
u8 __iomem *mmio_base = qs_mmio_base(ap->host);
|
||||||
|
|
||||||
pp->state = qs_state_idle;
|
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
|
||||||
qs_reset_channel_logic(ap);
|
qs_enter_reg_mode(ap);
|
||||||
sata_phy_reset(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qs_eng_timeout(struct ata_port *ap)
|
static void qs_thaw(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct qs_port_priv *pp = ap->private_data;
|
u8 __iomem *mmio_base = qs_mmio_base(ap->host);
|
||||||
|
|
||||||
|
qs_enter_reg_mode(ap);
|
||||||
|
writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qs_prereset(struct ata_link *link, unsigned long deadline)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = link->ap;
|
||||||
|
|
||||||
if (pp->state != qs_state_idle) /* healthy paranoia */
|
|
||||||
pp->state = qs_state_mmio;
|
|
||||||
qs_reset_channel_logic(ap);
|
qs_reset_channel_logic(ap);
|
||||||
ata_eng_timeout(ap);
|
return ata_std_prereset(link, deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
|
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
|
||||||
@ -260,6 +267,13 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qs_error_handler(struct ata_port *ap)
|
||||||
|
{
|
||||||
|
qs_enter_reg_mode(ap);
|
||||||
|
ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL,
|
||||||
|
ata_std_postreset);
|
||||||
|
}
|
||||||
|
|
||||||
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
|
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
|
||||||
{
|
{
|
||||||
if (sc_reg > SCR_CONTROL)
|
if (sc_reg > SCR_CONTROL)
|
||||||
@ -358,7 +372,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
|
|||||||
|
|
||||||
switch (qc->tf.protocol) {
|
switch (qc->tf.protocol) {
|
||||||
case ATA_PROT_DMA:
|
case ATA_PROT_DMA:
|
||||||
|
|
||||||
pp->state = qs_state_pkt;
|
pp->state = qs_state_pkt;
|
||||||
qs_packet_start(qc);
|
qs_packet_start(qc);
|
||||||
return 0;
|
return 0;
|
||||||
@ -375,6 +388,26 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
|
|||||||
return ata_qc_issue_prot(qc);
|
return ata_qc_issue_prot(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status)
|
||||||
|
{
|
||||||
|
qc->err_mask |= ac_err_mask(status);
|
||||||
|
|
||||||
|
if (!qc->err_mask) {
|
||||||
|
ata_qc_complete(qc);
|
||||||
|
} else {
|
||||||
|
struct ata_port *ap = qc->ap;
|
||||||
|
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||||
|
|
||||||
|
ata_ehi_clear_desc(ehi);
|
||||||
|
ata_ehi_push_desc(ehi, "status 0x%02X", status);
|
||||||
|
|
||||||
|
if (qc->err_mask == AC_ERR_DEV)
|
||||||
|
ata_port_abort(ap);
|
||||||
|
else
|
||||||
|
ata_port_freeze(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned int qs_intr_pkt(struct ata_host *host)
|
static inline unsigned int qs_intr_pkt(struct ata_host *host)
|
||||||
{
|
{
|
||||||
unsigned int handled = 0;
|
unsigned int handled = 0;
|
||||||
@ -406,10 +439,8 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
|
|||||||
switch (sHST) {
|
switch (sHST) {
|
||||||
case 0: /* successful CPB */
|
case 0: /* successful CPB */
|
||||||
case 3: /* device error */
|
case 3: /* device error */
|
||||||
pp->state = qs_state_idle;
|
|
||||||
qs_enter_reg_mode(qc->ap);
|
qs_enter_reg_mode(qc->ap);
|
||||||
qc->err_mask |= ac_err_mask(sDST);
|
qs_do_or_die(qc, sDST);
|
||||||
ata_qc_complete(qc);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -431,25 +462,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
|
|||||||
if (ap &&
|
if (ap &&
|
||||||
!(ap->flags & ATA_FLAG_DISABLED)) {
|
!(ap->flags & ATA_FLAG_DISABLED)) {
|
||||||
struct ata_queued_cmd *qc;
|
struct ata_queued_cmd *qc;
|
||||||
struct qs_port_priv *pp = ap->private_data;
|
struct qs_port_priv *pp;
|
||||||
|
qc = ata_qc_from_tag(ap, ap->link.active_tag);
|
||||||
|
if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) {
|
||||||
|
/*
|
||||||
|
* The qstor hardware generates spurious
|
||||||
|
* interrupts from time to time when switching
|
||||||
|
* in and out of packet mode.
|
||||||
|
* There's no obvious way to know if we're
|
||||||
|
* here now due to that, so just ack the irq
|
||||||
|
* and pretend we knew it was ours.. (ugh).
|
||||||
|
* This does not affect packet mode.
|
||||||
|
*/
|
||||||
|
ata_check_status(ap);
|
||||||
|
handled = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pp = ap->private_data;
|
||||||
if (!pp || pp->state != qs_state_mmio)
|
if (!pp || pp->state != qs_state_mmio)
|
||||||
continue;
|
continue;
|
||||||
qc = ata_qc_from_tag(ap, ap->link.active_tag);
|
if (!(qc->tf.flags & ATA_TFLAG_POLLING))
|
||||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
|
handled |= ata_host_intr(ap, qc);
|
||||||
|
|
||||||
/* check main status, clearing INTRQ */
|
|
||||||
u8 status = ata_check_status(ap);
|
|
||||||
if ((status & ATA_BUSY))
|
|
||||||
continue;
|
|
||||||
DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
|
|
||||||
ap->print_id, qc->tf.protocol, status);
|
|
||||||
|
|
||||||
/* complete taskfile transaction */
|
|
||||||
pp->state = qs_state_idle;
|
|
||||||
qc->err_mask |= ac_err_mask(status);
|
|
||||||
ata_qc_complete(qc);
|
|
||||||
handled = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handled;
|
return handled;
|
||||||
@ -459,12 +492,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
|
|||||||
{
|
{
|
||||||
struct ata_host *host = dev_instance;
|
struct ata_host *host = dev_instance;
|
||||||
unsigned int handled = 0;
|
unsigned int handled = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
VPRINTK("ENTER\n");
|
VPRINTK("ENTER\n");
|
||||||
|
|
||||||
spin_lock(&host->lock);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
handled = qs_intr_pkt(host) | qs_intr_mmio(host);
|
handled = qs_intr_pkt(host) | qs_intr_mmio(host);
|
||||||
spin_unlock(&host->lock);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
|
||||||
VPRINTK("EXIT\n");
|
VPRINTK("EXIT\n");
|
||||||
|
|
||||||
@ -501,7 +535,6 @@ static int qs_port_start(struct ata_port *ap)
|
|||||||
rc = ata_port_start(ap);
|
rc = ata_port_start(ap);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
qs_enter_reg_mode(ap);
|
|
||||||
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
||||||
if (!pp)
|
if (!pp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -512,6 +545,7 @@ static int qs_port_start(struct ata_port *ap)
|
|||||||
memset(pp->pkt, 0, QS_PKT_BYTES);
|
memset(pp->pkt, 0, QS_PKT_BYTES);
|
||||||
ap->private_data = pp;
|
ap->private_data = pp;
|
||||||
|
|
||||||
|
qs_enter_reg_mode(ap);
|
||||||
addr = (u64)pp->pkt_dma;
|
addr = (u64)pp->pkt_dma;
|
||||||
writel((u32) addr, chan + QS_CCF_CPBA);
|
writel((u32) addr, chan + QS_CCF_CPBA);
|
||||||
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
|
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
|
||||||
|
Loading…
Reference in New Issue
Block a user