Skip to content

Commit

Permalink
sata_mv: fix LED blinking for SoC+NCQ
Browse files Browse the repository at this point in the history
For Marvell SoC chips, the HDD LED does not blink when there is
disk I/O if NCQ is enabled. Add a quirk that enables blink mode for
the LED while NCQ is enabled on any port of a SoC host controller.
Normal LED function is restored when NCQ is not enabled on any port.

The code to enable the blink mode is based on earlier code
and suggestions from Frans Pop, Saeed Bishara, and possibly others.

Signed-off-by: Mark Lord <mlord@pobox.com>
Tested-by: Frans Pop <elendil@planet.nl>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
Mark Lord authored and Jeff Garzik committed Mar 25, 2009
1 parent 6abf467 commit 000b344
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions drivers/ata/sata_mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ enum {
HC_IRQ_COAL_IO_THRESHOLD_OFS = 0x000c,
HC_IRQ_COAL_TIME_THRESHOLD_OFS = 0x0010,

SOC_LED_CTRL_OFS = 0x2c,
SOC_LED_CTRL_BLINK = (1 << 0), /* Active LED blink */
SOC_LED_CTRL_ACT_PRESENCE = (1 << 2), /* Multiplex dev presence */
/* with dev activity LED */

/* Shadow block registers */
SHD_BLK_OFS = 0x100,
SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
Expand Down Expand Up @@ -411,6 +416,7 @@ enum {
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */
MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */

/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
Expand Down Expand Up @@ -1404,6 +1410,61 @@ static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma)
mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new);
}

/*
* SOC chips have an issue whereby the HDD LEDs don't always blink
* during I/O when NCQ is enabled. Enabling a special "LED blink" mode
* of the SOC takes care of it, generating a steady blink rate when
* any drive on the chip is active.
*
* Unfortunately, the blink mode is a global hardware setting for the SOC,
* so we must use it whenever at least one port on the SOC has NCQ enabled.
*
* We turn "LED blink" off when NCQ is not in use anywhere, because the normal
* LED operation works then, and provides better (more accurate) feedback.
*
* Note that this code assumes that an SOC never has more than one HC onboard.
*/
static void mv_soc_led_blink_enable(struct ata_port *ap)
{
struct ata_host *host = ap->host;
struct mv_host_priv *hpriv = host->private_data;
void __iomem *hc_mmio;
u32 led_ctrl;

if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)
return;
hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN;
hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
}

static void mv_soc_led_blink_disable(struct ata_port *ap)
{
struct ata_host *host = ap->host;
struct mv_host_priv *hpriv = host->private_data;
void __iomem *hc_mmio;
u32 led_ctrl;
unsigned int port;

if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN))
return;

/* disable led-blink only if no ports are using NCQ */
for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *this_ap = host->ports[port];
struct mv_port_priv *pp = this_ap->private_data;

if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
return;
}

hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN;
hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS);
writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS);
}

static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
{
u32 cfg;
Expand Down Expand Up @@ -1451,6 +1512,13 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
mv_bmdma_enable_iie(ap, !want_edma);

if (IS_SOC(hpriv)) {
if (want_ncq)
mv_soc_led_blink_enable(ap);
else
mv_soc_led_blink_disable(ap);
}
}

if (want_ncq) {
Expand Down

0 comments on commit 000b344

Please sign in to comment.