libata: Implement ATA_FLAG_NO_DIPM and apply it to mcp65
NVIDIA mcp65 familiy of controllers cause command timeouts when DIPM is used. Implement ATA_FLAG_NO_DIPM and apply it. This problem was reported by Stefan Bader in the following thread. http://thread.gmane.org/gmane.linux.ide/48841 stable: applicable to 2.6.37 and 38. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Stefan Bader <stefan.bader@canonical.com> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
3f7ac1d667
commit
ae01b2493c
|
@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
||||||
{
|
{
|
||||||
AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
|
AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
|
||||||
AHCI_HFLAG_YES_NCQ),
|
AHCI_HFLAG_YES_NCQ),
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
|
||||||
.pio_mask = ATA_PIO4,
|
.pio_mask = ATA_PIO4,
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &ahci_ops,
|
.port_ops = &ahci_ops,
|
||||||
|
|
|
@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||||
struct ata_eh_context *ehc = &link->eh_context;
|
struct ata_eh_context *ehc = &link->eh_context;
|
||||||
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
|
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
|
||||||
enum ata_lpm_policy old_policy = link->lpm_policy;
|
enum ata_lpm_policy old_policy = link->lpm_policy;
|
||||||
|
bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM;
|
||||||
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
|
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
|
||||||
unsigned int err_mask;
|
unsigned int err_mask;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||||
*/
|
*/
|
||||||
ata_for_each_dev(dev, link, ENABLED) {
|
ata_for_each_dev(dev, link, ENABLED) {
|
||||||
bool hipm = ata_id_has_hipm(dev->id);
|
bool hipm = ata_id_has_hipm(dev->id);
|
||||||
bool dipm = ata_id_has_dipm(dev->id);
|
bool dipm = ata_id_has_dipm(dev->id) && !no_dipm;
|
||||||
|
|
||||||
/* find the first enabled and LPM enabled devices */
|
/* find the first enabled and LPM enabled devices */
|
||||||
if (!link_dev)
|
if (!link_dev)
|
||||||
|
@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||||
|
|
||||||
/* host config updated, enable DIPM if transitioning to MIN_POWER */
|
/* host config updated, enable DIPM if transitioning to MIN_POWER */
|
||||||
ata_for_each_dev(dev, link, ENABLED) {
|
ata_for_each_dev(dev, link, ENABLED) {
|
||||||
if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
|
if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
|
||||||
|
ata_id_has_dipm(dev->id)) {
|
||||||
err_mask = ata_dev_set_feature(dev,
|
err_mask = ata_dev_set_feature(dev,
|
||||||
SETFEATURES_SATA_ENABLE, SATA_DIPM);
|
SETFEATURES_SATA_ENABLE, SATA_DIPM);
|
||||||
if (err_mask && err_mask != AC_ERR_DEV) {
|
if (err_mask && err_mask != AC_ERR_DEV) {
|
||||||
|
|
|
@ -196,6 +196,7 @@ enum {
|
||||||
* management */
|
* management */
|
||||||
ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity
|
ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity
|
||||||
* led */
|
* led */
|
||||||
|
ATA_FLAG_NO_DIPM = (1 << 23), /* host not happy with DIPM */
|
||||||
|
|
||||||
/* bits 24:31 of ap->flags are reserved for LLD specific flags */
|
/* bits 24:31 of ap->flags are reserved for LLD specific flags */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue