Commit 66337dab authored by Linus Torvalds's avatar Linus Torvalds

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:
  [PCI] Add JMicron PCI ID constants
  [PATCH] ahci: Ensure that we don't grab both functions
  [PATCH] libata-core.c: restore configuration boot messages in ata_dev_configure(), v2
  [PATCH] sata_sil24: add suspend/sleep support
  [PATCH] sata_sil24: separate out sil24_init_controller()
  [PATCH] sata_sil: add suspend/sleep support
  [PATCH] sata_sil: separate out sil_init_controller()
  [PATCH] libata: reimplement controller-wide PM
  [PATCH] libata: reimplement per-dev PM
  [PATCH] libata: implement PM EH actions
  [PATCH] libata: separate out __ata_ehi_hotplugged()
  [PATCH] libata: implement ATA_EHI_NO_AUTOPSY and QUIET
  [PATCH] libata: clean up debounce parameters and improve parameter selection
  [PATCH] libata: implement ATA_EHI_RESUME_LINK
  [PATCH] libata: replace ap_lock w/ ap->lock in ata_scsi_error()
  [PATCH] libata: fix ehc->i.action setting in ata_eh_autopsy()
  [PATCH] libata: add ap->pflags and move core dynamic flags to it
  [PATCH] libata: Conditionally set host->max_cmd_len
  [PATCH] sata_vsc: data_xfer should use mmio
parents a942b57b 309bade0
...@@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap) ...@@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap) static void ahci_error_handler(struct ata_port *ap)
{ {
if (!(ap->flags & ATA_FLAG_FROZEN)) { if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */ /* restart engine */
ahci_stop_engine(ap); ahci_stop_engine(ap);
ahci_start_engine(ap); ahci_start_engine(ap);
...@@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
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");
/* JMicron-specific fixup: make sure we're in AHCI mode */
/* This is protected from races with ata_jmicron by the pci probe
locking */
if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
/* AHCI enable, AHCI on function 0 */
pci_write_config_byte(pdev, 0x41, 0xa1);
/* Function 1 is the PATA controller */
if (PCI_FUNC(pdev->devfn))
return -ENODEV;
}
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) if (rc)
return rc; return rc;
...@@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (have_msi) if (have_msi)
hpriv->flags |= AHCI_FLAG_MSI; hpriv->flags |= AHCI_FLAG_MSI;
/* JMicron-specific fixup: make sure we're in AHCI mode */
if (pdev->vendor == 0x197b)
pci_write_config_byte(pdev, 0x41, 0xa1);
/* initialize adapter */ /* initialize adapter */
rc = ahci_host_init(probe_ent); rc = ahci_host_init(probe_ent);
if (rc) if (rc)
......
This diff is collapsed.
This diff is collapsed.
...@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf) ...@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
} }
} }
int ata_scsi_device_resume(struct scsi_device *sdev) /**
* ata_scsi_device_suspend - suspend ATA device associated with sdev
* @sdev: the SCSI device to suspend
* @state: target power management state
*
* Request suspend EH action on the ATA device associated with
* @sdev and wait for the operation to complete.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{ {
struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
unsigned long flags;
unsigned int action;
int rc = 0;
if (!dev)
goto out;
spin_lock_irqsave(ap->lock, flags);
/* wait for the previous resume to complete */
while (dev->flags & ATA_DFLAG_SUSPENDED) {
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
spin_lock_irqsave(ap->lock, flags);
}
/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;
/* request suspend */
action = ATA_EH_SUSPEND;
if (state.event != PM_EVENT_SUSPEND)
action |= ATA_EH_PM_FREEZE;
ap->eh_info.dev_action[dev->devno] |= action;
ap->eh_info.flags |= ATA_EHI_QUIET;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
/* wait for EH to do the job */
ata_port_wait_eh(ap);
spin_lock_irqsave(ap->lock, flags);
/* If @sdev is still attached but the associated ATA device
* isn't suspended, the operation failed.
*/
if (sdev->sdev_state != SDEV_OFFLINE &&
sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
!(dev->flags & ATA_DFLAG_SUSPENDED))
rc = -EIO;
return ata_device_resume(dev); out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
if (rc == 0)
sdev->sdev_gendev.power.power_state = state;
return rc;
} }
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) /**
* ata_scsi_device_resume - resume ATA device associated with sdev
* @sdev: the SCSI device to resume
*
* Request resume EH action on the ATA device associated with
* @sdev and return immediately. This enables parallel
* wakeup/spinup of devices.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0.
*/
int ata_scsi_device_resume(struct scsi_device *sdev)
{ {
struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
unsigned int action;
if (!dev)
goto out;
spin_lock_irqsave(ap->lock, flags);
/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;
return ata_device_suspend(dev, state); /* request resume */
action = ATA_EH_RESUME;
if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
__ata_ehi_hotplugged(ehi);
else
action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
ehi->dev_action[dev->devno] |= action;
/* We don't want autopsy and verbose EH messages. Disable
* those if we're the only device on this link.
*/
if (ata_port_max_devices(ap) == 1)
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ata_port_schedule_eh(ap);
out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
sdev->sdev_gendev.power.power_state = PMSG_ON;
return 0;
} }
/** /**
...@@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data) ...@@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
struct ata_port *ap = data; struct ata_port *ap = data;
int i; int i;
if (ap->flags & ATA_FLAG_UNLOADING) { if (ap->pflags & ATA_PFLAG_UNLOADING) {
DPRINTK("ENTER/EXIT - unloading\n"); DPRINTK("ENTER/EXIT - unloading\n");
return; return;
} }
...@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, ...@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (dev) { if (dev) {
ap->eh_info.probe_mask |= 1 << dev->devno; ap->eh_info.probe_mask |= 1 << dev->devno;
ap->eh_info.action |= ATA_EH_SOFTRESET; ap->eh_info.action |= ATA_EH_SOFTRESET;
ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
} else } else
rc = -EINVAL; rc = -EINVAL;
} }
......
...@@ -109,6 +109,7 @@ enum { ...@@ -109,6 +109,7 @@ enum {
}; };
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
...@@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = { ...@@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl, .id_table = sil_pci_tbl,
.probe = sil_init_one, .probe = sil_init_one,
.remove = ata_pci_remove_one, .remove = ata_pci_remove_one,
.suspend = ata_pci_device_suspend,
.resume = sil_pci_device_resume,
}; };
static struct scsi_host_template sil_sht = { static struct scsi_host_template sil_sht = {
...@@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = { ...@@ -178,6 +181,8 @@ static struct scsi_host_template sil_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 const struct ata_port_operations sil_ops = { static const struct ata_port_operations sil_ops = {
...@@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) ...@@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* during hardreset makes controllers with broken SIEN * during hardreset makes controllers with broken SIEN
* repeat probing needlessly. * repeat probing needlessly.
*/ */
if (!(ap->flags & ATA_FLAG_FROZEN)) { if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
ata_ehi_hotplugged(&ap->eh_info); ata_ehi_hotplugged(&ap->eh_info);
ap->eh_info.serror |= serror; ap->eh_info.serror |= serror;
} }
...@@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) ...@@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
} }
} }
static void sil_init_controller(struct pci_dev *pdev,
int n_ports, unsigned long host_flags,
void __iomem *mmio_base)
{
u8 cls;
u32 tmp;
int i;
/* Initialize FIFO PCI bus arbitration */
cls = sil_get_device_cache_line(pdev);
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
for (i = 0; i < n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
dev_printk(KERN_WARNING, &pdev->dev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
for (i = 0, cnt = 0; i < n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
dev_printk(KERN_INFO, &pdev->dev,
"Applying R_ERR on DMA activate "
"FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
}
if (n_ports == 4) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
mmio_base + sil_port[2].bmdma);
}
}
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
static int printed_version; static int printed_version;
...@@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc; int rc;
unsigned int i; unsigned int i;
int pci_dev_busy = 0; int pci_dev_busy = 0;
u32 tmp;
u8 cls;
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");
...@@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ata_std_ports(&probe_ent->port[i]); ata_std_ports(&probe_ent->port[i]);
} }
/* Initialize FIFO PCI bus arbitration */ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
cls = sil_get_device_cache_line(pdev); mmio_base);
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
for (i = 0; i < probe_ent->n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
dev_printk(KERN_WARNING, &pdev->dev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
dev_printk(KERN_INFO, &pdev->dev,
"Applying R_ERR on DMA activate "
"FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
}
if (ent->driver_data == sil_3114) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
mmio_base + sil_port[2].bmdma);
}
pci_set_master(pdev); pci_set_master(pdev);
...@@ -685,6 +700,18 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -685,6 +700,18 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc; return rc;
} }
static int sil_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
ata_pci_device_do_resume(pdev);
sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
host_set->mmio_base);
ata_host_set_resume(host_set);
return 0;
}
static int __init sil_init(void) static int __init sil_init(void)
{ {
return pci_module_init(&sil_pci_driver); return pci_module_init(&sil_pci_driver);
......
...@@ -92,6 +92,7 @@ enum { ...@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/* /*
* Port registers * Port registers
...@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap); ...@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap); static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set); static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = { static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
...@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = { ...@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl, .id_table = sil24_pci_tbl,
.probe = sil24_init_one, .probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */ .remove = ata_pci_remove_one, /* safe? */
.suspend = ata_pci_device_suspend,
.resume = sil24_pci_device_resume,
}; };
static struct scsi_host_template sil24_sht = { static struct scsi_host_template sil24_sht = {
...@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = { ...@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_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 const struct ata_port_operations sil24_ops = { static const struct ata_port_operations sil24_ops = {
...@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) ...@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after /* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it. * DEV_RST, debounce it.
*/ */
rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst); rc = sata_phy_debounce(ap, sata_deb_timing_long);
if (rc) { if (rc) {
reason = "PHY debouncing failed"; reason = "PHY debouncing failed";
goto err; goto err;
...@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set) ...@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
kfree(hpriv); kfree(hpriv);
} }
static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
unsigned long host_flags,
void __iomem *host_base,
void __iomem *port_base)
{
u32 tmp;
int i;
/* GPIO off */
writel(0, host_base + HOST_FLASH_CMD);
/* clear global reset & mask interrupts during initialization */
writel(0, host_base + HOST_CTRL);
/* init ports */
for (i = 0; i < n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE;
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
/* Clear port RST */
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, &pdev->dev,
"failed to clear port RST\n");
}
/* Configure IRQ WoC */
if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
else
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* Zero error counters. */
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
writel(0x8000, port + PORT_CRC_ERR_THRESH);
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
writel(0x0000, port + PORT_DECODE_ERR_CNT);
writel(0x0000, port + PORT_CRC_ERR_CNT);
writel(0x0000, port + PORT_HSHK_ERR_CNT);
/* Always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
/* Clear port multiplier enable and resume bits */
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
/* Turn on interrupts */
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
}
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
static int printed_version = 0; static int printed_version = 0;
...@@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
} }
/* GPIO off */
writel(0, host_base + HOST_FLASH_CMD);
/* Apply workaround for completion IRQ loss on PCI-X errata */ /* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) { if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL); tmp = readl(host_base + HOST_CTRL);
...@@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
} }
/* clear global reset & mask interrupts during initialization */
writel(0, host_base + HOST_CTRL);
for (i = 0; i < probe_ent->n_ports; i++) { for (i = 0; i < probe_ent->n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE; unsigned long portu =
unsigned long portu = (unsigned long)port; (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu; probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]); ata_std_ports(&probe_ent->port[i]);
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
/* Clear port RST */
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, &pdev->dev,
"failed to clear port RST\n");
}
/* Configure IRQ WoC */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
else
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* Zero error counters. */
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
writel(0x8000, port + PORT_CRC_ERR_THRESH);
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
writel(0x0000, port + PORT_DECODE_ERR_CNT);
writel(0x0000, port + PORT_CRC_ERR_CNT);
writel(0x0000, port + PORT_HSHK_ERR_CNT);
/* Always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
/* Clear port multiplier enable and resume bits */
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
} }
/* Turn on interrupts */ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); host_base, port_base);
pci_set_master(pdev); pci_set_master(pdev);
...@@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc; return rc;
} }
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
struct sil24_host_priv *hpriv = host_set->private_data;
ata_pci_device_do_resume(pdev);
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
sil24_init_controller(pdev, host_set->n_ports,
host_set->ports[0]->flags,
hpriv->host_base, hpriv->port_base);
ata_host_set_resume(host_set);
return 0;
}
static int __init sil24_init(void) static int __init sil24_init(void)
{ {
return pci_module_init(&sil24_pci_driver); return pci_module_init(&sil24_pci_driver);
......
...@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = { ...@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status, .bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer, .data_xfer = ata_mmio_data_xfer,
.freeze = ata_bmdma_freeze, .freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw, .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler, .error_handler = ata_bmdma_error_handler,
......
...@@ -131,6 +131,7 @@ enum { ...@@ -131,6 +131,7 @@ enum {
ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1, ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16), ATA_DFLAG_DETACH = (1 << 16),
...@@ -160,22 +161,28 @@ enum { ...@@ -160,22 +161,28 @@ enum {
ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */ ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
* Register FIS clearing BSY */ * Register FIS clearing BSY */
ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_DEBUGMSG = (1 << 13),
ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */ /* The following flag belongs to ap->pflags but is kept in
ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */ * ap->flags because it's referenced in many LLDs and will be
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ * removed in not-too-distant future.
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ */
ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */ ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */
ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */ /* bits 24:31 of ap->flags are reserved for LLD specific flags */
ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ /* struct ata_port pflags */
ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */
ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */
ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */
ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */
ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */ ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
/* struct ata_queued_cmd flags */ /* struct ata_queued_cmd flags */
ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
...@@ -248,12 +255,19 @@ enum { ...@@ -248,12 +255,19 @@ enum {
ATA_EH_REVALIDATE = (1 << 0), ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1), ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2), ATA_EH_HARDRESET = (1 << 2),
ATA_EH_SUSPEND = (1 << 3),
ATA_EH_RESUME = (1 << 4),
ATA_EH_PM_FREEZE = (1 << 5),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
ATA_EH_RESUME | ATA_EH_PM_FREEZE,
/* ata_eh_info->flags */ /* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */
ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
...@@ -486,6 +500,7 @@ struct ata_port { ...@@ -486,6 +500,7 @@ struct ata_port {
const struct ata_port_operations *ops; const struct ata_port_operations *ops;
spinlock_t *lock; spinlock_t *lock;
unsigned long flags; /* ATA_FLAG_xxx */ unsigned long flags; /* ATA_FLAG_xxx */
unsigned int pflags; /* ATA_PFLAG_xxx */
unsigned int id; /* unique id req'd by scsi midlyr */ unsigned int id; /* unique id req'd by scsi midlyr */
unsigned int port_no; /* unique port #; from zero */ unsigned int port_no; /* unique port #; from zero */
unsigned int hard_port_no; /* hardware port #; from zero */ unsigned int hard_port_no; /* hardware port #; from zero */
...@@ -535,6 +550,9 @@ struct ata_port { ...@@ -535,6 +550,9 @@ struct ata_port {
struct list_head eh_done_q; struct list_head eh_done_q;
wait_queue_head_t eh_wait_q; wait_queue_head_t eh_wait_q;
pm_message_t pm_mesg;
int *pm_result;
void *private_data; void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
...@@ -589,6 +607,9 @@ struct ata_port_operations { ...@@ -589,6 +607,9 @@ struct ata_port_operations {
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val); u32 val);
int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
int (*port_resume) (struct ata_port *ap);
int (*port_start) (struct ata_port *ap); int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap); void (*port_stop) (struct ata_port *ap);
...@@ -622,9 +643,18 @@ struct ata_timing { ...@@ -622,9 +643,18 @@ struct ata_timing {
#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) #define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)
extern const unsigned long sata_deb_timing_boot[]; extern const unsigned long sata_deb_timing_normal[];
extern const unsigned long sata_deb_timing_eh[]; extern const unsigned long sata_deb_timing_hotplug[];
extern const unsigned long sata_deb_timing_before_fsrst[]; extern const unsigned long sata_deb_timing_long[];
static inline const unsigned long *
sata_ehc_deb_timing(struct ata_eh_context *ehc)
{
if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
return sata_deb_timing_hotplug;
else
return sata_deb_timing_normal;
}
extern void ata_port_probe(struct ata_port *); extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap); extern void __sata_phy_reset(struct ata_port *ap);
...@@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr); ...@@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports); unsigned int n_ports);
extern void ata_pci_remove_one (struct pci_dev *pdev); extern void ata_pci_remove_one (struct pci_dev *pdev);
extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
extern void ata_pci_device_do_resume(struct pci_dev *pdev);
extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state); extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
extern int ata_pci_device_resume(struct pci_dev *pdev); extern int ata_pci_device_resume(struct pci_dev *pdev);
extern int ata_pci_clear_simplex(struct pci_dev *pdev); extern int ata_pci_clear_simplex(struct pci_dev *pdev);
...@@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap); ...@@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap); extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *); extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
extern int ata_device_resume(struct ata_device *); extern int ata_host_set_suspend(struct ata_host_set *host_set,
extern int ata_device_suspend(struct ata_device *, pm_message_t state); pm_message_t mesg);
extern void ata_host_set_resume(struct ata_host_set *host_set);
extern int ata_ratelimit(void); extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap, extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat, unsigned long timeout_pat,
...@@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
(ehi)->desc_len = 0; \ (ehi)->desc_len = 0; \
} while (0) } while (0)
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
{ {
if (ehi->flags & ATA_EHI_HOTPLUGGED) if (ehi->flags & ATA_EHI_HOTPLUGGED)
return; return;
ehi->flags |= ATA_EHI_HOTPLUGGED; ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
ehi->hotplug_timestamp = jiffies; ehi->hotplug_timestamp = jiffies;
ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET; ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
} }
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
__ata_ehi_hotplugged(ehi);
ehi->err_mask |= AC_ERR_ATA_BUS;
}
/* /*
* qc helpers * qc helpers
*/ */
...@@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) ...@@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
return ata_class_absent(dev->class); return ata_class_absent(dev->class);
} }
static inline unsigned int ata_dev_ready(const struct ata_device *dev)
{
return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
}
/* /*
* port helpers * port helpers
*/ */
......
...@@ -2019,6 +2019,13 @@ ...@@ -2019,6 +2019,13 @@
#define PCI_VENDOR_ID_TDI 0x192E #define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101 #define PCI_DEVICE_ID_TDI_EHCI 0x0101
#define PCI_VENDOR_ID_JMICRON 0x197B
#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
#define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment