|
@@ -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
|
|
|
|
- * per PM slot */
|
|
|
|
|
|
+ /* enclosure management info 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_SECT255),
|
|
|
|
|
|
+ AHCI_HFLAG_NO_MSI | 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);
|
|
|
|
|