|
@@ -185,6 +185,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * sata_pmp_set_lpm - configure LPM for a PMP link
|
|
|
+ * @link: PMP link to configure LPM for
|
|
|
+ * @policy: target LPM policy
|
|
|
+ * @hints: LPM hints
|
|
|
+ *
|
|
|
+ * Configure LPM for @link. This function will contain any PMP
|
|
|
+ * specific workarounds if necessary.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * EH context.
|
|
|
+ *
|
|
|
+ * RETURNS:
|
|
|
+ * 0 on success, -errno on failure.
|
|
|
+ */
|
|
|
+int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
|
|
+ unsigned hints)
|
|
|
+{
|
|
|
+ return sata_link_scr_lpm(link, policy, true);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* sata_pmp_read_gscr - read GSCR block of SATA PMP
|
|
|
* @dev: PMP device
|
|
@@ -365,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
|
|
if (vendor == 0x1095 && devid == 0x3726) {
|
|
|
/* sil3726 quirks */
|
|
|
ata_for_each_link(link, ap, EDGE) {
|
|
|
+ /* link reports offline after LPM */
|
|
|
+ link->flags |= ATA_LFLAG_NO_LPM;
|
|
|
+
|
|
|
/* Class code report is unreliable and SRST
|
|
|
* times out under certain configurations.
|
|
|
*/
|
|
@@ -380,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
|
|
} else if (vendor == 0x1095 && devid == 0x4723) {
|
|
|
/* sil4723 quirks */
|
|
|
ata_for_each_link(link, ap, EDGE) {
|
|
|
+ /* link reports offline after LPM */
|
|
|
+ link->flags |= ATA_LFLAG_NO_LPM;
|
|
|
+
|
|
|
/* class code report is unreliable */
|
|
|
if (link->pmp < 2)
|
|
|
link->flags |= ATA_LFLAG_ASSUME_ATA;
|
|
@@ -392,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
|
|
} else if (vendor == 0x1095 && devid == 0x4726) {
|
|
|
/* sil4726 quirks */
|
|
|
ata_for_each_link(link, ap, EDGE) {
|
|
|
+ /* link reports offline after LPM */
|
|
|
+ link->flags |= ATA_LFLAG_NO_LPM;
|
|
|
+
|
|
|
/* Class code report is unreliable and SRST
|
|
|
* times out under certain configurations.
|
|
|
* Config device can be at port 0 or 5 and
|
|
@@ -952,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
|
|
|
if (rc)
|
|
|
goto link_fail;
|
|
|
|
|
|
- /* Connection status might have changed while resetting other
|
|
|
- * links, check SATA_PMP_GSCR_ERROR before returning.
|
|
|
- */
|
|
|
-
|
|
|
/* clear SNotification */
|
|
|
rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
|
|
|
if (rc == 0)
|
|
|
sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
|
|
|
|
|
|
+ /*
|
|
|
+ * If LPM is active on any fan-out port, hotplug wouldn't
|
|
|
+ * work. Return w/ PHY event notification disabled.
|
|
|
+ */
|
|
|
+ ata_for_each_link(link, ap, EDGE)
|
|
|
+ if (link->lpm_policy > ATA_LPM_MAX_POWER)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Connection status might have changed while resetting other
|
|
|
+ * links, enable notification and check SATA_PMP_GSCR_ERROR
|
|
|
+ * before returning.
|
|
|
+ */
|
|
|
+
|
|
|
/* enable notification */
|
|
|
if (pmp_dev->flags & ATA_DFLAG_AN) {
|
|
|
gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
|