]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-libata-ahci-pm.patch
- up to 4.9.217
[packages/kernel.git] / kernel-libata-ahci-pm.patch
CommitLineData
2155c5a2
JR
1From: Matthew Garrett <mjg59@coreos.com>
2Date: Sat, 18 Apr 2015 08:26:34 -0700
3Subject: [PATCH 1/3] libata: Stash initial power management configuration
4
5The initial configuration for power management settings may be a result of
6the firmware using its knowledge of the installed hardware to program
7reasonable defaults. Stash as much of it as possible for later use.
8
9Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org>
10---
11 drivers/ata/acard-ahci.c | 3 +++
12 drivers/ata/ahci.c | 3 +++
13 drivers/ata/ahci.h | 7 +++++++
14 drivers/ata/libahci.c | 46 +++++++++++++++++++++++++++++++++++-------
15 drivers/ata/libahci_platform.c | 4 ++++
16 drivers/ata/libata-core.c | 19 ++++++++++-------
17 drivers/ata/libata-pmp.c | 2 +-
18 drivers/ata/libata.h | 2 +-
19 drivers/ata/sata_highbank.c | 4 ++++
20 include/linux/libata.h | 3 +++
21 10 files changed, 77 insertions(+), 16 deletions(-)
22
23diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
24index 12489ce..0029229 100644
25--- a/drivers/ata/acard-ahci.c
26+++ b/drivers/ata/acard-ahci.c
27@@ -476,6 +476,9 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
28 ata_port_pbar_desc(ap, AHCI_PCI_BAR,
29 0x100 + ap->port_no * 0x80, "port");
30
31+ rc = ahci_setup_port_privdata(ap);
32+ if (rc)
33+ return rc;
34 /* set initial link pm policy */
35 /*
36 ap->pm_policy = NOT_AVAILABLE;
37diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
38index c7a92a7..0f875e2 100644
39--- a/drivers/ata/ahci.c
40+++ b/drivers/ata/ahci.c
41@@ -1436,6 +1436,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
42 if (ap->flags & ATA_FLAG_EM)
43 ap->em_message_type = hpriv->em_msg_type;
44
45+ rc = ahci_setup_port_privdata(ap);
46+ if (rc)
47+ return rc;
48
49 /* disabled/not-implemented port */
50 if (!(hpriv->port_map & (1 << i)))
51diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
52index 71262e0..c1a4b6a 100644
53--- a/drivers/ata/ahci.h
54+++ b/drivers/ata/ahci.h
55@@ -313,6 +313,12 @@ struct ahci_port_priv {
56 /* enclosure management info per PM slot */
57 struct ahci_em_priv em_priv[EM_MAX_SLOTS];
58 char *irq_desc; /* desc in /proc/interrupts */
59+ bool init_alpe; /* alpe enabled by default */
60+ bool init_asp; /* asp enabled by default */
61+ bool init_devslp; /* devslp enabled by default */
62+ u32 init_dito; /* initial dito configuration */
63+ u32 init_deto; /* initial deto configuration */
64+ u32 init_mdat; /* initial mdat configuration */
65 };
66
67 struct ahci_host_priv {
68@@ -371,6 +377,7 @@ extern struct ata_port_operations ahci_platform_ops;
69 extern struct ata_port_operations ahci_pmp_retry_srst_ops;
70
71 unsigned int ahci_dev_classify(struct ata_port *ap);
72+int ahci_setup_port_privdata(struct ata_port *ap);
73 void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
74 u32 opts);
75 void ahci_save_initial_config(struct device *dev,
76diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
77index 61a9c07..f0c7120 100644
78--- a/drivers/ata/libahci.c
79+++ b/drivers/ata/libahci.c
80@@ -2212,19 +2212,53 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
81 }
82 #endif
83
84+/*
85+ * Allocate port privdata and read back initial power management configuration
86+ */
87+int ahci_setup_port_privdata(struct ata_port *ap)
88+{
89+ struct ahci_port_priv *pp;
90+ u32 cmd, devslp;
91+ void __iomem *port_mmio = ahci_port_base(ap);
92+
93+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
94+ if (!pp)
95+ return -ENOMEM;
96+
97+ ap->private_data = pp;
98+
99+ cmd = readl(port_mmio + PORT_CMD);
100+
101+ if (cmd & PORT_CMD_ALPE)
102+ pp->init_alpe = true;
103+
104+ if (cmd & PORT_CMD_ASP)
105+ pp->init_asp = true;
106+
107+ devslp = readl(port_mmio + PORT_DEVSLP);
108+
109+ /* devslp unsupported or disabled */
110+ if (!(devslp & PORT_DEVSLP_DSP) || !(devslp & PORT_DEVSLP_ADSE))
111+ return 0;
112+
113+ pp->init_devslp = true;
114+ pp->init_dito = (devslp >> PORT_DEVSLP_DITO_OFFSET) & 0x3ff;
115+ pp->init_deto = (devslp >> PORT_DEVSLP_DETO_OFFSET) & 0xff;
116+ pp->init_mdat = (devslp >> PORT_DEVSLP_MDAT_OFFSET) & 0x1f;
117+
118+ return 0;
119+}
120+EXPORT_SYMBOL_GPL(ahci_setup_port_privdata);
121+
122 static int ahci_port_start(struct ata_port *ap)
123 {
124 struct ahci_host_priv *hpriv = ap->host->private_data;
125+ struct ahci_port_priv *pp = ap->private_data;
126 struct device *dev = ap->host->dev;
127- struct ahci_port_priv *pp;
128 void *mem;
129 dma_addr_t mem_dma;
130 size_t dma_sz, rx_fis_sz;
131
132- pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
133- if (!pp)
134- return -ENOMEM;
135-
136 if (ap->host->n_ports > 1) {
137 pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
138 if (!pp->irq_desc) {
139@@ -2303,8 +2337,6 @@ static int ahci_port_start(struct ata_port *ap)
140 ap->lock = &pp->lock;
141 }
142
143- ap->private_data = pp;
144-
145 /* engage engines, captain */
146 return ahci_port_resume(ap);
147 }
148diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
149index d89305d..39946d4 100644
150--- a/drivers/ata/libahci_platform.c
151+++ b/drivers/ata/libahci_platform.c
152@@ -563,6 +563,10 @@ int ahci_platform_init_host(struct platform_device *pdev,
153 if (ap->flags & ATA_FLAG_EM)
154 ap->em_message_type = hpriv->em_msg_type;
155
156+ rc = ahci_setup_port_privdata(ap);
157+ if (rc)
158+ return rc;
159+
160 /* disabled/not-implemented port */
161 if (!(hpriv->port_map & (1 << i)))
162 ap->ops = &ata_dummy_port_ops;
163diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
164index f6cb1f1..c037f33 100644
165--- a/drivers/ata/libata-core.c
166+++ b/drivers/ata/libata-core.c
167@@ -2024,6 +2024,9 @@ retry:
168 }
169 }
170
171+ if (id[79] & SATA_DIPM)
172+ dev->init_dipm = true;
173+
174 *p_class = class;
175
176 return 0;
177@@ -5583,11 +5586,11 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
178 }
179
180 /**
181- * sata_link_init_spd - Initialize link->sata_spd_limit
182- * @link: Link to configure sata_spd_limit for
183+ * sata_link_init_config - Initialize link->sata_spd_limit and init_lpm
184+ * @link: Link to configure sata_spd_limit and init_lpm for
185 *
186- * Initialize @link->[hw_]sata_spd_limit to the currently
187- * configured value.
188+ * Initialize @link->[hw_]sata_spd_limit and @link->init_lpm to the
189+ * currently configured value.
190 *
191 * LOCKING:
192 * Kernel thread context (may sleep).
193@@ -5595,7 +5598,7 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
194 * RETURNS:
195 * 0 on success, -errno on failure.
196 */
197-int sata_link_init_spd(struct ata_link *link)
198+int sata_link_init_config(struct ata_link *link)
199 {
200 u8 spd;
201 int rc;
202@@ -5612,6 +5615,8 @@ int sata_link_init_spd(struct ata_link *link)
203
204 link->sata_spd_limit = link->hw_sata_spd_limit;
205
206+ link->init_lpm = (link->saved_scontrol >> 8) & 0x7;
207+
208 return 0;
209 }
210
211@@ -6161,9 +6166,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
212 ap->cbl = ATA_CBL_SATA;
213
214 /* init sata_spd_limit to the current value */
215- sata_link_init_spd(&ap->link);
216+ sata_link_init_config(&ap->link);
217 if (ap->slave_link)
218- sata_link_init_spd(ap->slave_link);
219+ sata_link_init_config(ap->slave_link);
220
221 /* print per-port info to dmesg */
222 xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
223diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
224index 7ccc084..b9f7ce8 100644
225--- a/drivers/ata/libata-pmp.c
226+++ b/drivers/ata/libata-pmp.c
227@@ -531,7 +531,7 @@ int sata_pmp_attach(struct ata_device *dev)
228 ap->ops->pmp_attach(ap);
229
230 ata_for_each_link(tlink, ap, EDGE)
231- sata_link_init_spd(tlink);
232+ sata_link_init_config(tlink);
233
234 return 0;
235
236diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
237index a998a17..35016d6 100644
238--- a/drivers/ata/libata.h
239+++ b/drivers/ata/libata.h
240@@ -99,7 +99,7 @@ extern bool ata_phys_link_online(struct ata_link *link);
241 extern bool ata_phys_link_offline(struct ata_link *link);
242 extern void ata_dev_init(struct ata_device *dev);
243 extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
244-extern int sata_link_init_spd(struct ata_link *link);
245+extern int sata_link_init_config(struct ata_link *link);
246 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
247 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
248 extern struct ata_port *ata_port_alloc(struct ata_host *host);
249diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
250index 24e311f..a2adf3f 100644
251--- a/drivers/ata/sata_highbank.c
252+++ b/drivers/ata/sata_highbank.c
253@@ -556,6 +556,10 @@ static int ahci_highbank_probe(struct platform_device *pdev)
254 if (ap->flags & ATA_FLAG_EM)
255 ap->em_message_type = hpriv->em_msg_type;
256
257+ rc = ahci_setup_port_privdata(ap);
258+ if (rc)
259+ goto err0;
260+
261 /* disabled/not-implemented port */
262 if (!(hpriv->port_map & (1 << i)))
263 ap->ops = &ata_dummy_port_ops;
264diff --git a/include/linux/libata.h b/include/linux/libata.h
265index 8dad4a3..31c149b 100644
266--- a/include/linux/libata.h
267+++ b/include/linux/libata.h
268@@ -719,6 +719,8 @@ struct ata_device {
269 int spdn_cnt;
270 /* ering is CLEAR_END, read comment above CLEAR_END */
271 struct ata_ering ering;
272+ /* Initial DIPM configuration */
273+ bool init_dipm;
274 };
275
276 /* Fields between ATA_DEVICE_CLEAR_BEGIN and ATA_DEVICE_CLEAR_END are
b912730e 277@@ -800,6 +800,7 @@ struct ata_link {
2155c5a2 278 struct ata_device device[ATA_MAX_DEVICES];
b912730e
AM
279
280 unsigned long last_lpm_change; /* when last LPM change happened */
2155c5a2
JR
281+ u8 init_lpm; /* initial lpm configuration */
282 };
283 #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag)
284 #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0])
285--
2862.3.5
287
288--
289To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
290the body of a message to majordomo@vger.kernel.org
291More majordomo info at http://vger.kernel.org/majordomo-info.html
292Please read the FAQ at http://www.tux.org/lkml/
293From: Matthew Garrett <mjg59@coreos.com>
294Date: Sat, 18 Apr 2015 08:26:35 -0700
295Subject: [PATCH 2/3] libata: Add firmware_default LPM policy
296
297System vendors may configure SATA link power management appropriately for
298their systems in firmware, based on their knowledge of the hardware
299installed. Add an additional LPM policy designed to inherit the
300configuration provided by the firmware.
301
302Signed-off-by: Matthew Garrett <mjg59@coreos.com>
303---
304 .../scsi/link_power_management_policy.txt | 5 +-
305 drivers/ata/libahci.c | 62 +++++++++++++++-------
306 drivers/ata/libata-core.c | 7 ++-
307 drivers/ata/libata-eh.c | 15 +++---
308 drivers/ata/libata-scsi.c | 1 +
309 include/linux/libata.h | 1 +
310 6 files changed, 63 insertions(+), 28 deletions(-)
311
312diff --git a/Documentation/scsi/link_power_management_policy.txt b/Documentation/scsi/link_power_management_policy.txt
313index d18993d..0285601 100644
314--- a/Documentation/scsi/link_power_management_policy.txt
315+++ b/Documentation/scsi/link_power_management_policy.txt
316@@ -1,8 +1,11 @@
317 This parameter allows the user to set the link (interface) power management.
318-There are 3 possible options:
319+There are 4 possible options:
320
321 Value Effect
322 ----------------------------------------------------------------------------
323+firmware_defaults Inherit configuration from the state programmed by
324+ the firmware during system init.
325+
326 min_power Tell the controller to try to make the link use the
327 least possible power when possible. This may
328 sacrifice some performance due to increased latency
329diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
330index f0c7120..fabcff4 100644
331--- a/drivers/ata/libahci.c
332+++ b/drivers/ata/libahci.c
333@@ -684,6 +684,7 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
334 {
335 struct ata_port *ap = link->ap;
336 struct ahci_host_priv *hpriv = ap->host->private_data;
337+ struct ahci_port_priv *ppriv = ap->private_data;
338 struct ahci_port_priv *pp = ap->private_data;
339 void __iomem *port_mmio = ahci_port_base(ap);
340
5076564f 341@@ -701,10 +702,10 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
2155c5a2
JR
342
343 if (hpriv->cap & HOST_CAP_ALPM) {
344 u32 cmd = readl(port_mmio + PORT_CMD);
5076564f
JR
345+ if (!(hints & ATA_LPM_WAKE_ONLY))
346+ cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
2155c5a2
JR
347
348 if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
5076564f
JR
349- if (!(hints & ATA_LPM_WAKE_ONLY))
350- cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
2155c5a2
JR
351 cmd |= PORT_CMD_ICC_ACTIVE;
352
353 writel(cmd, port_mmio + PORT_CMD);
354@@ -711,6 +712,13 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
355
5076564f
JR
356 if (hints & ATA_LPM_WAKE_ONLY)
357 return 0;
2155c5a2
JR
358+ } else if (policy == ATA_LPM_FIRMWARE_DEFAULTS) {
359+ if (ppriv->init_alpe)
360+ cmd |= PORT_CMD_ALPE;
361+ if (ppriv->init_asp)
362+ cmd |= PORT_CMD_ASP;
363+
364+ writel(cmd, port_mmio + PORT_CMD);
365 } else {
366 cmd |= PORT_CMD_ALPE;
367 if (policy == ATA_LPM_MIN_POWER)
368@@ -725,10 +733,17 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
369 if ((hpriv->cap2 & HOST_CAP2_SDS) &&
370 (hpriv->cap2 & HOST_CAP2_SADM) &&
371 (link->device->flags & ATA_DFLAG_DEVSLP)) {
372- if (policy == ATA_LPM_MIN_POWER)
373+ switch (policy) {
374+ case ATA_LPM_MIN_POWER:
375 ahci_set_aggressive_devslp(ap, true);
376- else
377+ break;
378+ case ATA_LPM_FIRMWARE_DEFAULTS:
379+ ahci_set_aggressive_devslp(ap, ppriv->init_devslp);
380+ break;
381+ default:
382 ahci_set_aggressive_devslp(ap, false);
383+ break;
384+ }
385 }
386
387 if (policy == ATA_LPM_MAX_POWER) {
388@@ -1995,6 +2010,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
389 static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
390 {
391 struct ahci_host_priv *hpriv = ap->host->private_data;
392+ struct ahci_port_priv *ppriv = ap->private_data;
393 void __iomem *port_mmio = ahci_port_base(ap);
394 struct ata_device *dev = ap->link.device;
395 u32 devslp, dm, dito, mdat, deto;
396@@ -2030,26 +2046,32 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
397 if (rc)
398 return;
399
400- dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
401- dito = devslp_idle_timeout / (dm + 1);
402- if (dito > 0x3ff)
403- dito = 0x3ff;
404+ if (ppriv->init_devslp) {
405+ dito = ppriv->init_dito;
406+ deto = ppriv->init_deto;
407+ mdat = ppriv->init_mdat;
408+ } else {
409+ dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
410+ dito = devslp_idle_timeout / (dm + 1);
411+ if (dito > 0x3ff)
412+ dito = 0x3ff;
413
414- /* Use the nominal value 10 ms if the read MDAT is zero,
415- * the nominal value of DETO is 20 ms.
416- */
417- if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
418- ATA_LOG_DEVSLP_VALID_MASK) {
419- mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
420- ATA_LOG_DEVSLP_MDAT_MASK;
421- if (!mdat)
422+ /* Use the nominal value 10 ms if the read MDAT is zero,
423+ * the nominal value of DETO is 20 ms.
424+ */
425+ if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
426+ ATA_LOG_DEVSLP_VALID_MASK) {
427+ mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
428+ ATA_LOG_DEVSLP_MDAT_MASK;
429+ if (!mdat)
430+ mdat = 10;
431+ deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
432+ if (!deto)
433+ deto = 20;
434+ } else {
435 mdat = 10;
436- deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
437- if (!deto)
438 deto = 20;
439- } else {
440- mdat = 10;
441- deto = 20;
442+ }
443 }
444
445 devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
446diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
447index c037f33..0a78f01 100644
448--- a/drivers/ata/libata-core.c
449+++ b/drivers/ata/libata-core.c
450@@ -2024,7 +2024,7 @@ retry:
451 }
452 }
453
454- if (id[79] & SATA_DIPM)
455+ if (id[79] & (1 << SATA_DIPM))
456 dev->init_dipm = true;
457
458 *p_class = class;
459@@ -3672,6 +3672,11 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
460 return rc;
461
462 switch (policy) {
463+ case ATA_LPM_FIRMWARE_DEFAULTS:
464+ /* use the values we read at probe */
465+ scontrol &= ~(0x7 << 8);
466+ scontrol |= (link->init_lpm << 8);
467+ break;
468 case ATA_LPM_MAX_POWER:
469 /* disable all LPM transitions */
470 scontrol |= (0x7 << 8);
471diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
472index 07f41be..c36fa56 100644
473--- a/drivers/ata/libata-eh.c
474+++ b/drivers/ata/libata-eh.c
475@@ -3519,9 +3519,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
476 return 0;
477
478 /*
479- * DIPM is enabled only for MIN_POWER as some devices
480- * misbehave when the host NACKs transition to SLUMBER. Order
481- * device and link configurations such that the host always
482+ * DIPM is enabled only for MIN_POWER and FIRMWARE_DEFAULT as some
483+ * devices misbehave when the host NACKs transition to SLUMBER.
484+ * Order device and link configurations such that the host always
485 * allows DIPM requests.
486 */
487 ata_for_each_dev(dev, link, ENABLED) {
488@@ -3581,10 +3581,13 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
489 if (ap && ap->slave_link)
490 ap->slave_link->lpm_policy = policy;
491
492- /* host config updated, enable DIPM if transitioning to MIN_POWER */
493+ /* host config updated, enable DIPM if transitioning to MIN_POWER or
494+ * FIRMWARE_DEFAULT when enabled by firmware
495+ */
496 ata_for_each_dev(dev, link, ENABLED) {
497- if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
498- ata_id_has_dipm(dev->id)) {
499+ if ((policy == ATA_LPM_MIN_POWER && !no_dipm &&
500+ ata_id_has_dipm(dev->id)) ||
501+ (policy == ATA_LPM_FIRMWARE_DEFAULTS && dev->init_dipm)) {
502 err_mask = ata_dev_set_feature(dev,
503 SETFEATURES_SATA_ENABLE, SATA_DIPM);
504 if (err_mask && err_mask != AC_ERR_DEV) {
505diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
506index 3131adc..f1ea052 100644
507--- a/drivers/ata/libata-scsi.c
508+++ b/drivers/ata/libata-scsi.c
509@@ -107,6 +107,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
510 static const char *ata_lpm_policy_names[] = {
511 [ATA_LPM_UNKNOWN] = "max_performance",
512 [ATA_LPM_MAX_POWER] = "max_performance",
513+ [ATA_LPM_FIRMWARE_DEFAULTS] = "firmware_defaults",
514 [ATA_LPM_MED_POWER] = "medium_power",
515 [ATA_LPM_MIN_POWER] = "min_power",
516 };
517diff --git a/include/linux/libata.h b/include/linux/libata.h
518index 31c149b..57b465d 100644
519--- a/include/linux/libata.h
520+++ b/include/linux/libata.h
521@@ -507,6 +507,7 @@ enum ata_completion_errors {
522 enum ata_lpm_policy {
523 ATA_LPM_UNKNOWN,
524 ATA_LPM_MAX_POWER,
525+ ATA_LPM_FIRMWARE_DEFAULTS,
526 ATA_LPM_MED_POWER,
527 ATA_LPM_MIN_POWER,
528 };
529--
5302.3.5
531
532--
533To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
534the body of a message to majordomo@vger.kernel.org
535More majordomo info at http://vger.kernel.org/majordomo-info.html
536Please read the FAQ at http://www.tux.org/lkml/
537From: Matthew Garrett <mjg59@coreos.com>
538Date: Sat, 18 Apr 2015 08:26:36 -0700
539Subject: [PATCH 3/3] libata: Change medium_power LPM policy to match Intel recommendations
540
541Intel publish a document on designing energy efficient SATA devices at
542http://www.intel.com/content/dam/doc/reference-guide/sata-devices-implementation-recommendations.pdf
543which recommends that ALPE be set, ASPE be cleared and that DIPM be enabled
544on the device. Right now we have no policy that matches that - medium_power
545does not enable DIPM and min_power sets ASPE. Change medium_power to
546implement these recommendations, with the addition of devslp state being
547inherited from the initial configuration. With luck this will provide
548reasonable power savings without causing the device breakages we
549occasionally see with the min_power policy.
550
551Signed-off-by: Matthew Garrett <mjg59@coreos.com>
552---
553 drivers/ata/libahci.c | 1 +
554 drivers/ata/libata-core.c | 4 ----
555 drivers/ata/libata-eh.c | 10 ++++------
556 3 files changed, 5 insertions(+), 10 deletions(-)
557
558diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
559index fabcff4..8efacb9 100644
560--- a/drivers/ata/libahci.c
561+++ b/drivers/ata/libahci.c
562@@ -738,6 +738,7 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
563 ahci_set_aggressive_devslp(ap, true);
564 break;
565 case ATA_LPM_FIRMWARE_DEFAULTS:
566+ case ATA_LPM_MED_POWER:
567 ahci_set_aggressive_devslp(ap, ppriv->init_devslp);
568 break;
569 default:
570diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
571index 0a78f01..99a7b8f 100644
572--- a/drivers/ata/libata-core.c
573+++ b/drivers/ata/libata-core.c
574@@ -3687,10 +3687,6 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
575 }
576 break;
577 case ATA_LPM_MED_POWER:
578- /* allow LPM to PARTIAL */
579- scontrol &= ~(0x1 << 8);
580- scontrol |= (0x6 << 8);
581- break;
582 case ATA_LPM_MIN_POWER:
583 if (ata_link_nr_enabled(link) > 0)
584 /* no restrictions on LPM transitions */
585diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
586index c36fa56..25d5f37 100644
587--- a/drivers/ata/libata-eh.c
588+++ b/drivers/ata/libata-eh.c
589@@ -3519,8 +3519,6 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
590 return 0;
591
592 /*
593- * DIPM is enabled only for MIN_POWER and FIRMWARE_DEFAULT as some
594- * devices misbehave when the host NACKs transition to SLUMBER.
595 * Order device and link configurations such that the host always
596 * allows DIPM requests.
597 */
598@@ -3540,7 +3538,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
599 hints &= ~ATA_LPM_HIPM;
600
601 /* disable DIPM before changing link config */
602- if (policy != ATA_LPM_MIN_POWER && dipm) {
603+ if (policy < ATA_LPM_MED_POWER && dipm) {
604 err_mask = ata_dev_set_feature(dev,
605 SETFEATURES_SATA_DISABLE, SATA_DIPM);
606 if (err_mask && err_mask != AC_ERR_DEV) {
607@@ -3581,11 +3579,11 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
608 if (ap && ap->slave_link)
609 ap->slave_link->lpm_policy = policy;
610
611- /* host config updated, enable DIPM if transitioning to MIN_POWER or
612- * FIRMWARE_DEFAULT when enabled by firmware
613+ /* host config updated, enable DIPM if transitioning to MED_POWER,
614+ * MIN_POWER or FIRMWARE_DEFAULT when enabled by firmware
615 */
616 ata_for_each_dev(dev, link, ENABLED) {
617- if ((policy == ATA_LPM_MIN_POWER && !no_dipm &&
618+ if ((policy >= ATA_LPM_MED_POWER && !no_dipm &&
619 ata_id_has_dipm(dev->id)) ||
620 (policy == ATA_LPM_FIRMWARE_DEFAULTS && dev->init_dipm)) {
621 err_mask = ata_dev_set_feature(dev,
622--
6232.3.5
624
625--
626To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
627the body of a message to majordomo@vger.kernel.org
628More majordomo info at http://vger.kernel.org/majordomo-info.html
629Please read the FAQ at http://www.tux.org/lkml/
This page took 0.097547 seconds and 4 git commands to generate.