mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 18:09:57 +00:00
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: [libata] ata_piix: Enable parallel scan sata_nv: use hardreset only for post-boot probing [libata] ahci: Restore SB600 SATA controller 64 bit DMA ata_piix: Remove stale comment ata_piix: Turn on hotplugging support for older chips ahci: misc cleanups for EM stuff [libata] get rid of ATA_MAX_QUEUE loop in ata_qc_complete_multiple() v2 sata_sil: enable 32-bit PIO sata_sx4: speed up ECC initialization libata-sff: avoid byte swapping in ata_sff_data_xfer() [libata] ahci: use less error-prone array initializers
This commit is contained in:
commit
6adc74b7d0
8 changed files with 181 additions and 93 deletions
|
@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
|
||||||
size_t size);
|
size_t size);
|
||||||
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
|
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
|
||||||
ssize_t size);
|
ssize_t size);
|
||||||
#define MAX_SLOTS 8
|
|
||||||
#define MAX_RETRY 15
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AHCI_PCI_BAR = 5,
|
AHCI_PCI_BAR = 5,
|
||||||
|
@ -231,6 +229,10 @@ enum {
|
||||||
|
|
||||||
ICH_MAP = 0x90, /* ICH MAP register */
|
ICH_MAP = 0x90, /* ICH MAP register */
|
||||||
|
|
||||||
|
/* em constants */
|
||||||
|
EM_MAX_SLOTS = 8,
|
||||||
|
EM_MAX_RETRY = 5,
|
||||||
|
|
||||||
/* em_ctl bits */
|
/* em_ctl bits */
|
||||||
EM_CTL_RST = (1 << 9), /* Reset */
|
EM_CTL_RST = (1 << 9), /* Reset */
|
||||||
EM_CTL_TM = (1 << 8), /* Transmit Message */
|
EM_CTL_TM = (1 << 8), /* Transmit Message */
|
||||||
|
@ -282,8 +284,8 @@ struct ahci_port_priv {
|
||||||
unsigned int ncq_saw_dmas:1;
|
unsigned int ncq_saw_dmas:1;
|
||||||
unsigned int ncq_saw_sdb:1;
|
unsigned int ncq_saw_sdb:1;
|
||||||
u32 intr_mask; /* interrupts to enable */
|
u32 intr_mask; /* interrupts to enable */
|
||||||
struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info
|
/* enclosure management info per PM slot */
|
||||||
* per PM slot */
|
struct ahci_em_priv em_priv[EM_MAX_SLOTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
||||||
|
@ -313,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap);
|
||||||
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
|
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
|
||||||
static int ahci_port_resume(struct ata_port *ap);
|
static int ahci_port_resume(struct ata_port *ap);
|
||||||
static void ahci_dev_config(struct ata_device *dev);
|
static void ahci_dev_config(struct ata_device *dev);
|
||||||
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
|
|
||||||
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
|
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
|
||||||
u32 opts);
|
u32 opts);
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@ -404,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = {
|
||||||
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
|
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
|
||||||
|
|
||||||
static const struct ata_port_info ahci_port_info[] = {
|
static const struct ata_port_info ahci_port_info[] = {
|
||||||
/* board_ahci */
|
[board_ahci] =
|
||||||
{
|
{
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
.pio_mask = ATA_PIO4,
|
.pio_mask = ATA_PIO4,
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_ops,
|
.port_ops = &ahci_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_vt8251 */
|
[board_ahci_vt8251] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
|
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
|
@ -419,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_vt8251_ops,
|
.port_ops = &ahci_vt8251_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_ign_iferr */
|
[board_ahci_ign_iferr] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
|
AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
|
@ -427,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_ops,
|
.port_ops = &ahci_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_sb600 */
|
[board_ahci_sb600] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
|
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
|
||||||
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
|
AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
|
||||||
AHCI_HFLAG_SECT255),
|
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
.pio_mask = ATA_PIO4,
|
.pio_mask = ATA_PIO4,
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_sb600_ops,
|
.port_ops = &ahci_sb600_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_mv */
|
[board_ahci_mv] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
|
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
|
||||||
AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
|
AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
|
||||||
|
@ -447,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_ops,
|
.port_ops = &ahci_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_sb700, for SB700 and SB800 */
|
[board_ahci_sb700] = /* for SB700 and SB800 */
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
|
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
|
@ -455,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_sb600_ops,
|
.port_ops = &ahci_sb600_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_mcp65 */
|
[board_ahci_mcp65] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
|
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
|
@ -463,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_ops,
|
.port_ops = &ahci_ops,
|
||||||
},
|
},
|
||||||
/* board_ahci_nopmp */
|
[board_ahci_nopmp] =
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
|
AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
|
@ -1141,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap)
|
||||||
emp = &pp->em_priv[link->pmp];
|
emp = &pp->em_priv[link->pmp];
|
||||||
|
|
||||||
/* EM Transmit bit maybe busy during init */
|
/* EM Transmit bit maybe busy during init */
|
||||||
for (i = 0; i < MAX_RETRY; i++) {
|
for (i = 0; i < EM_MAX_RETRY; i++) {
|
||||||
rc = ahci_transmit_led_message(ap,
|
rc = ahci_transmit_led_message(ap,
|
||||||
emp->led_state,
|
emp->led_state,
|
||||||
4);
|
4);
|
||||||
if (rc == -EBUSY)
|
if (rc == -EBUSY)
|
||||||
udelay(100);
|
msleep(1);
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
|
||||||
|
|
||||||
/* get the slot number from the message */
|
/* get the slot number from the message */
|
||||||
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
||||||
if (pmp < MAX_SLOTS)
|
if (pmp < EM_MAX_SLOTS)
|
||||||
emp = &pp->em_priv[pmp];
|
emp = &pp->em_priv[pmp];
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1408,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
|
||||||
|
|
||||||
/* get the slot number from the message */
|
/* get the slot number from the message */
|
||||||
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
||||||
if (pmp < MAX_SLOTS)
|
if (pmp < EM_MAX_SLOTS)
|
||||||
emp = &pp->em_priv[pmp];
|
emp = &pp->em_priv[pmp];
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2584,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older
|
||||||
|
* BIOS. The oldest version known to be broken is 0901 and working is
|
||||||
|
* 1501 which was released on 2007-10-26. Force 32bit DMA on anything
|
||||||
|
* older than 1501. Please read bko#9412 for more info.
|
||||||
|
*/
|
||||||
|
static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
static const struct dmi_system_id sysids[] = {
|
||||||
|
{
|
||||||
|
.ident = "ASUS M2A-VM",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_BOARD_VENDOR,
|
||||||
|
"ASUSTeK Computer INC."),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
const char *cutoff_mmdd = "10/26";
|
||||||
|
const char *date;
|
||||||
|
int year;
|
||||||
|
|
||||||
|
if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
|
||||||
|
!dmi_check_system(sysids))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Argh.... both version and date are free form strings.
|
||||||
|
* Let's hope they're using the same date format across
|
||||||
|
* different versions.
|
||||||
|
*/
|
||||||
|
date = dmi_get_system_info(DMI_BIOS_DATE);
|
||||||
|
year = dmi_get_year(DMI_BIOS_DATE);
|
||||||
|
if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' &&
|
||||||
|
(year > 2007 ||
|
||||||
|
(year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, "
|
||||||
|
"forcing 32bit DMA, update BIOS\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
|
static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
static const struct dmi_system_id broken_systems[] = {
|
static const struct dmi_system_id broken_systems[] = {
|
||||||
|
@ -2744,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
|
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
|
||||||
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
|
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
|
||||||
|
|
||||||
|
/* apply ASUS M2A_VM quirk */
|
||||||
|
if (ahci_asus_m2a_vm_32bit_only(pdev))
|
||||||
|
hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
|
||||||
|
|
||||||
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
|
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
|
||||||
pci_enable_msi(pdev);
|
pci_enable_msi(pdev);
|
||||||
|
|
||||||
|
|
|
@ -223,10 +223,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
|
||||||
/* ICH8 Mobile PATA Controller */
|
/* ICH8 Mobile PATA Controller */
|
||||||
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
|
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
|
||||||
|
|
||||||
/* NOTE: The following PCI ids must be kept in sync with the
|
/* SATA ports */
|
||||||
* list in drivers/pci/quirks.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 82801EB (ICH5) */
|
/* 82801EB (ICH5) */
|
||||||
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
|
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
|
||||||
/* 82801EB (ICH5) */
|
/* 82801EB (ICH5) */
|
||||||
|
@ -1509,8 +1507,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||||
dev_printk(KERN_DEBUG, &pdev->dev,
|
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||||
"version " DRV_VERSION "\n");
|
"version " DRV_VERSION "\n");
|
||||||
|
|
||||||
/* no hotplugging support (FIXME) */
|
/* no hotplugging support for later devices (FIXME) */
|
||||||
if (!in_module_init)
|
if (!in_module_init && ent->driver_data >= ich5_sata)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (piix_broken_system_poweroff(pdev)) {
|
if (piix_broken_system_poweroff(pdev)) {
|
||||||
|
@ -1591,6 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||||
host->ports[1]->mwdma_mask = 0;
|
host->ports[1]->mwdma_mask = 0;
|
||||||
host->ports[1]->udma_mask = 0;
|
host->ports[1]->udma_mask = 0;
|
||||||
}
|
}
|
||||||
|
host->flags |= ATA_HOST_PARALLEL_SCAN;
|
||||||
|
|
||||||
pci_set_master(pdev);
|
pci_set_master(pdev);
|
||||||
return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
|
return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
|
||||||
|
|
|
@ -5031,7 +5031,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
|
||||||
{
|
{
|
||||||
int nr_done = 0;
|
int nr_done = 0;
|
||||||
u32 done_mask;
|
u32 done_mask;
|
||||||
int i;
|
|
||||||
|
|
||||||
done_mask = ap->qc_active ^ qc_active;
|
done_mask = ap->qc_active ^ qc_active;
|
||||||
|
|
||||||
|
@ -5041,16 +5040,16 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ATA_MAX_QUEUE; i++) {
|
while (done_mask) {
|
||||||
struct ata_queued_cmd *qc;
|
struct ata_queued_cmd *qc;
|
||||||
|
unsigned int tag = __ffs(done_mask);
|
||||||
|
|
||||||
if (!(done_mask & (1 << i)))
|
qc = ata_qc_from_tag(ap, tag);
|
||||||
continue;
|
if (qc) {
|
||||||
|
|
||||||
if ((qc = ata_qc_from_tag(ap, i))) {
|
|
||||||
ata_qc_complete(qc);
|
ata_qc_complete(qc);
|
||||||
nr_done++;
|
nr_done++;
|
||||||
}
|
}
|
||||||
|
done_mask &= ~(1 << tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nr_done;
|
return nr_done;
|
||||||
|
|
|
@ -727,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
|
||||||
else
|
else
|
||||||
iowrite16_rep(data_addr, buf, words);
|
iowrite16_rep(data_addr, buf, words);
|
||||||
|
|
||||||
/* Transfer trailing 1 byte, if any. */
|
/* Transfer trailing byte, if any. */
|
||||||
if (unlikely(buflen & 0x01)) {
|
if (unlikely(buflen & 0x01)) {
|
||||||
__le16 align_buf[1] = { 0 };
|
unsigned char pad[2];
|
||||||
unsigned char *trailing_buf = buf + buflen - 1;
|
|
||||||
|
|
||||||
|
/* Point buf to the tail of buffer */
|
||||||
|
buf += buflen - 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use io*16_rep() accessors here as well to avoid pointlessly
|
||||||
|
* swapping bytes to and fro on the big endian machines...
|
||||||
|
*/
|
||||||
if (rw == READ) {
|
if (rw == READ) {
|
||||||
align_buf[0] = cpu_to_le16(ioread16(data_addr));
|
ioread16_rep(data_addr, pad, 1);
|
||||||
memcpy(trailing_buf, align_buf, 1);
|
*buf = pad[0];
|
||||||
} else {
|
} else {
|
||||||
memcpy(align_buf, trailing_buf, 1);
|
pad[0] = *buf;
|
||||||
iowrite16(le16_to_cpu(align_buf[0]), data_addr);
|
iowrite16_rep(data_addr, pad, 1);
|
||||||
}
|
}
|
||||||
words++;
|
words++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,8 +305,8 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
|
||||||
static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
||||||
static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
|
static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
|
||||||
|
|
||||||
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class,
|
static int nv_hardreset(struct ata_link *link, unsigned int *class,
|
||||||
unsigned long deadline);
|
unsigned long deadline);
|
||||||
static void nv_nf2_freeze(struct ata_port *ap);
|
static void nv_nf2_freeze(struct ata_port *ap);
|
||||||
static void nv_nf2_thaw(struct ata_port *ap);
|
static void nv_nf2_thaw(struct ata_port *ap);
|
||||||
static void nv_ck804_freeze(struct ata_port *ap);
|
static void nv_ck804_freeze(struct ata_port *ap);
|
||||||
|
@ -406,49 +406,82 @@ static struct scsi_host_template nv_swncq_sht = {
|
||||||
.slave_configure = nv_swncq_slave_config,
|
.slave_configure = nv_swncq_slave_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ata_port_operations nv_common_ops = {
|
/*
|
||||||
|
* NV SATA controllers have various different problems with hardreset
|
||||||
|
* protocol depending on the specific controller and device.
|
||||||
|
*
|
||||||
|
* GENERIC:
|
||||||
|
*
|
||||||
|
* bko11195 reports that link doesn't come online after hardreset on
|
||||||
|
* generic nv's and there have been several other similar reports on
|
||||||
|
* linux-ide.
|
||||||
|
*
|
||||||
|
* bko12351#c23 reports that warmplug on MCP61 doesn't work with
|
||||||
|
* softreset.
|
||||||
|
*
|
||||||
|
* NF2/3:
|
||||||
|
*
|
||||||
|
* bko3352 reports nf2/3 controllers can't determine device signature
|
||||||
|
* reliably after hardreset. The following thread reports detection
|
||||||
|
* failure on cold boot with the standard debouncing timing.
|
||||||
|
*
|
||||||
|
* http://thread.gmane.org/gmane.linux.ide/34098
|
||||||
|
*
|
||||||
|
* bko12176 reports that hardreset fails to bring up the link during
|
||||||
|
* boot on nf2.
|
||||||
|
*
|
||||||
|
* CK804:
|
||||||
|
*
|
||||||
|
* For initial probing after boot and hot plugging, hardreset mostly
|
||||||
|
* works fine on CK804 but curiously, reprobing on the initial port
|
||||||
|
* by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
|
||||||
|
* FIS in somewhat undeterministic way.
|
||||||
|
*
|
||||||
|
* SWNCQ:
|
||||||
|
*
|
||||||
|
* bko12351 reports that when SWNCQ is enabled, for hotplug to work,
|
||||||
|
* hardreset should be used and hardreset can't report proper
|
||||||
|
* signature, which suggests that mcp5x is closer to nf2 as long as
|
||||||
|
* reset quirkiness is concerned.
|
||||||
|
*
|
||||||
|
* bko12703 reports that boot probing fails for intel SSD with
|
||||||
|
* hardreset. Link fails to come online. Softreset works fine.
|
||||||
|
*
|
||||||
|
* The failures are varied but the following patterns seem true for
|
||||||
|
* all flavors.
|
||||||
|
*
|
||||||
|
* - Softreset during boot always works.
|
||||||
|
*
|
||||||
|
* - Hardreset during boot sometimes fails to bring up the link on
|
||||||
|
* certain comibnations and device signature acquisition is
|
||||||
|
* unreliable.
|
||||||
|
*
|
||||||
|
* - Hardreset is often necessary after hotplug.
|
||||||
|
*
|
||||||
|
* So, preferring softreset for boot probing and error handling (as
|
||||||
|
* hardreset might bring down the link) but using hardreset for
|
||||||
|
* post-boot probing should work around the above issues in most
|
||||||
|
* cases. Define nv_hardreset() which only kicks in for post-boot
|
||||||
|
* probing and use it for all variants.
|
||||||
|
*/
|
||||||
|
static struct ata_port_operations nv_generic_ops = {
|
||||||
.inherits = &ata_bmdma_port_ops,
|
.inherits = &ata_bmdma_port_ops,
|
||||||
.lost_interrupt = ATA_OP_NULL,
|
.lost_interrupt = ATA_OP_NULL,
|
||||||
.scr_read = nv_scr_read,
|
.scr_read = nv_scr_read,
|
||||||
.scr_write = nv_scr_write,
|
.scr_write = nv_scr_write,
|
||||||
|
.hardreset = nv_hardreset,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* OSDL bz11195 reports that link doesn't come online after hardreset
|
|
||||||
* on generic nv's and there have been several other similar reports
|
|
||||||
* on linux-ide. Disable hardreset for generic nv's.
|
|
||||||
*/
|
|
||||||
static struct ata_port_operations nv_generic_ops = {
|
|
||||||
.inherits = &nv_common_ops,
|
|
||||||
.hardreset = ATA_OP_NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* nf2 is ripe with hardreset related problems.
|
|
||||||
*
|
|
||||||
* kernel bz#3352 reports nf2/3 controllers can't determine device
|
|
||||||
* signature reliably. The following thread reports detection failure
|
|
||||||
* on cold boot with the standard debouncing timing.
|
|
||||||
*
|
|
||||||
* http://thread.gmane.org/gmane.linux.ide/34098
|
|
||||||
*
|
|
||||||
* And bz#12176 reports that hardreset simply doesn't work on nf2.
|
|
||||||
* Give up on it and just don't do hardreset.
|
|
||||||
*/
|
|
||||||
static struct ata_port_operations nv_nf2_ops = {
|
static struct ata_port_operations nv_nf2_ops = {
|
||||||
.inherits = &nv_generic_ops,
|
.inherits = &nv_generic_ops,
|
||||||
.freeze = nv_nf2_freeze,
|
.freeze = nv_nf2_freeze,
|
||||||
.thaw = nv_nf2_thaw,
|
.thaw = nv_nf2_thaw,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For initial probing after boot and hot plugging, hardreset mostly
|
|
||||||
* works fine on CK804 but curiously, reprobing on the initial port by
|
|
||||||
* rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS
|
|
||||||
* in somewhat undeterministic way. Use noclassify hardreset.
|
|
||||||
*/
|
|
||||||
static struct ata_port_operations nv_ck804_ops = {
|
static struct ata_port_operations nv_ck804_ops = {
|
||||||
.inherits = &nv_common_ops,
|
.inherits = &nv_generic_ops,
|
||||||
.freeze = nv_ck804_freeze,
|
.freeze = nv_ck804_freeze,
|
||||||
.thaw = nv_ck804_thaw,
|
.thaw = nv_ck804_thaw,
|
||||||
.hardreset = nv_noclassify_hardreset,
|
|
||||||
.host_stop = nv_ck804_host_stop,
|
.host_stop = nv_ck804_host_stop,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -476,19 +509,8 @@ static struct ata_port_operations nv_adma_ops = {
|
||||||
.host_stop = nv_adma_host_stop,
|
.host_stop = nv_adma_host_stop,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to
|
|
||||||
* work, hardreset should be used and hardreset can't report proper
|
|
||||||
* signature, which suggests that mcp5x is closer to nf2 as long as
|
|
||||||
* reset quirkiness is concerned. Define separate ops for mcp5x with
|
|
||||||
* nv_noclassify_hardreset().
|
|
||||||
*/
|
|
||||||
static struct ata_port_operations nv_mcp5x_ops = {
|
|
||||||
.inherits = &nv_common_ops,
|
|
||||||
.hardreset = nv_noclassify_hardreset,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ata_port_operations nv_swncq_ops = {
|
static struct ata_port_operations nv_swncq_ops = {
|
||||||
.inherits = &nv_mcp5x_ops,
|
.inherits = &nv_generic_ops,
|
||||||
|
|
||||||
.qc_defer = ata_std_qc_defer,
|
.qc_defer = ata_std_qc_defer,
|
||||||
.qc_prep = nv_swncq_qc_prep,
|
.qc_prep = nv_swncq_qc_prep,
|
||||||
|
@ -557,7 +579,7 @@ static const struct ata_port_info nv_port_info[] = {
|
||||||
.pio_mask = NV_PIO_MASK,
|
.pio_mask = NV_PIO_MASK,
|
||||||
.mwdma_mask = NV_MWDMA_MASK,
|
.mwdma_mask = NV_MWDMA_MASK,
|
||||||
.udma_mask = NV_UDMA_MASK,
|
.udma_mask = NV_UDMA_MASK,
|
||||||
.port_ops = &nv_mcp5x_ops,
|
.port_ops = &nv_generic_ops,
|
||||||
.private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
|
.private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
|
||||||
},
|
},
|
||||||
/* SWNCQ */
|
/* SWNCQ */
|
||||||
|
@ -1559,15 +1581,24 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class,
|
static int nv_hardreset(struct ata_link *link, unsigned int *class,
|
||||||
unsigned long deadline)
|
unsigned long deadline)
|
||||||
{
|
{
|
||||||
bool online;
|
struct ata_eh_context *ehc = &link->eh_context;
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
|
/* Do hardreset iff it's post-boot probing, please read the
|
||||||
&online, NULL);
|
* comment above port ops for details.
|
||||||
return online ? -EAGAIN : rc;
|
*/
|
||||||
|
if (!(link->ap->pflags & ATA_PFLAG_LOADING) &&
|
||||||
|
!ata_dev_enabled(link->device))
|
||||||
|
sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
|
||||||
|
NULL, NULL);
|
||||||
|
else if (!(ehc->i.flags & ATA_EHI_QUIET))
|
||||||
|
ata_link_printk(link, KERN_INFO,
|
||||||
|
"nv: skipping hardreset on occupied port\n");
|
||||||
|
|
||||||
|
/* device signature acquisition is unreliable */
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nv_nf2_freeze(struct ata_port *ap)
|
static void nv_nf2_freeze(struct ata_port *ap)
|
||||||
|
|
|
@ -183,7 +183,7 @@ static struct scsi_host_template sil_sht = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ata_port_operations sil_ops = {
|
static struct ata_port_operations sil_ops = {
|
||||||
.inherits = &ata_bmdma_port_ops,
|
.inherits = &ata_bmdma32_port_ops,
|
||||||
.dev_config = sil_dev_config,
|
.dev_config = sil_dev_config,
|
||||||
.set_mode = sil_set_mode,
|
.set_mode = sil_set_mode,
|
||||||
.bmdma_setup = sil_bmdma_setup,
|
.bmdma_setup = sil_bmdma_setup,
|
||||||
|
|
|
@ -193,6 +193,7 @@ enum {
|
||||||
PDC_TIMER_MASK_INT,
|
PDC_TIMER_MASK_INT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ECC_ERASE_BUF_SZ (128 * 1024)
|
||||||
|
|
||||||
struct pdc_port_priv {
|
struct pdc_port_priv {
|
||||||
u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
|
u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
|
||||||
|
@ -1280,7 +1281,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
|
||||||
{
|
{
|
||||||
int speed, size, length;
|
int speed, size, length;
|
||||||
u32 addr, spd0, pci_status;
|
u32 addr, spd0, pci_status;
|
||||||
u32 tmp = 0;
|
|
||||||
u32 time_period = 0;
|
u32 time_period = 0;
|
||||||
u32 tcount = 0;
|
u32 tcount = 0;
|
||||||
u32 ticks = 0;
|
u32 ticks = 0;
|
||||||
|
@ -1395,14 +1395,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
|
||||||
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
|
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
|
||||||
PDC_DIMM_SPD_TYPE, &spd0);
|
PDC_DIMM_SPD_TYPE, &spd0);
|
||||||
if (spd0 == 0x02) {
|
if (spd0 == 0x02) {
|
||||||
|
void *buf;
|
||||||
VPRINTK("Start ECC initialization\n");
|
VPRINTK("Start ECC initialization\n");
|
||||||
addr = 0;
|
addr = 0;
|
||||||
length = size * 1024 * 1024;
|
length = size * 1024 * 1024;
|
||||||
|
buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
|
||||||
while (addr < length) {
|
while (addr < length) {
|
||||||
pdc20621_put_to_dimm(host, (void *) &tmp, addr,
|
pdc20621_put_to_dimm(host, buf, addr,
|
||||||
sizeof(u32));
|
ECC_ERASE_BUF_SZ);
|
||||||
addr += sizeof(u32);
|
addr += ECC_ERASE_BUF_SZ;
|
||||||
}
|
}
|
||||||
|
kfree(buf);
|
||||||
VPRINTK("Finish ECC initialization\n");
|
VPRINTK("Finish ECC initialization\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -596,6 +596,7 @@ int dmi_get_year(int field)
|
||||||
|
|
||||||
return year;
|
return year;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(dmi_get_year);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dmi_walk - Walk the DMI table and get called back for every record
|
* dmi_walk - Walk the DMI table and get called back for every record
|
||||||
|
|
Loading…
Reference in a new issue