aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/libahci.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 8cdf0afd551d..2d21b46db714 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -225,6 +225,31 @@ static void ahci_enable_ahci(void __iomem *mmio)
225 WARN_ON(1); 225 WARN_ON(1);
226} 226}
227 227
228/**
229 * ahci_rpm_get_port - Make sure the port is powered on
230 * @ap: Port to power on
231 *
232 * Whenever there is need to access the AHCI host registers outside of
233 * normal execution paths, call this function to make sure the host is
234 * actually powered on.
235 */
236static int ahci_rpm_get_port(struct ata_port *ap)
237{
238 return pm_runtime_get_sync(ap->dev);
239}
240
241/**
242 * ahci_rpm_put_port - Undoes ahci_rpm_get_port()
243 * @ap: Port to power down
244 *
245 * Undoes ahci_rpm_get_port() and possibly powers down the AHCI host
246 * if it has no more active users.
247 */
248static void ahci_rpm_put_port(struct ata_port *ap)
249{
250 pm_runtime_put(ap->dev);
251}
252
228static ssize_t ahci_show_host_caps(struct device *dev, 253static ssize_t ahci_show_host_caps(struct device *dev,
229 struct device_attribute *attr, char *buf) 254 struct device_attribute *attr, char *buf)
230{ 255{
@@ -261,8 +286,13 @@ static ssize_t ahci_show_port_cmd(struct device *dev,
261 struct Scsi_Host *shost = class_to_shost(dev); 286 struct Scsi_Host *shost = class_to_shost(dev);
262 struct ata_port *ap = ata_shost_to_port(shost); 287 struct ata_port *ap = ata_shost_to_port(shost);
263 void __iomem *port_mmio = ahci_port_base(ap); 288 void __iomem *port_mmio = ahci_port_base(ap);
289 ssize_t ret;
264 290
265 return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD)); 291 ahci_rpm_get_port(ap);
292 ret = sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
293 ahci_rpm_put_port(ap);
294
295 return ret;
266} 296}
267 297
268static ssize_t ahci_read_em_buffer(struct device *dev, 298static ssize_t ahci_read_em_buffer(struct device *dev,
@@ -278,17 +308,20 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
278 size_t count; 308 size_t count;
279 int i; 309 int i;
280 310
311 ahci_rpm_get_port(ap);
281 spin_lock_irqsave(ap->lock, flags); 312 spin_lock_irqsave(ap->lock, flags);
282 313
283 em_ctl = readl(mmio + HOST_EM_CTL); 314 em_ctl = readl(mmio + HOST_EM_CTL);
284 if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT || 315 if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
285 !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) { 316 !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
286 spin_unlock_irqrestore(ap->lock, flags); 317 spin_unlock_irqrestore(ap->lock, flags);
318 ahci_rpm_put_port(ap);
287 return -EINVAL; 319 return -EINVAL;
288 } 320 }
289 321
290 if (!(em_ctl & EM_CTL_MR)) { 322 if (!(em_ctl & EM_CTL_MR)) {
291 spin_unlock_irqrestore(ap->lock, flags); 323 spin_unlock_irqrestore(ap->lock, flags);
324 ahci_rpm_put_port(ap);
292 return -EAGAIN; 325 return -EAGAIN;
293 } 326 }
294 327
@@ -316,6 +349,7 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
316 } 349 }
317 350
318 spin_unlock_irqrestore(ap->lock, flags); 351 spin_unlock_irqrestore(ap->lock, flags);
352 ahci_rpm_put_port(ap);
319 353
320 return i; 354 return i;
321} 355}
@@ -340,11 +374,13 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
340 size % 4 || size > hpriv->em_buf_sz) 374 size % 4 || size > hpriv->em_buf_sz)
341 return -EINVAL; 375 return -EINVAL;
342 376
377 ahci_rpm_get_port(ap);
343 spin_lock_irqsave(ap->lock, flags); 378 spin_lock_irqsave(ap->lock, flags);
344 379
345 em_ctl = readl(mmio + HOST_EM_CTL); 380 em_ctl = readl(mmio + HOST_EM_CTL);
346 if (em_ctl & EM_CTL_TM) { 381 if (em_ctl & EM_CTL_TM) {
347 spin_unlock_irqrestore(ap->lock, flags); 382 spin_unlock_irqrestore(ap->lock, flags);
383 ahci_rpm_put_port(ap);
348 return -EBUSY; 384 return -EBUSY;
349 } 385 }
350 386
@@ -357,6 +393,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
357 writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); 393 writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
358 394
359 spin_unlock_irqrestore(ap->lock, flags); 395 spin_unlock_irqrestore(ap->lock, flags);
396 ahci_rpm_put_port(ap);
360 397
361 return size; 398 return size;
362} 399}
@@ -370,7 +407,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
370 void __iomem *mmio = hpriv->mmio; 407 void __iomem *mmio = hpriv->mmio;
371 u32 em_ctl; 408 u32 em_ctl;
372 409
410 ahci_rpm_get_port(ap);
373 em_ctl = readl(mmio + HOST_EM_CTL); 411 em_ctl = readl(mmio + HOST_EM_CTL);
412 ahci_rpm_put_port(ap);
374 413
375 return sprintf(buf, "%s%s%s%s\n", 414 return sprintf(buf, "%s%s%s%s\n",
376 em_ctl & EM_CTL_LED ? "led " : "", 415 em_ctl & EM_CTL_LED ? "led " : "",
@@ -1014,6 +1053,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
1014 else 1053 else
1015 return -EINVAL; 1054 return -EINVAL;
1016 1055
1056 ahci_rpm_get_port(ap);
1017 spin_lock_irqsave(ap->lock, flags); 1057 spin_lock_irqsave(ap->lock, flags);
1018 1058
1019 /* 1059 /*
@@ -1023,6 +1063,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
1023 em_ctl = readl(mmio + HOST_EM_CTL); 1063 em_ctl = readl(mmio + HOST_EM_CTL);
1024 if (em_ctl & EM_CTL_TM) { 1064 if (em_ctl & EM_CTL_TM) {
1025 spin_unlock_irqrestore(ap->lock, flags); 1065 spin_unlock_irqrestore(ap->lock, flags);
1066 ahci_rpm_put_port(ap);
1026 return -EBUSY; 1067 return -EBUSY;
1027 } 1068 }
1028 1069
@@ -1050,6 +1091,8 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
1050 emp->led_state = state; 1091 emp->led_state = state;
1051 1092
1052 spin_unlock_irqrestore(ap->lock, flags); 1093 spin_unlock_irqrestore(ap->lock, flags);
1094 ahci_rpm_put_port(ap);
1095
1053 return size; 1096 return size;
1054} 1097}
1055 1098
@@ -2216,6 +2259,8 @@ static void ahci_pmp_detach(struct ata_port *ap)
2216 2259
2217int ahci_port_resume(struct ata_port *ap) 2260int ahci_port_resume(struct ata_port *ap)
2218{ 2261{
2262 ahci_rpm_get_port(ap);
2263
2219 ahci_power_up(ap); 2264 ahci_power_up(ap);
2220 ahci_start_port(ap); 2265 ahci_start_port(ap);
2221 2266
@@ -2242,6 +2287,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2242 ata_port_freeze(ap); 2287 ata_port_freeze(ap);
2243 } 2288 }
2244 2289
2290 ahci_rpm_put_port(ap);
2245 return rc; 2291 return rc;
2246} 2292}
2247#endif 2293#endif