diff options
| -rw-r--r-- | drivers/ata/sata_mv.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 47184567248d..8a751054c8a1 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
| @@ -251,6 +251,11 @@ enum { | |||
| 251 | HC_IRQ_COAL_IO_THRESHOLD_OFS = 0x000c, | 251 | HC_IRQ_COAL_IO_THRESHOLD_OFS = 0x000c, |
| 252 | HC_IRQ_COAL_TIME_THRESHOLD_OFS = 0x0010, | 252 | HC_IRQ_COAL_TIME_THRESHOLD_OFS = 0x0010, |
| 253 | 253 | ||
| 254 | SOC_LED_CTRL_OFS = 0x2c, | ||
| 255 | SOC_LED_CTRL_BLINK = (1 << 0), /* Active LED blink */ | ||
| 256 | SOC_LED_CTRL_ACT_PRESENCE = (1 << 2), /* Multiplex dev presence */ | ||
| 257 | /* with dev activity LED */ | ||
| 258 | |||
| 254 | /* Shadow block registers */ | 259 | /* Shadow block registers */ |
| 255 | SHD_BLK_OFS = 0x100, | 260 | SHD_BLK_OFS = 0x100, |
| 256 | SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ | 261 | SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ |
| @@ -411,6 +416,7 @@ enum { | |||
| 411 | MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ | 416 | MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ |
| 412 | MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ | 417 | MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ |
| 413 | MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ | 418 | MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ |
| 419 | MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */ | ||
| 414 | 420 | ||
| 415 | /* Port private flags (pp_flags) */ | 421 | /* Port private flags (pp_flags) */ |
| 416 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ | 422 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ |
| @@ -1404,6 +1410,61 @@ static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma) | |||
| 1404 | mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new); | 1410 | mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new); |
| 1405 | } | 1411 | } |
| 1406 | 1412 | ||
| 1413 | /* | ||
| 1414 | * SOC chips have an issue whereby the HDD LEDs don't always blink | ||
| 1415 | * during I/O when NCQ is enabled. Enabling a special "LED blink" mode | ||
| 1416 | * of the SOC takes care of it, generating a steady blink rate when | ||
| 1417 | * any drive on the chip is active. | ||
| 1418 | * | ||
| 1419 | * Unfortunately, the blink mode is a global hardware setting for the SOC, | ||
| 1420 | * so we must use it whenever at least one port on the SOC has NCQ enabled. | ||
| 1421 | * | ||
| 1422 | * We turn "LED blink" off when NCQ is not in use anywhere, because the normal | ||
| 1423 | * LED operation works then, and provides better (more accurate) feedback. | ||
| 1424 | * | ||
| 1425 | * Note that this code assumes that an SOC never has more than one HC onboard. | ||
| 1426 | */ | ||
| 1427 | static void mv_soc_led_blink_enable(struct ata_port *ap) | ||
| 1428 | { | ||
| 1429 | struct ata_host *host = ap->host; | ||
| 1430 | struct mv_host_priv *hpriv = host->private_data; | ||
| 1431 | void __iomem *hc_mmio; | ||
| 1432 | u32 led_ctrl; | ||
| 1433 | |||
| 1434 | if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN) | ||
| 1435 | return; | ||
| 1436 | hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN; | ||
| 1437 | hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no); | ||
| 1438 | led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS); | ||
| 1439 | writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS); | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | static void mv_soc_led_blink_disable(struct ata_port *ap) | ||
| 1443 | { | ||
| 1444 | struct ata_host *host = ap->host; | ||
| 1445 | struct mv_host_priv *hpriv = host->private_data; | ||
| 1446 | void __iomem *hc_mmio; | ||
| 1447 | u32 led_ctrl; | ||
| 1448 | unsigned int port; | ||
| 1449 | |||
| 1450 | if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)) | ||
| 1451 | return; | ||
| 1452 | |||
| 1453 | /* disable led-blink only if no ports are using NCQ */ | ||
| 1454 | for (port = 0; port < hpriv->n_ports; port++) { | ||
| 1455 | struct ata_port *this_ap = host->ports[port]; | ||
| 1456 | struct mv_port_priv *pp = this_ap->private_data; | ||
| 1457 | |||
| 1458 | if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) | ||
| 1459 | return; | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN; | ||
| 1463 | hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no); | ||
| 1464 | led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS); | ||
| 1465 | writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS); | ||
| 1466 | } | ||
| 1467 | |||
| 1407 | static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) | 1468 | static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) |
| 1408 | { | 1469 | { |
| 1409 | u32 cfg; | 1470 | u32 cfg; |
| @@ -1451,6 +1512,13 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) | |||
| 1451 | if (hpriv->hp_flags & MV_HP_CUT_THROUGH) | 1512 | if (hpriv->hp_flags & MV_HP_CUT_THROUGH) |
| 1452 | cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ | 1513 | cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ |
| 1453 | mv_bmdma_enable_iie(ap, !want_edma); | 1514 | mv_bmdma_enable_iie(ap, !want_edma); |
| 1515 | |||
| 1516 | if (IS_SOC(hpriv)) { | ||
| 1517 | if (want_ncq) | ||
| 1518 | mv_soc_led_blink_enable(ap); | ||
| 1519 | else | ||
| 1520 | mv_soc_led_blink_disable(ap); | ||
| 1521 | } | ||
| 1454 | } | 1522 | } |
| 1455 | 1523 | ||
| 1456 | if (want_ncq) { | 1524 | if (want_ncq) { |
