summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ata/ata-all.h6
-rw-r--r--sys/dev/ata/ata-pci.c3
-rw-r--r--sys/dev/ata/ata-sata.c7
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c14
4 files changed, 19 insertions, 11 deletions
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index a721d809414b..c590ea2e9678 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -148,9 +148,12 @@
/* SATA AHCI v1.0 register defines */
#define ATA_AHCI_CAP 0x00
-#define ATA_AHCI_NPMASK 0x1f
+#define ATA_AHCI_CAP_NPMASK 0x0000001f
+#define ATA_AHCI_CAP_PSC 0x00002000
+#define ATA_AHCI_CAP_SSC 0x00004000
#define ATA_AHCI_CAP_SPM 0x00020000
#define ATA_AHCI_CAP_CLO 0x01000000
+#define ATA_AHCI_CAP_SALP 0x04000000
#define ATA_AHCI_CAP_64BIT 0x80000000
#define ATA_AHCI_GHC 0x04
@@ -513,6 +516,7 @@ struct ata_channel {
#define ATA_NO_48BIT_DMA 0x08
#define ATA_ALWAYS_DMASTAT 0x10
+ int pm_level; /* power management level */
int devices; /* what is present */
#define ATA_ATA_MASTER 0x00000001
#define ATA_ATA_SLAVE 0x00000002
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index a903da744d08..9a0af1cf55c0 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -556,6 +556,9 @@ ata_pcichannel_attach(device_t dev)
ch->unit = (intptr_t)device_get_ivars(dev);
+ resource_int_value(device_get_name(dev),
+ device_get_unit(dev), "pm_level", &ch->pm_level);
+
if ((error = ctlr->ch_attach(dev)))
return error;
diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c
index 1151ca17b67f..79978a6e9cd9 100644
--- a/sys/dev/ata/ata-sata.c
+++ b/sys/dev/ata/ata-sata.c
@@ -60,7 +60,7 @@ ata_sata_phy_check_events(device_t dev)
ATA_IDX_OUTL(ch, ATA_SERROR, error);
/* if we have a connection event deal with it */
- if (error & ATA_SE_PHY_CHANGED) {
+ if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) {
if (bootverbose) {
u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS);
if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) ||
@@ -199,9 +199,8 @@ ata_sata_phy_reset(device_t dev, int port, int quick)
ata_udelay(5000);
for (loop = 0; loop < 10; loop++) {
if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
- ATA_SC_DET_IDLE |
- ATA_SC_IPM_DIS_PARTIAL |
- ATA_SC_IPM_DIS_SLUMBER))
+ ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 :
+ ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)))
return (0);
ata_udelay(100);
if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
index e89acef21a30..7037f4dd5f0c 100644
--- a/sys/dev/ata/chipsets/ata-ahci.c
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -131,7 +131,7 @@ ata_ahci_chipinit(device_t dev)
ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI);
ctlr->channels =
MAX(flsl(ctlr->ichannels),
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1);
ctlr->reset = ata_ahci_reset;
ctlr->ch_attach = ata_ahci_ch_attach;
@@ -148,7 +148,7 @@ ata_ahci_chipinit(device_t dev)
"AHCI Version %x%x.%x%x controller with %d ports PM %s\n",
(version >> 24) & 0xff, (version >> 16) & 0xff,
(version >> 8) & 0xff, version & 0xff,
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1,
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1,
(ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ?
"supported" : "not supported");
return 0;
@@ -286,7 +286,9 @@ ata_ahci_ch_resume(device_t dev)
/* activate the channel and power/spin up device */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD));
+ (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD |
+ ((ch->pm_level > 1) ? ATA_AHCI_P_CMD_ALPE : 0) |
+ ((ch->pm_level > 2) ? ATA_AHCI_P_CMD_ASP : 0 )));
ata_ahci_start_fr(dev);
ata_ahci_start(dev);
@@ -818,9 +820,9 @@ ata_ahci_reset(device_t dev)
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
(ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
- ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
- ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
- ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
+ ((ch->pm_level == 0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
+ ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
+ ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
/* only probe for PortMultiplier if HW has support */
if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) {