Blame view

drivers/ata/libahci.c 66.7 KB
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1
2
3
  /*
   *  libahci.c - Common AHCI SATA low-level routines
   *
8c3d3d4b1   Tejun Heo   libata: update "M...
4
   *  Maintained by:  Tejun Heo <tj@kernel.org>
365cfa1ed   Anton Vorontsov   ahci: Move generi...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
   *    		    Please ALWAYS copy linux-ide@vger.kernel.org
   *		    on emails.
   *
   *  Copyright 2004-2005 Red Hat, Inc.
   *
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2, or (at your option)
   *  any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; see the file COPYING.  If not, write to
   *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   *
   * libata documentation is available via 'make {ps|pdf}docs',
   * as Documentation/DocBook/libata.*
   *
   * AHCI hardware documentation:
   * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
   * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
   *
   */
  
  #include <linux/kernel.h>
fbaf666b8   Tejun Heo   libata: update gf...
36
  #include <linux/gfp.h>
365cfa1ed   Anton Vorontsov   ahci: Move generi...
37
  #include <linux/module.h>
365cfa1ed   Anton Vorontsov   ahci: Move generi...
38
39
40
41
42
43
44
45
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/dma-mapping.h>
  #include <linux/device.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_cmnd.h>
  #include <linux/libata.h>
d684a90d3   Dan Williams   ahci: per-port ms...
46
  #include <linux/pci.h>
365cfa1ed   Anton Vorontsov   ahci: Move generi...
47
  #include "ahci.h"
65fe1f0f6   Shane Huang   ahci: implement a...
48
  #include "libata.h"
365cfa1ed   Anton Vorontsov   ahci: Move generi...
49
50
51
52
53
54
55
56
57
58
  
  static int ahci_skip_host_reset;
  int ahci_ignore_sss;
  EXPORT_SYMBOL_GPL(ahci_ignore_sss);
  
  module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
  MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
  
  module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
  MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
6b7ae9545   Tejun Heo   libata: reimpleme...
59
60
  static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
  			unsigned hints);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
61
62
63
64
65
66
67
68
69
70
  static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
  static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
  			      size_t size);
  static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
  					ssize_t size);
  
  
  
  static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
  static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
71
72
73
74
75
76
77
  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
  static int ahci_port_start(struct ata_port *ap);
  static void ahci_port_stop(struct ata_port *ap);
  static void ahci_qc_prep(struct ata_queued_cmd *qc);
  static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
  static void ahci_freeze(struct ata_port *ap);
  static void ahci_thaw(struct ata_port *ap);
65fe1f0f6   Shane Huang   ahci: implement a...
78
  static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
79
80
81
82
83
84
  static void ahci_enable_fbs(struct ata_port *ap);
  static void ahci_disable_fbs(struct ata_port *ap);
  static void ahci_pmp_attach(struct ata_port *ap);
  static void ahci_pmp_detach(struct ata_port *ap);
  static int ahci_softreset(struct ata_link *link, unsigned int *class,
  			  unsigned long deadline);
345347c5d   Yuan-Hsin Chen   ahci: move ahci_s...
85
86
  static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
  			  unsigned long deadline);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
87
88
89
  static int ahci_hardreset(struct ata_link *link, unsigned int *class,
  			  unsigned long deadline);
  static void ahci_postreset(struct ata_link *link, unsigned int *class);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
90
  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
91
  static void ahci_dev_config(struct ata_device *dev);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  #ifdef CONFIG_PM
  static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
  #endif
  static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
  static ssize_t ahci_activity_store(struct ata_device *dev,
  				   enum sw_activity val);
  static void ahci_init_sw_activity(struct ata_link *link);
  
  static ssize_t ahci_show_host_caps(struct device *dev,
  				   struct device_attribute *attr, char *buf);
  static ssize_t ahci_show_host_cap2(struct device *dev,
  				   struct device_attribute *attr, char *buf);
  static ssize_t ahci_show_host_version(struct device *dev,
  				      struct device_attribute *attr, char *buf);
  static ssize_t ahci_show_port_cmd(struct device *dev,
  				  struct device_attribute *attr, char *buf);
c06231661   Harry Zhang   ahci: add "em_buf...
108
109
110
111
112
  static ssize_t ahci_read_em_buffer(struct device *dev,
  				   struct device_attribute *attr, char *buf);
  static ssize_t ahci_store_em_buffer(struct device *dev,
  				    struct device_attribute *attr,
  				    const char *buf, size_t size);
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
113
114
  static ssize_t ahci_show_em_supported(struct device *dev,
  				      struct device_attribute *attr, char *buf);
f070d6715   Suman Tripathi   libahci: Implemen...
115
  static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
116
117
118
119
120
  
  static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
  static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
  static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
  static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
c06231661   Harry Zhang   ahci: add "em_buf...
121
122
  static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
  		   ahci_read_em_buffer, ahci_store_em_buffer);
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
123
  static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
124

fad16e7a7   Tejun Heo   ahci: fix module ...
125
  struct device_attribute *ahci_shost_attrs[] = {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
126
127
128
129
130
131
132
  	&dev_attr_link_power_management_policy,
  	&dev_attr_em_message_type,
  	&dev_attr_em_message,
  	&dev_attr_ahci_host_caps,
  	&dev_attr_ahci_host_cap2,
  	&dev_attr_ahci_host_version,
  	&dev_attr_ahci_port_cmd,
c06231661   Harry Zhang   ahci: add "em_buf...
133
  	&dev_attr_em_buffer,
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
134
  	&dev_attr_em_message_supported,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
135
136
  	NULL
  };
fad16e7a7   Tejun Heo   ahci: fix module ...
137
  EXPORT_SYMBOL_GPL(ahci_shost_attrs);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
138

fad16e7a7   Tejun Heo   ahci: fix module ...
139
  struct device_attribute *ahci_sdev_attrs[] = {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
140
141
142
143
  	&dev_attr_sw_activity,
  	&dev_attr_unload_heads,
  	NULL
  };
fad16e7a7   Tejun Heo   ahci: fix module ...
144
  EXPORT_SYMBOL_GPL(ahci_sdev_attrs);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  
  struct ata_port_operations ahci_ops = {
  	.inherits		= &sata_pmp_port_ops,
  
  	.qc_defer		= ahci_pmp_qc_defer,
  	.qc_prep		= ahci_qc_prep,
  	.qc_issue		= ahci_qc_issue,
  	.qc_fill_rtf		= ahci_qc_fill_rtf,
  
  	.freeze			= ahci_freeze,
  	.thaw			= ahci_thaw,
  	.softreset		= ahci_softreset,
  	.hardreset		= ahci_hardreset,
  	.postreset		= ahci_postreset,
  	.pmp_softreset		= ahci_softreset,
  	.error_handler		= ahci_error_handler,
  	.post_internal_cmd	= ahci_post_internal_cmd,
  	.dev_config		= ahci_dev_config,
  
  	.scr_read		= ahci_scr_read,
  	.scr_write		= ahci_scr_write,
  	.pmp_attach		= ahci_pmp_attach,
  	.pmp_detach		= ahci_pmp_detach,
6b7ae9545   Tejun Heo   libata: reimpleme...
168
  	.set_lpm		= ahci_set_lpm,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
169
170
171
172
  	.em_show		= ahci_led_show,
  	.em_store		= ahci_led_store,
  	.sw_activity_show	= ahci_activity_show,
  	.sw_activity_store	= ahci_activity_store,
439d7a358   Mark Langsdorf   ahci: make ahci_t...
173
  	.transmit_led_message	= ahci_transmit_led_message,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
174
175
176
177
178
179
180
181
  #ifdef CONFIG_PM
  	.port_suspend		= ahci_port_suspend,
  	.port_resume		= ahci_port_resume,
  #endif
  	.port_start		= ahci_port_start,
  	.port_stop		= ahci_port_stop,
  };
  EXPORT_SYMBOL_GPL(ahci_ops);
345347c5d   Yuan-Hsin Chen   ahci: move ahci_s...
182
183
184
185
186
  struct ata_port_operations ahci_pmp_retry_srst_ops = {
  	.inherits		= &ahci_ops,
  	.softreset		= ahci_pmp_retry_softreset,
  };
  EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops);
ed08d40cd   Chuansheng Liu   ahci: Changing tw...
187
  static bool ahci_em_messages __read_mostly = true;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
188
  EXPORT_SYMBOL_GPL(ahci_em_messages);
ed08d40cd   Chuansheng Liu   ahci: Changing tw...
189
  module_param(ahci_em_messages, bool, 0444);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
190
191
  /* add other LED protocol types when they become supported */
  MODULE_PARM_DESC(ahci_em_messages,
008dbd61e   Harry Zhang   ahci: EM message ...
192
  	"AHCI Enclosure Management Message control (0 = off, 1 = on)");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
193

ed08d40cd   Chuansheng Liu   ahci: Changing tw...
194
195
  /* device sleep idle timeout in ms */
  static int devslp_idle_timeout __read_mostly = 1000;
65fe1f0f6   Shane Huang   ahci: implement a...
196
197
  module_param(devslp_idle_timeout, int, 0644);
  MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  static void ahci_enable_ahci(void __iomem *mmio)
  {
  	int i;
  	u32 tmp;
  
  	/* turn on AHCI_EN */
  	tmp = readl(mmio + HOST_CTL);
  	if (tmp & HOST_AHCI_EN)
  		return;
  
  	/* Some controllers need AHCI_EN to be written multiple times.
  	 * Try a few times before giving up.
  	 */
  	for (i = 0; i < 5; i++) {
  		tmp |= HOST_AHCI_EN;
  		writel(tmp, mmio + HOST_CTL);
  		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
  		if (tmp & HOST_AHCI_EN)
  			return;
  		msleep(10);
  	}
  
  	WARN_ON(1);
  }
bb03c6406   Mika Westerberg   ahci: Add functio...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  /**
   *	ahci_rpm_get_port - Make sure the port is powered on
   *	@ap: Port to power on
   *
   *	Whenever there is need to access the AHCI host registers outside of
   *	normal execution paths, call this function to make sure the host is
   *	actually powered on.
   */
  static int ahci_rpm_get_port(struct ata_port *ap)
  {
  	return pm_runtime_get_sync(ap->dev);
  }
  
  /**
   *	ahci_rpm_put_port - Undoes ahci_rpm_get_port()
   *	@ap: Port to power down
   *
   *	Undoes ahci_rpm_get_port() and possibly powers down the AHCI host
   *	if it has no more active users.
   */
  static void ahci_rpm_put_port(struct ata_port *ap)
  {
  	pm_runtime_put(ap->dev);
  }
365cfa1ed   Anton Vorontsov   ahci: Move generi...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  static ssize_t ahci_show_host_caps(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  
  	return sprintf(buf, "%x
  ", hpriv->cap);
  }
  
  static ssize_t ahci_show_host_cap2(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  
  	return sprintf(buf, "%x
  ", hpriv->cap2);
  }
  
  static ssize_t ahci_show_host_version(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
274

8ea909cb3   Mika Westerberg   ahci: Cache host ...
275
276
  	return sprintf(buf, "%x
  ", hpriv->version);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
277
278
279
280
281
282
283
284
  }
  
  static ssize_t ahci_show_port_cmd(struct device *dev,
  				  struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	void __iomem *port_mmio = ahci_port_base(ap);
bb03c6406   Mika Westerberg   ahci: Add functio...
285
  	ssize_t ret;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
286

bb03c6406   Mika Westerberg   ahci: Add functio...
287
288
289
290
291
292
  	ahci_rpm_get_port(ap);
  	ret = sprintf(buf, "%x
  ", readl(port_mmio + PORT_CMD));
  	ahci_rpm_put_port(ap);
  
  	return ret;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
293
  }
c06231661   Harry Zhang   ahci: add "em_buf...
294
295
296
297
298
299
300
301
302
303
304
305
  static ssize_t ahci_read_em_buffer(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	void __iomem *em_mmio = mmio + hpriv->em_loc;
  	u32 em_ctl, msg;
  	unsigned long flags;
  	size_t count;
  	int i;
bb03c6406   Mika Westerberg   ahci: Add functio...
306
  	ahci_rpm_get_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
307
308
309
310
311
312
  	spin_lock_irqsave(ap->lock, flags);
  
  	em_ctl = readl(mmio + HOST_EM_CTL);
  	if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
  	    !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
  		spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
313
  		ahci_rpm_put_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
314
315
316
317
318
  		return -EINVAL;
  	}
  
  	if (!(em_ctl & EM_CTL_MR)) {
  		spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
319
  		ahci_rpm_put_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
320
321
322
323
324
325
326
327
328
329
330
  		return -EAGAIN;
  	}
  
  	if (!(em_ctl & EM_CTL_SMB))
  		em_mmio += hpriv->em_buf_sz;
  
  	count = hpriv->em_buf_sz;
  
  	/* the count should not be larger than PAGE_SIZE */
  	if (count > PAGE_SIZE) {
  		if (printk_ratelimit())
a9a79dfec   Joe Perches   ata: Convert ata_...
331
332
333
334
335
  			ata_port_warn(ap,
  				      "EM read buffer size too large: "
  				      "buffer size %u, page size %lu
  ",
  				      hpriv->em_buf_sz, PAGE_SIZE);
c06231661   Harry Zhang   ahci: add "em_buf...
336
337
338
339
340
341
342
343
344
345
346
347
  		count = PAGE_SIZE;
  	}
  
  	for (i = 0; i < count; i += 4) {
  		msg = readl(em_mmio + i);
  		buf[i] = msg & 0xff;
  		buf[i + 1] = (msg >> 8) & 0xff;
  		buf[i + 2] = (msg >> 16) & 0xff;
  		buf[i + 3] = (msg >> 24) & 0xff;
  	}
  
  	spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
348
  	ahci_rpm_put_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
349
350
351
352
353
354
355
356
357
358
359
360
361
  
  	return i;
  }
  
  static ssize_t ahci_store_em_buffer(struct device *dev,
  				    struct device_attribute *attr,
  				    const char *buf, size_t size)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	void __iomem *em_mmio = mmio + hpriv->em_loc;
f9ce889b8   Harry Zhang   libahci: Fix bug ...
362
  	const unsigned char *msg_buf = buf;
c06231661   Harry Zhang   ahci: add "em_buf...
363
364
365
366
367
368
369
370
371
  	u32 em_ctl, msg;
  	unsigned long flags;
  	int i;
  
  	/* check size validity */
  	if (!(ap->flags & ATA_FLAG_EM) ||
  	    !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO) ||
  	    size % 4 || size > hpriv->em_buf_sz)
  		return -EINVAL;
bb03c6406   Mika Westerberg   ahci: Add functio...
372
  	ahci_rpm_get_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
373
374
375
376
377
  	spin_lock_irqsave(ap->lock, flags);
  
  	em_ctl = readl(mmio + HOST_EM_CTL);
  	if (em_ctl & EM_CTL_TM) {
  		spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
378
  		ahci_rpm_put_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
379
380
381
382
  		return -EBUSY;
  	}
  
  	for (i = 0; i < size; i += 4) {
f9ce889b8   Harry Zhang   libahci: Fix bug ...
383
384
  		msg = msg_buf[i] | msg_buf[i + 1] << 8 |
  		      msg_buf[i + 2] << 16 | msg_buf[i + 3] << 24;
c06231661   Harry Zhang   ahci: add "em_buf...
385
386
387
388
389
390
  		writel(msg, em_mmio + i);
  	}
  
  	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
  
  	spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
391
  	ahci_rpm_put_port(ap);
c06231661   Harry Zhang   ahci: add "em_buf...
392
393
394
  
  	return size;
  }
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
395
396
397
398
399
400
401
402
  static ssize_t ahci_show_em_supported(struct device *dev,
  				      struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct ata_port *ap = ata_shost_to_port(shost);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	u32 em_ctl;
bb03c6406   Mika Westerberg   ahci: Add functio...
403
  	ahci_rpm_get_port(ap);
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
404
  	em_ctl = readl(mmio + HOST_EM_CTL);
bb03c6406   Mika Westerberg   ahci: Add functio...
405
  	ahci_rpm_put_port(ap);
6e5fe5b12   Hannes Reinecke   ahci: EM supporte...
406
407
408
409
410
411
412
413
  
  	return sprintf(buf, "%s%s%s%s
  ",
  		       em_ctl & EM_CTL_LED ? "led " : "",
  		       em_ctl & EM_CTL_SAFTE ? "saf-te " : "",
  		       em_ctl & EM_CTL_SES ? "ses-2 " : "",
  		       em_ctl & EM_CTL_SGPIO ? "sgpio " : "");
  }
365cfa1ed   Anton Vorontsov   ahci: Move generi...
414
415
416
417
  /**
   *	ahci_save_initial_config - Save and fixup initial config values
   *	@dev: target AHCI device
   *	@hpriv: host private area to store config values
365cfa1ed   Anton Vorontsov   ahci: Move generi...
418
419
420
421
422
423
424
425
   *
   *	Some registers containing configuration info might be setup by
   *	BIOS and might be cleared on reset.  This function saves the
   *	initial values of those registers into @hpriv such that they
   *	can be restored after controller reset.
   *
   *	If inconsistent, config values are fixed up by this function.
   *
039ece38d   Hans de Goede   libahci: Allow dr...
426
427
428
   *	If it is not set already this function sets hpriv->start_engine to
   *	ahci_start_engine.
   *
365cfa1ed   Anton Vorontsov   ahci: Move generi...
429
430
431
   *	LOCKING:
   *	None.
   */
725c7b570   Antoine Ténart   ata: libahci_plat...
432
  void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  {
  	void __iomem *mmio = hpriv->mmio;
  	u32 cap, cap2, vers, port_map;
  	int i;
  
  	/* make sure AHCI mode is enabled before accessing CAP */
  	ahci_enable_ahci(mmio);
  
  	/* Values prefixed with saved_ are written back to host after
  	 * reset.  Values without are used for driver operation.
  	 */
  	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
  	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
  
  	/* CAP2 register is only defined for AHCI 1.2 and later */
  	vers = readl(mmio + HOST_VERSION);
  	if ((vers >> 16) > 1 ||
  	   ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
  		hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
  	else
  		hpriv->saved_cap2 = cap2 = 0;
  
  	/* some chips have errata preventing 64bit use */
  	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
457
458
  		dev_info(dev, "controller can't do 64bit DMA, forcing 32bit
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
459
460
461
462
  		cap &= ~HOST_CAP_64;
  	}
  
  	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
463
464
  		dev_info(dev, "controller can't do NCQ, turning off CAP_NCQ
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
465
466
467
468
  		cap &= ~HOST_CAP_NCQ;
  	}
  
  	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
469
470
  		dev_info(dev, "controller can do NCQ, turning on CAP_NCQ
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
471
472
473
474
  		cap |= HOST_CAP_NCQ;
  	}
  
  	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
475
476
  		dev_info(dev, "controller can't do PMP, turning off CAP_PMP
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
477
478
479
480
  		cap &= ~HOST_CAP_PMP;
  	}
  
  	if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
481
482
483
  		dev_info(dev,
  			 "controller can't do SNTF, turning off CAP_SNTF
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
484
485
  		cap &= ~HOST_CAP_SNTF;
  	}
0cf4a7d6c   Jacob Pan   ahci: disable DEV...
486
487
488
489
490
491
492
  	if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) {
  		dev_info(dev,
  			 "controller can't do DEVSLP, turning off
  ");
  		cap2 &= ~HOST_CAP2_SDS;
  		cap2 &= ~HOST_CAP2_SADM;
  	}
5f173107e   Tejun Heo   ahci: add HFLAG_Y...
493
  	if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
494
495
  		dev_info(dev, "controller can do FBS, turning on CAP_FBS
  ");
5f173107e   Tejun Heo   ahci: add HFLAG_Y...
496
497
  		cap |= HOST_CAP_FBS;
  	}
888d91a08   Kefeng Wang   ata: ahci: append...
498
499
500
501
502
  	if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) {
  		dev_info(dev, "controller can't do FBS, turning off CAP_FBS
  ");
  		cap &= ~HOST_CAP_FBS;
  	}
725c7b570   Antoine Ténart   ata: libahci_plat...
503
  	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
a44fec1fc   Joe Perches   ata: Convert dev_...
504
505
  		dev_info(dev, "forcing port_map 0x%x -> 0x%x
  ",
725c7b570   Antoine Ténart   ata: libahci_plat...
506
507
  			 port_map, hpriv->force_port_map);
  		port_map = hpriv->force_port_map;
2fd0f46cb   Srinivas Kandagatla   libahci: save por...
508
  		hpriv->saved_port_map = port_map;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
509
  	}
725c7b570   Antoine Ténart   ata: libahci_plat...
510
  	if (hpriv->mask_port_map) {
a44fec1fc   Joe Perches   ata: Convert dev_...
511
512
513
  		dev_warn(dev, "masking port_map 0x%x -> 0x%x
  ",
  			port_map,
725c7b570   Antoine Ténart   ata: libahci_plat...
514
515
  			port_map & hpriv->mask_port_map);
  		port_map &= hpriv->mask_port_map;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  	}
  
  	/* cross check port_map and cap.n_ports */
  	if (port_map) {
  		int map_ports = 0;
  
  		for (i = 0; i < AHCI_MAX_PORTS; i++)
  			if (port_map & (1 << i))
  				map_ports++;
  
  		/* If PI has more ports than n_ports, whine, clear
  		 * port_map and let it be generated from n_ports.
  		 */
  		if (map_ports > ahci_nr_ports(cap)) {
a44fec1fc   Joe Perches   ata: Convert dev_...
530
531
532
533
  			dev_warn(dev,
  				 "implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports
  ",
  				 port_map, ahci_nr_ports(cap));
365cfa1ed   Anton Vorontsov   ahci: Move generi...
534
535
536
  			port_map = 0;
  		}
  	}
566d1827d   Tejun Heo   libata: disable f...
537
538
  	/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
  	if (!port_map && vers < 0x10300) {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
539
  		port_map = (1 << ahci_nr_ports(cap)) - 1;
a44fec1fc   Joe Perches   ata: Convert dev_...
540
541
  		dev_warn(dev, "forcing PORTS_IMPL to 0x%x
  ", port_map);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
542
543
544
545
546
547
548
549
  
  		/* write the fixed up value to the PI register */
  		hpriv->saved_port_map = port_map;
  	}
  
  	/* record values to use during operation */
  	hpriv->cap = cap;
  	hpriv->cap2 = cap2;
8ea909cb3   Mika Westerberg   ahci: Cache host ...
550
  	hpriv->version = readl(mmio + HOST_VERSION);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
551
  	hpriv->port_map = port_map;
039ece38d   Hans de Goede   libahci: Allow dr...
552
553
554
  
  	if (!hpriv->start_engine)
  		hpriv->start_engine = ahci_start_engine;
f070d6715   Suman Tripathi   libahci: Implemen...
555
556
  
  	if (!hpriv->irq_handler)
d867b95f9   Suman Tripathi   ata: Remove the A...
557
  		hpriv->irq_handler = ahci_single_level_irq_intr;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  }
  EXPORT_SYMBOL_GPL(ahci_save_initial_config);
  
  /**
   *	ahci_restore_initial_config - Restore initial config
   *	@host: target ATA host
   *
   *	Restore initial config stored by ahci_save_initial_config().
   *
   *	LOCKING:
   *	None.
   */
  static void ahci_restore_initial_config(struct ata_host *host)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  
  	writel(hpriv->saved_cap, mmio + HOST_CAP);
  	if (hpriv->saved_cap2)
  		writel(hpriv->saved_cap2, mmio + HOST_CAP2);
  	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
  	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
  }
  
  static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
  {
  	static const int offset[] = {
  		[SCR_STATUS]		= PORT_SCR_STAT,
  		[SCR_CONTROL]		= PORT_SCR_CTL,
  		[SCR_ERROR]		= PORT_SCR_ERR,
  		[SCR_ACTIVE]		= PORT_SCR_ACT,
  		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
  	};
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  
  	if (sc_reg < ARRAY_SIZE(offset) &&
  	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
  		return offset[sc_reg];
  	return 0;
  }
  
  static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
  {
  	void __iomem *port_mmio = ahci_port_base(link->ap);
  	int offset = ahci_scr_offset(link->ap, sc_reg);
  
  	if (offset) {
  		*val = readl(port_mmio + offset);
  		return 0;
  	}
  	return -EINVAL;
  }
  
  static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
  {
  	void __iomem *port_mmio = ahci_port_base(link->ap);
  	int offset = ahci_scr_offset(link->ap, sc_reg);
  
  	if (offset) {
  		writel(val, port_mmio + offset);
  		return 0;
  	}
  	return -EINVAL;
  }
  
  void ahci_start_engine(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 tmp;
  
  	/* start DMA */
  	tmp = readl(port_mmio + PORT_CMD);
  	tmp |= PORT_CMD_START;
  	writel(tmp, port_mmio + PORT_CMD);
  	readl(port_mmio + PORT_CMD); /* flush */
  }
  EXPORT_SYMBOL_GPL(ahci_start_engine);
  
  int ahci_stop_engine(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
fb3296335   Danesh Petigara   drivers: ata: wak...
639
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
640
  	u32 tmp;
fb3296335   Danesh Petigara   drivers: ata: wak...
641
642
643
644
645
646
647
648
649
650
651
652
653
  	/*
  	 * On some controllers, stopping a port's DMA engine while the port
  	 * is in ALPM state (partial or slumber) results in failures on
  	 * subsequent DMA engine starts.  For those controllers, put the
  	 * port back in active state before stopping its DMA engine.
  	 */
  	if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
  	    (ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
  	    ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
  		dev_err(ap->host->dev, "Failed to wake up port before engine stop
  ");
  		return -EIO;
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
654
655
656
657
658
659
660
661
662
663
664
  	tmp = readl(port_mmio + PORT_CMD);
  
  	/* check if the HBA is idle */
  	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
  		return 0;
  
  	/* setting HBA to idle */
  	tmp &= ~PORT_CMD_START;
  	writel(tmp, port_mmio + PORT_CMD);
  
  	/* wait for engine to stop. This could be as long as 500 msec */
97750cebb   Tejun Heo   libata: add @ap t...
665
  	tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
666
667
668
669
670
671
672
  				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
  	if (tmp & PORT_CMD_LIST_ON)
  		return -EIO;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ahci_stop_engine);
39e0ee996   Suman Tripathi   libahci: export a...
673
  void ahci_start_fis_rx(struct ata_port *ap)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	struct ahci_port_priv *pp = ap->private_data;
  	u32 tmp;
  
  	/* set FIS registers */
  	if (hpriv->cap & HOST_CAP_64)
  		writel((pp->cmd_slot_dma >> 16) >> 16,
  		       port_mmio + PORT_LST_ADDR_HI);
  	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
  
  	if (hpriv->cap & HOST_CAP_64)
  		writel((pp->rx_fis_dma >> 16) >> 16,
  		       port_mmio + PORT_FIS_ADDR_HI);
  	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
  
  	/* enable FIS reception */
  	tmp = readl(port_mmio + PORT_CMD);
  	tmp |= PORT_CMD_FIS_RX;
  	writel(tmp, port_mmio + PORT_CMD);
  
  	/* flush */
  	readl(port_mmio + PORT_CMD);
  }
39e0ee996   Suman Tripathi   libahci: export a...
699
  EXPORT_SYMBOL_GPL(ahci_start_fis_rx);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
700
701
702
703
704
705
706
707
708
709
710
711
  
  static int ahci_stop_fis_rx(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 tmp;
  
  	/* disable FIS reception */
  	tmp = readl(port_mmio + PORT_CMD);
  	tmp &= ~PORT_CMD_FIS_RX;
  	writel(tmp, port_mmio + PORT_CMD);
  
  	/* wait for completion, spec says 500ms, give it 1000 */
97750cebb   Tejun Heo   libata: add @ap t...
712
  	tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
  				PORT_CMD_FIS_ON, 10, 1000);
  	if (tmp & PORT_CMD_FIS_ON)
  		return -EBUSY;
  
  	return 0;
  }
  
  static void ahci_power_up(struct ata_port *ap)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 cmd;
  
  	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
  
  	/* spin up device */
  	if (hpriv->cap & HOST_CAP_SSS) {
  		cmd |= PORT_CMD_SPIN_UP;
  		writel(cmd, port_mmio + PORT_CMD);
  	}
  
  	/* wake up link */
  	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
  }
6b7ae9545   Tejun Heo   libata: reimpleme...
737
738
  static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
  			unsigned int hints)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
739
  {
6b7ae9545   Tejun Heo   libata: reimpleme...
740
  	struct ata_port *ap = link->ap;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
741
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
742
  	struct ahci_port_priv *pp = ap->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
743
  	void __iomem *port_mmio = ahci_port_base(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
744

6b7ae9545   Tejun Heo   libata: reimpleme...
745
  	if (policy != ATA_LPM_MAX_POWER) {
fb3296335   Danesh Petigara   drivers: ata: wak...
746
747
  		/* wakeup flag only applies to the max power policy */
  		hints &= ~ATA_LPM_WAKE_ONLY;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
748
  		/*
6b7ae9545   Tejun Heo   libata: reimpleme...
749
750
751
  		 * Disable interrupts on Phy Ready. This keeps us from
  		 * getting woken up due to spurious phy ready
  		 * interrupts.
365cfa1ed   Anton Vorontsov   ahci: Move generi...
752
  		 */
6b7ae9545   Tejun Heo   libata: reimpleme...
753
754
755
756
  		pp->intr_mask &= ~PORT_IRQ_PHYRDY;
  		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
  
  		sata_link_scr_lpm(link, policy, false);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
757
  	}
6b7ae9545   Tejun Heo   libata: reimpleme...
758
759
  	if (hpriv->cap & HOST_CAP_ALPM) {
  		u32 cmd = readl(port_mmio + PORT_CMD);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
760

6b7ae9545   Tejun Heo   libata: reimpleme...
761
  		if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
fb3296335   Danesh Petigara   drivers: ata: wak...
762
763
  			if (!(hints & ATA_LPM_WAKE_ONLY))
  				cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
6b7ae9545   Tejun Heo   libata: reimpleme...
764
  			cmd |= PORT_CMD_ICC_ACTIVE;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
765

6b7ae9545   Tejun Heo   libata: reimpleme...
766
767
  			writel(cmd, port_mmio + PORT_CMD);
  			readl(port_mmio + PORT_CMD);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
768

6b7ae9545   Tejun Heo   libata: reimpleme...
769
  			/* wait 10ms to be sure we've come out of LPM state */
97750cebb   Tejun Heo   libata: add @ap t...
770
  			ata_msleep(ap, 10);
fb3296335   Danesh Petigara   drivers: ata: wak...
771
772
773
  
  			if (hints & ATA_LPM_WAKE_ONLY)
  				return 0;
6b7ae9545   Tejun Heo   libata: reimpleme...
774
775
776
777
  		} else {
  			cmd |= PORT_CMD_ALPE;
  			if (policy == ATA_LPM_MIN_POWER)
  				cmd |= PORT_CMD_ASP;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
778

6b7ae9545   Tejun Heo   libata: reimpleme...
779
780
781
782
  			/* write out new cmd value */
  			writel(cmd, port_mmio + PORT_CMD);
  		}
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
783

65fe1f0f6   Shane Huang   ahci: implement a...
784
785
786
787
788
789
790
791
792
  	/* set aggressive device sleep */
  	if ((hpriv->cap2 & HOST_CAP2_SDS) &&
  	    (hpriv->cap2 & HOST_CAP2_SADM) &&
  	    (link->device->flags & ATA_DFLAG_DEVSLP)) {
  		if (policy == ATA_LPM_MIN_POWER)
  			ahci_set_aggressive_devslp(ap, true);
  		else
  			ahci_set_aggressive_devslp(ap, false);
  	}
6b7ae9545   Tejun Heo   libata: reimpleme...
793
794
795
796
797
798
799
  	if (policy == ATA_LPM_MAX_POWER) {
  		sata_link_scr_lpm(link, policy, false);
  
  		/* turn PHYRDY IRQ back on */
  		pp->intr_mask |= PORT_IRQ_PHYRDY;
  		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
800

365cfa1ed   Anton Vorontsov   ahci: Move generi...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  	return 0;
  }
  
  #ifdef CONFIG_PM
  static void ahci_power_down(struct ata_port *ap)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 cmd, scontrol;
  
  	if (!(hpriv->cap & HOST_CAP_SSS))
  		return;
  
  	/* put device into listen mode, first set PxSCTL.DET to 0 */
  	scontrol = readl(port_mmio + PORT_SCR_CTL);
  	scontrol &= ~0xf;
  	writel(scontrol, port_mmio + PORT_SCR_CTL);
  
  	/* then set PxCMD.SUD to 0 */
  	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
  	cmd &= ~PORT_CMD_SPIN_UP;
  	writel(cmd, port_mmio + PORT_CMD);
  }
  #endif
  
  static void ahci_start_port(struct ata_port *ap)
  {
66583c9fa   Brian Norris   ahci: add AHCI_HF...
828
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
829
830
831
832
833
834
835
836
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ata_link *link;
  	struct ahci_em_priv *emp;
  	ssize_t rc;
  	int i;
  
  	/* enable FIS reception */
  	ahci_start_fis_rx(ap);
66583c9fa   Brian Norris   ahci: add AHCI_HF...
837
838
  	/* enable DMA */
  	if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
039ece38d   Hans de Goede   libahci: Allow dr...
839
  		hpriv->start_engine(ap);
66583c9fa   Brian Norris   ahci: add AHCI_HF...
840

365cfa1ed   Anton Vorontsov   ahci: Move generi...
841
842
843
844
845
846
847
  	/* turn on LEDs */
  	if (ap->flags & ATA_FLAG_EM) {
  		ata_for_each_link(link, ap, EDGE) {
  			emp = &pp->em_priv[link->pmp];
  
  			/* EM Transmit bit maybe busy during init */
  			for (i = 0; i < EM_MAX_RETRY; i++) {
439d7a358   Mark Langsdorf   ahci: make ahci_t...
848
  				rc = ap->ops->transmit_led_message(ap,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
849
850
  							       emp->led_state,
  							       4);
fa070ee6d   Lukasz Dorau   libahci: fix turn...
851
852
853
854
855
856
857
858
  				/*
  				 * If busy, give a breather but do not
  				 * release EH ownership by using msleep()
  				 * instead of ata_msleep().  EM Transmit
  				 * bit is busy for the whole host and
  				 * releasing ownership will cause other
  				 * ports to fail the same way.
  				 */
365cfa1ed   Anton Vorontsov   ahci: Move generi...
859
  				if (rc == -EBUSY)
fa070ee6d   Lukasz Dorau   libahci: fix turn...
860
  					msleep(1);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  				else
  					break;
  			}
  		}
  	}
  
  	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
  		ata_for_each_link(link, ap, EDGE)
  			ahci_init_sw_activity(link);
  
  }
  
  static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
  {
  	int rc;
  
  	/* disable DMA */
  	rc = ahci_stop_engine(ap);
  	if (rc) {
  		*emsg = "failed to stop engine";
  		return rc;
  	}
  
  	/* disable FIS reception */
  	rc = ahci_stop_fis_rx(ap);
  	if (rc) {
  		*emsg = "failed stop FIS RX";
  		return rc;
  	}
  
  	return 0;
  }
  
  int ahci_reset_controller(struct ata_host *host)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	u32 tmp;
  
  	/* we must be in AHCI mode, before using anything
  	 * AHCI-specific, such as HOST_RESET.
  	 */
  	ahci_enable_ahci(mmio);
  
  	/* global controller reset */
  	if (!ahci_skip_host_reset) {
  		tmp = readl(mmio + HOST_CTL);
  		if ((tmp & HOST_RESET) == 0) {
  			writel(tmp | HOST_RESET, mmio + HOST_CTL);
  			readl(mmio + HOST_CTL); /* flush */
  		}
  
  		/*
  		 * to perform host reset, OS should set HOST_RESET
  		 * and poll until this bit is read to be "0".
  		 * reset must complete within 1 second, or
  		 * the hardware should be considered fried.
  		 */
97750cebb   Tejun Heo   libata: add @ap t...
919
  		tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
920
921
922
  					HOST_RESET, 10, 1000);
  
  		if (tmp & HOST_RESET) {
a44fec1fc   Joe Perches   ata: Convert dev_...
923
924
925
  			dev_err(host->dev, "controller reset failed (0x%x)
  ",
  				tmp);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
926
927
928
929
930
931
932
933
934
935
936
  			return -EIO;
  		}
  
  		/* turn on AHCI mode */
  		ahci_enable_ahci(mmio);
  
  		/* Some registers might be cleared on reset.  Restore
  		 * initial values.
  		 */
  		ahci_restore_initial_config(host);
  	} else
a44fec1fc   Joe Perches   ata: Convert dev_...
937
938
  		dev_info(host->dev, "skipping global host reset
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ahci_reset_controller);
  
  static void ahci_sw_activity(struct ata_link *link)
  {
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
  
  	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
  		return;
  
  	emp->activity++;
  	if (!timer_pending(&emp->timer))
  		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
  }
  
  static void ahci_sw_activity_blink(unsigned long arg)
  {
  	struct ata_link *link = (struct ata_link *)arg;
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
  	unsigned long led_message = emp->led_state;
  	u32 activity_led_state;
  	unsigned long flags;
  
  	led_message &= EM_MSG_LED_VALUE;
  	led_message |= ap->port_no | (link->pmp << 8);
  
  	/* check to see if we've had activity.  If so,
  	 * toggle state of LED and reset timer.  If not,
  	 * turn LED to desired idle state.
  	 */
  	spin_lock_irqsave(ap->lock, flags);
  	if (emp->saved_activity != emp->activity) {
  		emp->saved_activity = emp->activity;
  		/* get the current LED state */
  		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
  
  		if (activity_led_state)
  			activity_led_state = 0;
  		else
  			activity_led_state = 1;
  
  		/* clear old state */
  		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
  
  		/* toggle state */
  		led_message |= (activity_led_state << 16);
  		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
  	} else {
  		/* switch to idle */
  		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
  		if (emp->blink_policy == BLINK_OFF)
  			led_message |= (1 << 16);
  	}
  	spin_unlock_irqrestore(ap->lock, flags);
439d7a358   Mark Langsdorf   ahci: make ahci_t...
999
  	ap->ops->transmit_led_message(ap, led_message, 4);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  }
  
  static void ahci_init_sw_activity(struct ata_link *link)
  {
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
  
  	/* init activity stats, setup timer */
  	emp->saved_activity = emp->activity = 0;
  	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
  
  	/* check our blink policy and set flag for link if it's enabled */
  	if (emp->blink_policy)
  		link->flags |= ATA_LFLAG_SW_ACTIVITY;
  }
  
  int ahci_reset_em(struct ata_host *host)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	u32 em_ctl;
  
  	em_ctl = readl(mmio + HOST_EM_CTL);
  	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
  		return -EINVAL;
  
  	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ahci_reset_em);
  
  static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
  					ssize_t size)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	struct ahci_port_priv *pp = ap->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	u32 em_ctl;
  	u32 message[] = {0, 0};
  	unsigned long flags;
  	int pmp;
  	struct ahci_em_priv *emp;
  
  	/* get the slot number from the message */
  	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
  	if (pmp < EM_MAX_SLOTS)
  		emp = &pp->em_priv[pmp];
  	else
  		return -EINVAL;
bb03c6406   Mika Westerberg   ahci: Add functio...
1050
  	ahci_rpm_get_port(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1051
1052
1053
1054
1055
1056
1057
1058
1059
  	spin_lock_irqsave(ap->lock, flags);
  
  	/*
  	 * if we are still busy transmitting a previous message,
  	 * do not allow
  	 */
  	em_ctl = readl(mmio + HOST_EM_CTL);
  	if (em_ctl & EM_CTL_TM) {
  		spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
1060
  		ahci_rpm_put_port(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1061
1062
  		return -EBUSY;
  	}
008dbd61e   Harry Zhang   ahci: EM message ...
1063
1064
1065
1066
1067
1068
  	if (hpriv->em_msg_type & EM_MSG_TYPE_LED) {
  		/*
  		 * create message header - this is all zero except for
  		 * the message size, which is 4 bytes.
  		 */
  		message[0] |= (4 << 8);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1069

008dbd61e   Harry Zhang   ahci: EM message ...
1070
1071
  		/* ignore 0:4 of byte zero, fill in port info yourself */
  		message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1072

008dbd61e   Harry Zhang   ahci: EM message ...
1073
1074
1075
1076
1077
1078
1079
1080
1081
  		/* write message to EM_LOC */
  		writel(message[0], mmio + hpriv->em_loc);
  		writel(message[1], mmio + hpriv->em_loc+4);
  
  		/*
  		 * tell hardware to transmit the message
  		 */
  		writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1082
1083
1084
  
  	/* save off new led state for port/slot */
  	emp->led_state = state;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1085
  	spin_unlock_irqrestore(ap->lock, flags);
bb03c6406   Mika Westerberg   ahci: Add functio...
1086
  	ahci_rpm_put_port(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
  	return size;
  }
  
  static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
  {
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ata_link *link;
  	struct ahci_em_priv *emp;
  	int rc = 0;
  
  	ata_for_each_link(link, ap, EDGE) {
  		emp = &pp->em_priv[link->pmp];
  		rc += sprintf(buf, "%lx
  ", emp->led_state);
  	}
  	return rc;
  }
  
  static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
  				size_t size)
  {
b2a52b6a0   Daeseok Youn   ata: libahci: rep...
1108
  	unsigned int state;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1109
1110
1111
  	int pmp;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp;
b2a52b6a0   Daeseok Youn   ata: libahci: rep...
1112
1113
  	if (kstrtouint(buf, 0, &state) < 0)
  		return -EINVAL;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  
  	/* get the slot number from the message */
  	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
  	if (pmp < EM_MAX_SLOTS)
  		emp = &pp->em_priv[pmp];
  	else
  		return -EINVAL;
  
  	/* mask off the activity bits if we are in sw_activity
  	 * mode, user should turn off sw_activity before setting
  	 * activity led through em_message
  	 */
  	if (emp->blink_policy)
  		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
439d7a358   Mark Langsdorf   ahci: make ahci_t...
1128
  	return ap->ops->transmit_led_message(ap, state, size);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
  }
  
  static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
  {
  	struct ata_link *link = dev->link;
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
  	u32 port_led_state = emp->led_state;
  
  	/* save the desired Activity LED behavior */
  	if (val == OFF) {
  		/* clear LFLAG */
  		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
  
  		/* set the LED to OFF */
  		port_led_state &= EM_MSG_LED_VALUE_OFF;
  		port_led_state |= (ap->port_no | (link->pmp << 8));
439d7a358   Mark Langsdorf   ahci: make ahci_t...
1147
  		ap->ops->transmit_led_message(ap, port_led_state, 4);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1148
1149
1150
1151
1152
1153
1154
  	} else {
  		link->flags |= ATA_LFLAG_SW_ACTIVITY;
  		if (val == BLINK_OFF) {
  			/* set LED to ON for idle */
  			port_led_state &= EM_MSG_LED_VALUE_OFF;
  			port_led_state |= (ap->port_no | (link->pmp << 8));
  			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
439d7a358   Mark Langsdorf   ahci: make ahci_t...
1155
  			ap->ops->transmit_led_message(ap, port_led_state, 4);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  		}
  	}
  	emp->blink_policy = val;
  	return 0;
  }
  
  static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
  {
  	struct ata_link *link = dev->link;
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
  
  	/* display the saved value of activity behavior for this
  	 * disk.
  	 */
  	return sprintf(buf, "%d
  ", emp->blink_policy);
  }
  
  static void ahci_port_init(struct device *dev, struct ata_port *ap,
  			   int port_no, void __iomem *mmio,
  			   void __iomem *port_mmio)
  {
8a3e33cf9   Manuel Lauss   ata: ahci: find e...
1180
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
  	const char *emsg = NULL;
  	int rc;
  	u32 tmp;
  
  	/* make sure port is not active */
  	rc = ahci_deinit_port(ap, &emsg);
  	if (rc)
  		dev_warn(dev, "%s (%d)
  ", emsg, rc);
  
  	/* clear SError */
  	tmp = readl(port_mmio + PORT_SCR_ERR);
  	VPRINTK("PORT_SCR_ERR 0x%x
  ", tmp);
  	writel(tmp, port_mmio + PORT_SCR_ERR);
  
  	/* clear port IRQ */
  	tmp = readl(port_mmio + PORT_IRQ_STAT);
  	VPRINTK("PORT_IRQ_STAT 0x%x
  ", tmp);
  	if (tmp)
  		writel(tmp, port_mmio + PORT_IRQ_STAT);
  
  	writel(1 << port_no, mmio + HOST_IRQ_STAT);
8a3e33cf9   Manuel Lauss   ata: ahci: find e...
1205
1206
1207
  
  	/* mark esata ports */
  	tmp = readl(port_mmio + PORT_CMD);
dc8b4afc4   Manuel Lauss   ata: ahci: don't ...
1208
  	if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
8a3e33cf9   Manuel Lauss   ata: ahci: find e...
1209
  		ap->pflags |= ATA_PFLAG_EXTERNAL;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
  }
  
  void ahci_init_controller(struct ata_host *host)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	int i;
  	void __iomem *port_mmio;
  	u32 tmp;
  
  	for (i = 0; i < host->n_ports; i++) {
  		struct ata_port *ap = host->ports[i];
  
  		port_mmio = ahci_port_base(ap);
  		if (ata_port_is_dummy(ap))
  			continue;
  
  		ahci_port_init(host->dev, ap, i, mmio, port_mmio);
  	}
  
  	tmp = readl(mmio + HOST_CTL);
  	VPRINTK("HOST_CTL 0x%x
  ", tmp);
  	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
  	tmp = readl(mmio + HOST_CTL);
  	VPRINTK("HOST_CTL 0x%x
  ", tmp);
  }
  EXPORT_SYMBOL_GPL(ahci_init_controller);
  
  static void ahci_dev_config(struct ata_device *dev)
  {
  	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
  
  	if (hpriv->flags & AHCI_HFLAG_SECT255) {
  		dev->max_sectors = 255;
a9a79dfec   Joe Perches   ata: Convert ata_...
1246
1247
1248
  		ata_dev_info(dev,
  			     "SB600 AHCI: limiting to 255 sectors per cmd
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1249
1250
  	}
  }
bbb4ab43f   Rob Herring   ahci: un-staticiz...
1251
  unsigned int ahci_dev_classify(struct ata_port *ap)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ata_taskfile tf;
  	u32 tmp;
  
  	tmp = readl(port_mmio + PORT_SIG);
  	tf.lbah		= (tmp >> 24)	& 0xff;
  	tf.lbam		= (tmp >> 16)	& 0xff;
  	tf.lbal		= (tmp >> 8)	& 0xff;
  	tf.nsect	= (tmp)		& 0xff;
  
  	return ata_dev_classify(&tf);
  }
bbb4ab43f   Rob Herring   ahci: un-staticiz...
1265
  EXPORT_SYMBOL_GPL(ahci_dev_classify);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1266

02cdfcf04   David Milburn   [libata] new driv...
1267
1268
  void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
  			u32 opts)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
  {
  	dma_addr_t cmd_tbl_dma;
  
  	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
  
  	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
  	pp->cmd_slot[tag].status = 0;
  	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
  	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
  }
02cdfcf04   David Milburn   [libata] new driv...
1279
  EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
  
  int ahci_kick_engine(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
  	u32 tmp;
  	int busy, rc;
  
  	/* stop engine */
  	rc = ahci_stop_engine(ap);
  	if (rc)
  		goto out_restart;
  
  	/* need to do CLO?
  	 * always do CLO if PMP is attached (AHCI-1.3 9.2)
  	 */
  	busy = status & (ATA_BUSY | ATA_DRQ);
  	if (!busy && !sata_pmp_attached(ap)) {
  		rc = 0;
  		goto out_restart;
  	}
  
  	if (!(hpriv->cap & HOST_CAP_CLO)) {
  		rc = -EOPNOTSUPP;
  		goto out_restart;
  	}
  
  	/* perform CLO */
  	tmp = readl(port_mmio + PORT_CMD);
  	tmp |= PORT_CMD_CLO;
  	writel(tmp, port_mmio + PORT_CMD);
  
  	rc = 0;
97750cebb   Tejun Heo   libata: add @ap t...
1314
  	tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1315
1316
1317
1318
1319
1320
  				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
  	if (tmp & PORT_CMD_CLO)
  		rc = -EIO;
  
  	/* restart engine */
   out_restart:
039ece38d   Hans de Goede   libahci: Allow dr...
1321
  	hpriv->start_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
  	return rc;
  }
  EXPORT_SYMBOL_GPL(ahci_kick_engine);
  
  static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
  				struct ata_taskfile *tf, int is_cmd, u16 flags,
  				unsigned long timeout_msec)
  {
  	const u32 cmd_fis_len = 5; /* five dwords */
  	struct ahci_port_priv *pp = ap->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u8 *fis = pp->cmd_tbl;
  	u32 tmp;
  
  	/* prep the command */
  	ata_tf_to_fis(tf, pmp, is_cmd, fis);
  	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
023113d24   Xiangliang Yu   AHCI: Fix softres...
1339
1340
1341
1342
1343
1344
1345
1346
  	/* set port value for softreset of Port Multiplier */
  	if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
  		tmp = readl(port_mmio + PORT_FBS);
  		tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
  		tmp |= pmp << PORT_FBS_DEV_OFFSET;
  		writel(tmp, port_mmio + PORT_FBS);
  		pp->fbs_last_dev = pmp;
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1347
1348
1349
1350
  	/* issue & wait */
  	writel(1, port_mmio + PORT_CMD_ISSUE);
  
  	if (timeout_msec) {
97750cebb   Tejun Heo   libata: add @ap t...
1351
1352
  		tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
  					0x1, 0x1, 1, timeout_msec);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  		if (tmp & 0x1) {
  			ahci_kick_engine(ap);
  			return -EBUSY;
  		}
  	} else
  		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
  
  	return 0;
  }
  
  int ahci_do_softreset(struct ata_link *link, unsigned int *class,
  		      int pmp, unsigned long deadline,
  		      int (*check_ready)(struct ata_link *link))
  {
  	struct ata_port *ap = link->ap;
  	struct ahci_host_priv *hpriv = ap->host->private_data;
89dafa20f   xiangliang yu   ahci: disabled FB...
1369
  	struct ahci_port_priv *pp = ap->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1370
1371
1372
  	const char *reason = NULL;
  	unsigned long now, msecs;
  	struct ata_taskfile tf;
89dafa20f   xiangliang yu   ahci: disabled FB...
1373
  	bool fbs_disabled = false;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1374
1375
1376
1377
1378
1379
1380
1381
  	int rc;
  
  	DPRINTK("ENTER
  ");
  
  	/* prepare for SRST (AHCI-1.1 10.4.1) */
  	rc = ahci_kick_engine(ap);
  	if (rc && rc != -EOPNOTSUPP)
a9a79dfec   Joe Perches   ata: Convert ata_...
1382
1383
  		ata_link_warn(link, "failed to reset engine (errno=%d)
  ", rc);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1384

89dafa20f   xiangliang yu   ahci: disabled FB...
1385
1386
1387
1388
1389
1390
1391
1392
1393
  	/*
  	 * According to AHCI-1.2 9.3.9: if FBS is enable, software shall
  	 * clear PxFBS.EN to '0' prior to issuing software reset to devices
  	 * that is attached to port multiplier.
  	 */
  	if (!ata_is_host_link(link) && pp->fbs_enabled) {
  		ahci_disable_fbs(ap);
  		fbs_disabled = true;
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1394
1395
1396
1397
1398
  	ata_tf_init(link->device, &tf);
  
  	/* issue the first D2H Register FIS */
  	msecs = 0;
  	now = jiffies;
f1f5a807b   Tejun Heo   ahci: fix hang on...
1399
  	if (time_after(deadline, now))
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
  		msecs = jiffies_to_msecs(deadline - now);
  
  	tf.ctl |= ATA_SRST;
  	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
  				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
  		rc = -EIO;
  		reason = "1st FIS failed";
  		goto fail;
  	}
  
  	/* spec says at least 5us, but be generous and sleep for 1ms */
97750cebb   Tejun Heo   libata: add @ap t...
1411
  	ata_msleep(ap, 1);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
  
  	/* issue the second D2H Register FIS */
  	tf.ctl &= ~ATA_SRST;
  	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
  
  	/* wait for link to become ready */
  	rc = ata_wait_after_reset(link, deadline, check_ready);
  	if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
  		/*
  		 * Workaround for cases where link online status can't
  		 * be trusted.  Treat device readiness timeout as link
  		 * offline.
  		 */
a9a79dfec   Joe Perches   ata: Convert ata_...
1425
1426
  		ata_link_info(link, "device not ready, treating as offline
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1427
1428
1429
1430
1431
1432
1433
  		*class = ATA_DEV_NONE;
  	} else if (rc) {
  		/* link occupied, -ENODEV too is an error */
  		reason = "device not ready";
  		goto fail;
  	} else
  		*class = ahci_dev_classify(ap);
89dafa20f   xiangliang yu   ahci: disabled FB...
1434
1435
1436
  	/* re-enable FBS if disabled before */
  	if (fbs_disabled)
  		ahci_enable_fbs(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1437
1438
1439
1440
1441
  	DPRINTK("EXIT, class=%u
  ", *class);
  	return 0;
  
   fail:
a9a79dfec   Joe Perches   ata: Convert ata_...
1442
1443
  	ata_link_err(link, "softreset failed (%s)
  ", reason);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  	return rc;
  }
  
  int ahci_check_ready(struct ata_link *link)
  {
  	void __iomem *port_mmio = ahci_port_base(link->ap);
  	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
  
  	return ata_check_ready(status);
  }
  EXPORT_SYMBOL_GPL(ahci_check_ready);
  
  static int ahci_softreset(struct ata_link *link, unsigned int *class,
  			  unsigned long deadline)
  {
  	int pmp = sata_srst_pmp(link);
  
  	DPRINTK("ENTER
  ");
  
  	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
  }
  EXPORT_SYMBOL_GPL(ahci_do_softreset);
345347c5d   Yuan-Hsin Chen   ahci: move ahci_s...
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
  static int ahci_bad_pmp_check_ready(struct ata_link *link)
  {
  	void __iomem *port_mmio = ahci_port_base(link->ap);
  	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
  	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
  
  	/*
  	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
  	 * which can save timeout delay.
  	 */
  	if (irq_status & PORT_IRQ_BAD_PMP)
  		return -EIO;
  
  	return ata_check_ready(status);
  }
35186d058   Daeseok Youn   ata: libahci: mak...
1482
1483
  static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
  				    unsigned long deadline)
345347c5d   Yuan-Hsin Chen   ahci: move ahci_s...
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
  {
  	struct ata_port *ap = link->ap;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	int pmp = sata_srst_pmp(link);
  	int rc;
  	u32 irq_sts;
  
  	DPRINTK("ENTER
  ");
  
  	rc = ahci_do_softreset(link, class, pmp, deadline,
  			       ahci_bad_pmp_check_ready);
  
  	/*
  	 * Soft reset fails with IPMS set when PMP is enabled but
  	 * SATA HDD/ODD is connected to SATA port, do soft reset
  	 * again to port 0.
  	 */
  	if (rc == -EIO) {
  		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
  		if (irq_sts & PORT_IRQ_BAD_PMP) {
39f80acb9   Wei Yongjun   ahci: convert ata...
1505
  			ata_link_warn(link,
345347c5d   Yuan-Hsin Chen   ahci: move ahci_s...
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
  					"applying PMP SRST workaround "
  					"and retrying
  ");
  			rc = ahci_do_softreset(link, class, 0, deadline,
  					       ahci_check_ready);
  		}
  	}
  
  	return rc;
  }
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1516
1517
1518
1519
1520
1521
  static int ahci_hardreset(struct ata_link *link, unsigned int *class,
  			  unsigned long deadline)
  {
  	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
  	struct ata_port *ap = link->ap;
  	struct ahci_port_priv *pp = ap->private_data;
039ece38d   Hans de Goede   libahci: Allow dr...
1522
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
  	struct ata_taskfile tf;
  	bool online;
  	int rc;
  
  	DPRINTK("ENTER
  ");
  
  	ahci_stop_engine(ap);
  
  	/* clear D2H reception area to properly wait for D2H FIS */
  	ata_tf_init(link->device, &tf);
9bbb1b0e2   Sergei Shtylyov   AHCI: use ATA_BUSY
1535
  	tf.command = ATA_BUSY;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1536
1537
1538
1539
  	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
  
  	rc = sata_link_hardreset(link, timing, deadline, &online,
  				 ahci_check_ready);
039ece38d   Hans de Goede   libahci: Allow dr...
1540
  	hpriv->start_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
  
  	if (online)
  		*class = ahci_dev_classify(ap);
  
  	DPRINTK("EXIT, rc=%d, class=%u
  ", rc, *class);
  	return rc;
  }
  
  static void ahci_postreset(struct ata_link *link, unsigned int *class)
  {
  	struct ata_port *ap = link->ap;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 new_tmp, tmp;
  
  	ata_std_postreset(link, class);
  
  	/* Make sure port's ATAPI bit is set appropriately */
  	new_tmp = tmp = readl(port_mmio + PORT_CMD);
  	if (*class == ATA_DEV_ATAPI)
  		new_tmp |= PORT_CMD_ATAPI;
  	else
  		new_tmp &= ~PORT_CMD_ATAPI;
  	if (new_tmp != tmp) {
  		writel(new_tmp, port_mmio + PORT_CMD);
  		readl(port_mmio + PORT_CMD); /* flush */
  	}
  }
  
  static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
  {
  	struct scatterlist *sg;
  	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
  	unsigned int si;
  
  	VPRINTK("ENTER
  ");
  
  	/*
  	 * Next, the S/G list.
  	 */
  	for_each_sg(qc->sg, sg, qc->n_elem, si) {
  		dma_addr_t addr = sg_dma_address(sg);
  		u32 sg_len = sg_dma_len(sg);
  
  		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
  		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
  		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
  	}
  
  	return si;
  }
  
  static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  
  	if (!sata_pmp_attached(ap) || pp->fbs_enabled)
  		return ata_std_qc_defer(qc);
  	else
  		return sata_pmp_qc_defer_cmd_switch(qc);
  }
  
  static void ahci_qc_prep(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct ahci_port_priv *pp = ap->private_data;
  	int is_atapi = ata_is_atapi(qc->tf.protocol);
  	void *cmd_tbl;
  	u32 opts;
  	const u32 cmd_fis_len = 5; /* five dwords */
  	unsigned int n_elem;
  
  	/*
  	 * Fill in command table information.  First, the header,
  	 * a SATA Register - Host to Device command FIS.
  	 */
  	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
  
  	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
  	if (is_atapi) {
  		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
  		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
  	}
  
  	n_elem = 0;
  	if (qc->flags & ATA_QCFLAG_DMAMAP)
  		n_elem = ahci_fill_sg(qc, cmd_tbl);
  
  	/*
  	 * Fill in command slot information.
  	 */
  	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
  	if (qc->tf.flags & ATA_TFLAG_WRITE)
  		opts |= AHCI_CMD_WRITE;
  	if (is_atapi)
  		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
  
  	ahci_fill_cmd_slot(pp, qc->tag, opts);
  }
  
  static void ahci_fbs_dec_intr(struct ata_port *ap)
  {
  	struct ahci_port_priv *pp = ap->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 fbs = readl(port_mmio + PORT_FBS);
  	int retries = 3;
  
  	DPRINTK("ENTER
  ");
  	BUG_ON(!pp->fbs_enabled);
  
  	/* time to wait for DEC is not specified by AHCI spec,
  	 * add a retry loop for safety.
  	 */
  	writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
  	fbs = readl(port_mmio + PORT_FBS);
  	while ((fbs & PORT_FBS_DEC) && retries--) {
  		udelay(1);
  		fbs = readl(port_mmio + PORT_FBS);
  	}
  
  	if (fbs & PORT_FBS_DEC)
a44fec1fc   Joe Perches   ata: Convert dev_...
1665
1666
  		dev_err(ap->host->dev, "failed to clear device error
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
  }
  
  static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ata_eh_info *host_ehi = &ap->link.eh_info;
  	struct ata_link *link = NULL;
  	struct ata_queued_cmd *active_qc;
  	struct ata_eh_info *active_ehi;
  	bool fbs_need_dec = false;
  	u32 serror;
  
  	/* determine active link with error */
  	if (pp->fbs_enabled) {
  		void __iomem *port_mmio = ahci_port_base(ap);
  		u32 fbs = readl(port_mmio + PORT_FBS);
  		int pmp = fbs >> PORT_FBS_DWE_OFFSET;
912b9ac68   Shane Huang   ahci: remove pmp ...
1685
  		if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
  			link = &ap->pmp_link[pmp];
  			fbs_need_dec = true;
  		}
  
  	} else
  		ata_for_each_link(link, ap, EDGE)
  			if (ata_link_active(link))
  				break;
  
  	if (!link)
  		link = &ap->link;
  
  	active_qc = ata_qc_from_tag(ap, link->active_tag);
  	active_ehi = &link->eh_info;
  
  	/* record irq stat */
  	ata_ehi_clear_desc(host_ehi);
  	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
  
  	/* AHCI needs SError cleared; otherwise, it might lock up */
  	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
  	ahci_scr_write(&ap->link, SCR_ERROR, serror);
  	host_ehi->serror |= serror;
  
  	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
  	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
  		irq_stat &= ~PORT_IRQ_IF_ERR;
  
  	if (irq_stat & PORT_IRQ_TF_ERR) {
  		/* If qc is active, charge it; otherwise, the active
  		 * link.  There's no active qc on NCQ errors.  It will
  		 * be determined by EH by reading log page 10h.
  		 */
  		if (active_qc)
  			active_qc->err_mask |= AC_ERR_DEV;
  		else
  			active_ehi->err_mask |= AC_ERR_DEV;
  
  		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
  			host_ehi->serror &= ~SERR_INTERNAL;
  	}
  
  	if (irq_stat & PORT_IRQ_UNK_FIS) {
d5185d655   Joe Perches   ata: remove super...
1729
  		u32 *unk = pp->rx_fis + RX_FIS_UNK;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
  
  		active_ehi->err_mask |= AC_ERR_HSM;
  		active_ehi->action |= ATA_EH_RESET;
  		ata_ehi_push_desc(active_ehi,
  				  "unknown FIS %08x %08x %08x %08x" ,
  				  unk[0], unk[1], unk[2], unk[3]);
  	}
  
  	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
  		active_ehi->err_mask |= AC_ERR_HSM;
  		active_ehi->action |= ATA_EH_RESET;
  		ata_ehi_push_desc(active_ehi, "incorrect PMP");
  	}
  
  	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
  		host_ehi->err_mask |= AC_ERR_HOST_BUS;
  		host_ehi->action |= ATA_EH_RESET;
  		ata_ehi_push_desc(host_ehi, "host bus error");
  	}
  
  	if (irq_stat & PORT_IRQ_IF_ERR) {
  		if (fbs_need_dec)
  			active_ehi->err_mask |= AC_ERR_DEV;
  		else {
  			host_ehi->err_mask |= AC_ERR_ATA_BUS;
  			host_ehi->action |= ATA_EH_RESET;
  		}
  
  		ata_ehi_push_desc(host_ehi, "interface fatal error");
  	}
  
  	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
  		ata_ehi_hotplugged(host_ehi);
  		ata_ehi_push_desc(host_ehi, "%s",
  			irq_stat & PORT_IRQ_CONNECT ?
  			"connection status changed" : "PHY RDY changed");
  	}
  
  	/* okay, let's hand over to EH */
  
  	if (irq_stat & PORT_IRQ_FREEZE)
  		ata_port_freeze(ap);
  	else if (fbs_need_dec) {
  		ata_link_abort(link);
  		ahci_fbs_dec_intr(ap);
  	} else
  		ata_port_abort(ap);
  }
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1778
1779
  static void ahci_handle_port_interrupt(struct ata_port *ap,
  				       void __iomem *port_mmio, u32 status)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1780
  {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1781
1782
1783
1784
  	struct ata_eh_info *ehi = &ap->link.eh_info;
  	struct ahci_port_priv *pp = ap->private_data;
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1785
  	u32 qc_active = 0;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1786
  	int rc;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1787
1788
1789
  	/* ignore BAD_PMP while resetting */
  	if (unlikely(resetting))
  		status &= ~PORT_IRQ_BAD_PMP;
8393b811f   Gabriele Mazzotta   libata: Add helpe...
1790
  	if (sata_lpm_ignore_phy_events(&ap->link)) {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1791
  		status &= ~PORT_IRQ_PHYRDY;
6b7ae9545   Tejun Heo   libata: reimpleme...
1792
  		ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  	}
  
  	if (unlikely(status & PORT_IRQ_ERROR)) {
  		ahci_error_intr(ap, status);
  		return;
  	}
  
  	if (status & PORT_IRQ_SDB_FIS) {
  		/* If SNotification is available, leave notification
  		 * handling to sata_async_notification().  If not,
  		 * emulate it by snooping SDB FIS RX area.
  		 *
  		 * Snooping FIS RX area is probably cheaper than
  		 * poking SNotification but some constrollers which
  		 * implement SNotification, ICH9 for example, don't
  		 * store AN SDB FIS into receive area.
  		 */
  		if (hpriv->cap & HOST_CAP_SNTF)
  			sata_async_notification(ap);
  		else {
  			/* If the 'N' bit in word 0 of the FIS is set,
  			 * we just received asynchronous notification.
  			 * Tell libata about it.
  			 *
  			 * Lack of SNotification should not appear in
  			 * ahci 1.2, so the workaround is unnecessary
  			 * when FBS is enabled.
  			 */
  			if (pp->fbs_enabled)
  				WARN_ON_ONCE(1);
  			else {
  				const __le32 *f = pp->rx_fis + RX_FIS_SDB;
  				u32 f0 = le32_to_cpu(f[0]);
  				if (f0 & (1 << 15))
  					sata_async_notification(ap);
  			}
  		}
  	}
  
  	/* pp->active_link is not reliable once FBS is enabled, both
  	 * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
  	 * NCQ and non-NCQ commands may be in flight at the same time.
  	 */
  	if (pp->fbs_enabled) {
  		if (ap->qc_active) {
  			qc_active = readl(port_mmio + PORT_SCR_ACT);
  			qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
  		}
  	} else {
  		/* pp->active_link is valid iff any command is in flight */
  		if (ap->qc_active && pp->active_link->sactive)
  			qc_active = readl(port_mmio + PORT_SCR_ACT);
  		else
  			qc_active = readl(port_mmio + PORT_CMD_ISSUE);
  	}
  
  
  	rc = ata_qc_complete_multiple(ap, qc_active);
  
  	/* while resetting, invalid completions are expected */
  	if (unlikely(rc < 0 && !resetting)) {
  		ehi->err_mask |= AC_ERR_HSM;
  		ehi->action |= ATA_EH_RESET;
  		ata_port_freeze(ap);
  	}
  }
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
1859
  static void ahci_port_intr(struct ata_port *ap)
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1860
1861
1862
1863
1864
1865
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 status;
  
  	status = readl(port_mmio + PORT_IRQ_STAT);
  	writel(status, port_mmio + PORT_IRQ_STAT);
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
1866
  	ahci_handle_port_interrupt(ap, port_mmio, status);
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1867
  }
a6b7fb764   Dan Williams   ahci: switch from...
1868
  static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1869
1870
  {
  	struct ata_port *ap = dev_instance;
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1871
  	void __iomem *port_mmio = ahci_port_base(ap);
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1872
  	u32 status;
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1873
1874
  	VPRINTK("ENTER
  ");
227dfb4db   Alexander Gordeev   AHCI: Do not read...
1875
1876
  	status = readl(port_mmio + PORT_IRQ_STAT);
  	writel(status, port_mmio + PORT_IRQ_STAT);
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1877

a6b7fb764   Dan Williams   ahci: switch from...
1878
1879
1880
  	spin_lock(ap->lock);
  	ahci_handle_port_interrupt(ap, port_mmio, status);
  	spin_unlock(ap->lock);
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1881
1882
1883
  
  	VPRINTK("EXIT
  ");
a6b7fb764   Dan Williams   ahci: switch from...
1884
  	return IRQ_HANDLED;
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1885
  }
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
1886

f070d6715   Suman Tripathi   libahci: Implemen...
1887
  u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1888
  {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1889
  	unsigned int i, handled = 0;
03e83cbd3   Tejun Heo   Revert "AHCI: Do ...
1890

365cfa1ed   Anton Vorontsov   ahci: Move generi...
1891
1892
1893
1894
1895
1896
1897
1898
  	for (i = 0; i < host->n_ports; i++) {
  		struct ata_port *ap;
  
  		if (!(irq_masked & (1 << i)))
  			continue;
  
  		ap = host->ports[i];
  		if (ap) {
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
1899
  			ahci_port_intr(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1900
1901
1902
1903
1904
1905
  			VPRINTK("port %u
  ", i);
  		} else {
  			VPRINTK("port %u (no irq)
  ", i);
  			if (ata_ratelimit())
a44fec1fc   Joe Perches   ata: Convert dev_...
1906
1907
1908
  				dev_warn(host->dev,
  					 "interrupt on disabled port %u
  ", i);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1909
1910
1911
1912
  		}
  
  		handled = 1;
  	}
a129db89d   Suman Tripathi   libahci: Refactor...
1913
1914
  	return handled;
  }
f070d6715   Suman Tripathi   libahci: Implemen...
1915
  EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
a129db89d   Suman Tripathi   libahci: Refactor...
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
  
  static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
  {
  	struct ata_host *host = dev_instance;
  	struct ahci_host_priv *hpriv;
  	unsigned int rc = 0;
  	void __iomem *mmio;
  	u32 irq_stat, irq_masked;
  
  	VPRINTK("ENTER
  ");
  
  	hpriv = host->private_data;
  	mmio = hpriv->mmio;
  
  	/* sigh.  0xffffffff is a valid return from h/w */
  	irq_stat = readl(mmio + HOST_IRQ_STAT);
  	if (!irq_stat)
  		return IRQ_NONE;
  
  	irq_masked = irq_stat & hpriv->port_map;
  
  	spin_lock(&host->lock);
  
  	rc = ahci_handle_port_intr(host, irq_masked);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
  
  	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
  	 * it should be cleared after all the port events are cleared;
  	 * otherwise, it will raise a spurious interrupt after each
  	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
  	 * information.
  	 *
  	 * Also, use the unmasked value to clear interrupt as spurious
  	 * pending event on a dummy port might cause screaming IRQ.
  	 */
  	writel(irq_stat, mmio + HOST_IRQ_STAT);
03e83cbd3   Tejun Heo   Revert "AHCI: Do ...
1952
  	spin_unlock(&host->lock);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1953
1954
  	VPRINTK("EXIT
  ");
a129db89d   Suman Tripathi   libahci: Refactor...
1955
  	return IRQ_RETVAL(rc);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1956
  }
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1957

39e0ee996   Suman Tripathi   libahci: export a...
1958
  unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
  {
  	struct ata_port *ap = qc->ap;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ahci_port_priv *pp = ap->private_data;
  
  	/* Keep track of the currently active link.  It will be used
  	 * in completion path to determine whether NCQ phase is in
  	 * progress.
  	 */
  	pp->active_link = qc->dev->link;
179b310ae   Hannes Reinecke   libata: use ata_i...
1969
  	if (ata_is_ncq(qc->tf.protocol))
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
  		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
  
  	if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
  		u32 fbs = readl(port_mmio + PORT_FBS);
  		fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
  		fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
  		writel(fbs, port_mmio + PORT_FBS);
  		pp->fbs_last_dev = qc->dev->link->pmp;
  	}
  
  	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
  
  	ahci_sw_activity(qc->dev->link);
  
  	return 0;
  }
39e0ee996   Suman Tripathi   libahci: export a...
1986
  EXPORT_SYMBOL_GPL(ahci_qc_issue);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1987
1988
1989
1990
  
  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
  {
  	struct ahci_port_priv *pp = qc->ap->private_data;
6ad601955   Tejun Heo   libahci: fix resu...
1991
  	u8 *rx_fis = pp->rx_fis;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
1992
1993
  
  	if (pp->fbs_enabled)
6ad601955   Tejun Heo   libahci: fix resu...
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
  		rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
  
  	/*
  	 * After a successful execution of an ATA PIO data-in command,
  	 * the device doesn't send D2H Reg FIS to update the TF and
  	 * the host should take TF and E_Status from the preceding PIO
  	 * Setup FIS.
  	 */
  	if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
  	    !(qc->flags & ATA_QCFLAG_FAILED)) {
  		ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
  		qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
  	} else
  		ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2008

365cfa1ed   Anton Vorontsov   ahci: Move generi...
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
  	return true;
  }
  
  static void ahci_freeze(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  
  	/* turn IRQ off */
  	writel(0, port_mmio + PORT_IRQ_MASK);
  }
  
  static void ahci_thaw(struct ata_port *ap)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *mmio = hpriv->mmio;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 tmp;
  	struct ahci_port_priv *pp = ap->private_data;
  
  	/* clear IRQ */
  	tmp = readl(port_mmio + PORT_IRQ_STAT);
  	writel(tmp, port_mmio + PORT_IRQ_STAT);
  	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
  
  	/* turn IRQ back on */
  	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
  }
8b789d898   Richard Zhu   ahci: imx: setup ...
2036
  void ahci_error_handler(struct ata_port *ap)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2037
  {
039ece38d   Hans de Goede   libahci: Allow dr...
2038
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2039
2040
2041
  	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
  		/* restart engine */
  		ahci_stop_engine(ap);
039ece38d   Hans de Goede   libahci: Allow dr...
2042
  		hpriv->start_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2043
2044
2045
  	}
  
  	sata_pmp_error_handler(ap);
0ee719527   Tejun Heo   ahci: redo stoppi...
2046
2047
2048
  
  	if (!ata_dev_enabled(ap->link.device))
  		ahci_stop_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2049
  }
8b789d898   Richard Zhu   ahci: imx: setup ...
2050
  EXPORT_SYMBOL_GPL(ahci_error_handler);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2051
2052
2053
2054
2055
2056
2057
2058
2059
  
  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  
  	/* make DMA engine forget about the failed command */
  	if (qc->flags & ATA_QCFLAG_FAILED)
  		ahci_kick_engine(ap);
  }
65fe1f0f6   Shane Huang   ahci: implement a...
2060
2061
  static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
  {
039ece38d   Hans de Goede   libahci: Allow dr...
2062
  	struct ahci_host_priv *hpriv = ap->host->private_data;
65fe1f0f6   Shane Huang   ahci: implement a...
2063
2064
2065
2066
2067
2068
2069
2070
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ata_device *dev = ap->link.device;
  	u32 devslp, dm, dito, mdat, deto;
  	int rc;
  	unsigned int err_mask;
  
  	devslp = readl(port_mmio + PORT_DEVSLP);
  	if (!(devslp & PORT_DEVSLP_DSP)) {
95bbbe9a6   Gabriele Mazzotta   ahci: Use dev_inf...
2071
2072
  		dev_info(ap->host->dev, "port does not support device sleep
  ");
65fe1f0f6   Shane Huang   ahci: implement a...
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
  		return;
  	}
  
  	/* disable device sleep */
  	if (!sleep) {
  		if (devslp & PORT_DEVSLP_ADSE) {
  			writel(devslp & ~PORT_DEVSLP_ADSE,
  			       port_mmio + PORT_DEVSLP);
  			err_mask = ata_dev_set_feature(dev,
  						       SETFEATURES_SATA_DISABLE,
  						       SATA_DEVSLP);
  			if (err_mask && err_mask != AC_ERR_DEV)
  				ata_dev_warn(dev, "failed to disable DEVSLP
  ");
  		}
  		return;
  	}
  
  	/* device sleep was already enabled */
  	if (devslp & PORT_DEVSLP_ADSE)
  		return;
  
  	/* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */
  	rc = ahci_stop_engine(ap);
  	if (rc)
  		return;
  
  	dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
  	dito = devslp_idle_timeout / (dm + 1);
  	if (dito > 0x3ff)
  		dito = 0x3ff;
  
  	/* Use the nominal value 10 ms if the read MDAT is zero,
  	 * the nominal value of DETO is 20 ms.
  	 */
803739d25   Shane Huang   [libata] replace ...
2108
  	if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
65fe1f0f6   Shane Huang   ahci: implement a...
2109
  	    ATA_LOG_DEVSLP_VALID_MASK) {
803739d25   Shane Huang   [libata] replace ...
2110
  		mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
65fe1f0f6   Shane Huang   ahci: implement a...
2111
2112
2113
  		       ATA_LOG_DEVSLP_MDAT_MASK;
  		if (!mdat)
  			mdat = 10;
803739d25   Shane Huang   [libata] replace ...
2114
  		deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
65fe1f0f6   Shane Huang   ahci: implement a...
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
  		if (!deto)
  			deto = 20;
  	} else {
  		mdat = 10;
  		deto = 20;
  	}
  
  	devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
  		   (mdat << PORT_DEVSLP_MDAT_OFFSET) |
  		   (deto << PORT_DEVSLP_DETO_OFFSET) |
  		   PORT_DEVSLP_ADSE);
  	writel(devslp, port_mmio + PORT_DEVSLP);
039ece38d   Hans de Goede   libahci: Allow dr...
2127
  	hpriv->start_engine(ap);
65fe1f0f6   Shane Huang   ahci: implement a...
2128
2129
2130
2131
2132
2133
2134
2135
2136
  
  	/* enable device sleep feature for the drive */
  	err_mask = ata_dev_set_feature(dev,
  				       SETFEATURES_SATA_ENABLE,
  				       SATA_DEVSLP);
  	if (err_mask && err_mask != AC_ERR_DEV)
  		ata_dev_warn(dev, "failed to enable DEVSLP
  ");
  }
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2137
2138
  static void ahci_enable_fbs(struct ata_port *ap)
  {
039ece38d   Hans de Goede   libahci: Allow dr...
2139
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
  	struct ahci_port_priv *pp = ap->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 fbs;
  	int rc;
  
  	if (!pp->fbs_supported)
  		return;
  
  	fbs = readl(port_mmio + PORT_FBS);
  	if (fbs & PORT_FBS_EN) {
  		pp->fbs_enabled = true;
  		pp->fbs_last_dev = -1; /* initialization */
  		return;
  	}
  
  	rc = ahci_stop_engine(ap);
  	if (rc)
  		return;
  
  	writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
  	fbs = readl(port_mmio + PORT_FBS);
  	if (fbs & PORT_FBS_EN) {
a44fec1fc   Joe Perches   ata: Convert dev_...
2162
2163
  		dev_info(ap->host->dev, "FBS is enabled
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2164
2165
2166
  		pp->fbs_enabled = true;
  		pp->fbs_last_dev = -1; /* initialization */
  	} else
a44fec1fc   Joe Perches   ata: Convert dev_...
2167
2168
  		dev_err(ap->host->dev, "Failed to enable FBS
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2169

039ece38d   Hans de Goede   libahci: Allow dr...
2170
  	hpriv->start_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2171
2172
2173
2174
  }
  
  static void ahci_disable_fbs(struct ata_port *ap)
  {
039ece38d   Hans de Goede   libahci: Allow dr...
2175
  	struct ahci_host_priv *hpriv = ap->host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
  	struct ahci_port_priv *pp = ap->private_data;
  	void __iomem *port_mmio = ahci_port_base(ap);
  	u32 fbs;
  	int rc;
  
  	if (!pp->fbs_supported)
  		return;
  
  	fbs = readl(port_mmio + PORT_FBS);
  	if ((fbs & PORT_FBS_EN) == 0) {
  		pp->fbs_enabled = false;
  		return;
  	}
  
  	rc = ahci_stop_engine(ap);
  	if (rc)
  		return;
  
  	writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);
  	fbs = readl(port_mmio + PORT_FBS);
  	if (fbs & PORT_FBS_EN)
a44fec1fc   Joe Perches   ata: Convert dev_...
2197
2198
  		dev_err(ap->host->dev, "Failed to disable FBS
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2199
  	else {
a44fec1fc   Joe Perches   ata: Convert dev_...
2200
2201
  		dev_info(ap->host->dev, "FBS is disabled
  ");
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2202
2203
  		pp->fbs_enabled = false;
  	}
039ece38d   Hans de Goede   libahci: Allow dr...
2204
  	hpriv->start_engine(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
  }
  
  static void ahci_pmp_attach(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ahci_port_priv *pp = ap->private_data;
  	u32 cmd;
  
  	cmd = readl(port_mmio + PORT_CMD);
  	cmd |= PORT_CMD_PMP;
  	writel(cmd, port_mmio + PORT_CMD);
  
  	ahci_enable_fbs(ap);
  
  	pp->intr_mask |= PORT_IRQ_BAD_PMP;
7b3a24c57   Maxime Bizon   ahci: don't enabl...
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
  
  	/*
  	 * We must not change the port interrupt mask register if the
  	 * port is marked frozen, the value in pp->intr_mask will be
  	 * restored later when the port is thawed.
  	 *
  	 * Note that during initialization, the port is marked as
  	 * frozen since the irq handler is not yet registered.
  	 */
  	if (!(ap->pflags & ATA_PFLAG_FROZEN))
  		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
  }
  
  static void ahci_pmp_detach(struct ata_port *ap)
  {
  	void __iomem *port_mmio = ahci_port_base(ap);
  	struct ahci_port_priv *pp = ap->private_data;
  	u32 cmd;
  
  	ahci_disable_fbs(ap);
  
  	cmd = readl(port_mmio + PORT_CMD);
  	cmd &= ~PORT_CMD_PMP;
  	writel(cmd, port_mmio + PORT_CMD);
  
  	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
7b3a24c57   Maxime Bizon   ahci: don't enabl...
2246
2247
2248
2249
  
  	/* see comment above in ahci_pmp_attach() */
  	if (!(ap->pflags & ATA_PFLAG_FROZEN))
  		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2250
  }
02cdfcf04   David Milburn   [libata] new driv...
2251
  int ahci_port_resume(struct ata_port *ap)
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2252
  {
bb03c6406   Mika Westerberg   ahci: Add functio...
2253
  	ahci_rpm_get_port(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
  	ahci_power_up(ap);
  	ahci_start_port(ap);
  
  	if (sata_pmp_attached(ap))
  		ahci_pmp_attach(ap);
  	else
  		ahci_pmp_detach(ap);
  
  	return 0;
  }
02cdfcf04   David Milburn   [libata] new driv...
2264
  EXPORT_SYMBOL_GPL(ahci_port_resume);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
  
  #ifdef CONFIG_PM
  static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
  {
  	const char *emsg = NULL;
  	int rc;
  
  	rc = ahci_deinit_port(ap, &emsg);
  	if (rc == 0)
  		ahci_power_down(ap);
  	else {
a9a79dfec   Joe Perches   ata: Convert ata_...
2276
2277
  		ata_port_err(ap, "%s (%d)
  ", emsg, rc);
7faa33da9   Tejun Heo   ahci: start engin...
2278
  		ata_port_freeze(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2279
  	}
bb03c6406   Mika Westerberg   ahci: Add functio...
2280
  	ahci_rpm_put_port(ap);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
  	return rc;
  }
  #endif
  
  static int ahci_port_start(struct ata_port *ap)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	struct device *dev = ap->host->dev;
  	struct ahci_port_priv *pp;
  	void *mem;
  	dma_addr_t mem_dma;
  	size_t dma_sz, rx_fis_sz;
  
  	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
  	if (!pp)
  		return -ENOMEM;
b29900e62   Alexander Gordeev   AHCI: Make distin...
2297
2298
2299
2300
2301
2302
2303
2304
2305
  	if (ap->host->n_ports > 1) {
  		pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
  		if (!pp->irq_desc) {
  			devm_kfree(dev, pp);
  			return -ENOMEM;
  		}
  		snprintf(pp->irq_desc, 8,
  			 "%s%d", dev_driver_string(dev), ap->port_no);
  	}
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2306
2307
2308
2309
2310
2311
  	/* check FBS capability */
  	if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
  		void __iomem *port_mmio = ahci_port_base(ap);
  		u32 cmd = readl(port_mmio + PORT_CMD);
  		if (cmd & PORT_CMD_FBSCP)
  			pp->fbs_supported = true;
5f173107e   Tejun Heo   ahci: add HFLAG_Y...
2312
  		else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
a44fec1fc   Joe Perches   ata: Convert dev_...
2313
2314
2315
  			dev_info(dev, "port %d can do FBS, forcing FBSCP
  ",
  				 ap->port_no);
5f173107e   Tejun Heo   ahci: add HFLAG_Y...
2316
2317
  			pp->fbs_supported = true;
  		} else
a44fec1fc   Joe Perches   ata: Convert dev_...
2318
2319
2320
  			dev_warn(dev, "port %d is not capable of FBS
  ",
  				 ap->port_no);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
  	}
  
  	if (pp->fbs_supported) {
  		dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
  		rx_fis_sz = AHCI_RX_FIS_SZ * 16;
  	} else {
  		dma_sz = AHCI_PORT_PRIV_DMA_SZ;
  		rx_fis_sz = AHCI_RX_FIS_SZ;
  	}
  
  	mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
  	if (!mem)
  		return -ENOMEM;
  	memset(mem, 0, dma_sz);
  
  	/*
  	 * First item in chunk of DMA memory: 32-slot command table,
  	 * 32 bytes each in size
  	 */
  	pp->cmd_slot = mem;
  	pp->cmd_slot_dma = mem_dma;
  
  	mem += AHCI_CMD_SLOT_SZ;
  	mem_dma += AHCI_CMD_SLOT_SZ;
  
  	/*
  	 * Second item: Received-FIS area
  	 */
  	pp->rx_fis = mem;
  	pp->rx_fis_dma = mem_dma;
  
  	mem += rx_fis_sz;
  	mem_dma += rx_fis_sz;
  
  	/*
  	 * Third item: data area for storing a single command
  	 * and its scatter-gather table
  	 */
  	pp->cmd_tbl = mem;
  	pp->cmd_tbl_dma = mem_dma;
  
  	/*
  	 * Save off initial list of interrupts to be enabled.
  	 * This could be changed later
  	 */
  	pp->intr_mask = DEF_PORT_IRQ;
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
2367
2368
2369
  	/*
  	 * Switch to per-port locking in case each port has its own MSI vector.
  	 */
0b9e2988a   Christoph Hellwig   ahci: use pci_all...
2370
  	if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
2371
2372
2373
  		spin_lock_init(&pp->lock);
  		ap->lock = &pp->lock;
  	}
5ca72c4f7   Alexander Gordeev   AHCI: Support mul...
2374

365cfa1ed   Anton Vorontsov   ahci: Move generi...
2375
2376
2377
2378
2379
2380
2381
2382
2383
  	ap->private_data = pp;
  
  	/* engage engines, captain */
  	return ahci_port_resume(ap);
  }
  
  static void ahci_port_stop(struct ata_port *ap)
  {
  	const char *emsg = NULL;
0516900ad   Pang Raymond   AHCI: Clear GHC.I...
2384
2385
  	struct ahci_host_priv *hpriv = ap->host->private_data;
  	void __iomem *host_mmio = hpriv->mmio;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2386
2387
2388
2389
2390
  	int rc;
  
  	/* de-initialize port */
  	rc = ahci_deinit_port(ap, &emsg);
  	if (rc)
a9a79dfec   Joe Perches   ata: Convert ata_...
2391
2392
  		ata_port_warn(ap, "%s (%d)
  ", emsg, rc);
0516900ad   Pang Raymond   AHCI: Clear GHC.I...
2393
2394
2395
2396
2397
2398
  
  	/*
  	 * Clear GHC.IS to prevent stuck INTx after disabling MSI and
  	 * re-enabling INTx.
  	 */
  	writel(1 << ap->port_no, host_mmio + HOST_IRQ_STAT);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2399
2400
2401
2402
2403
  }
  
  void ahci_print_info(struct ata_host *host, const char *scc_s)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2404
2405
  	u32 vers, cap, cap2, impl, speed;
  	const char *speed_s;
8ea909cb3   Mika Westerberg   ahci: Cache host ...
2406
  	vers = hpriv->version;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
  	cap = hpriv->cap;
  	cap2 = hpriv->cap2;
  	impl = hpriv->port_map;
  
  	speed = (cap >> 20) & 0xf;
  	if (speed == 1)
  		speed_s = "1.5";
  	else if (speed == 2)
  		speed_s = "3";
  	else if (speed == 3)
  		speed_s = "6";
  	else
  		speed_s = "?";
  
  	dev_info(host->dev,
  		"AHCI %02x%02x.%02x%02x "
  		"%u slots %u ports %s Gbps 0x%x impl %s mode
  "
  		,
  
  		(vers >> 24) & 0xff,
  		(vers >> 16) & 0xff,
  		(vers >> 8) & 0xff,
  		vers & 0xff,
  
  		((cap >> 8) & 0x1f) + 1,
  		(cap & 0x1f) + 1,
  		speed_s,
  		impl,
  		scc_s);
  
  	dev_info(host->dev,
  		"flags: "
  		"%s%s%s%s%s%s%s"
  		"%s%s%s%s%s%s%s"
65fe1f0f6   Shane Huang   ahci: implement a...
2442
2443
2444
  		"%s%s%s%s%s%s%s"
  		"%s%s
  "
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
  		,
  
  		cap & HOST_CAP_64 ? "64bit " : "",
  		cap & HOST_CAP_NCQ ? "ncq " : "",
  		cap & HOST_CAP_SNTF ? "sntf " : "",
  		cap & HOST_CAP_MPS ? "ilck " : "",
  		cap & HOST_CAP_SSS ? "stag " : "",
  		cap & HOST_CAP_ALPM ? "pm " : "",
  		cap & HOST_CAP_LED ? "led " : "",
  		cap & HOST_CAP_CLO ? "clo " : "",
  		cap & HOST_CAP_ONLY ? "only " : "",
  		cap & HOST_CAP_PMP ? "pmp " : "",
  		cap & HOST_CAP_FBS ? "fbs " : "",
  		cap & HOST_CAP_PIO_MULTI ? "pio " : "",
  		cap & HOST_CAP_SSC ? "slum " : "",
  		cap & HOST_CAP_PART ? "part " : "",
  		cap & HOST_CAP_CCC ? "ccc " : "",
  		cap & HOST_CAP_EMS ? "ems " : "",
  		cap & HOST_CAP_SXS ? "sxs " : "",
65fe1f0f6   Shane Huang   ahci: implement a...
2464
2465
2466
  		cap2 & HOST_CAP2_DESO ? "deso " : "",
  		cap2 & HOST_CAP2_SADM ? "sadm " : "",
  		cap2 & HOST_CAP2_SDS ? "sds " : "",
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
  		cap2 & HOST_CAP2_APST ? "apst " : "",
  		cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
  		cap2 & HOST_CAP2_BOH ? "boh " : ""
  		);
  }
  EXPORT_SYMBOL_GPL(ahci_print_info);
  
  void ahci_set_em_messages(struct ahci_host_priv *hpriv,
  			  struct ata_port_info *pi)
  {
  	u8 messages;
  	void __iomem *mmio = hpriv->mmio;
  	u32 em_loc = readl(mmio + HOST_EM_LOC);
  	u32 em_ctl = readl(mmio + HOST_EM_CTL);
  
  	if (!ahci_em_messages || !(hpriv->cap & HOST_CAP_EMS))
  		return;
  
  	messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
008dbd61e   Harry Zhang   ahci: EM message ...
2486
  	if (messages) {
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2487
2488
  		/* store em_loc */
  		hpriv->em_loc = ((em_loc >> 16) * 4);
c06231661   Harry Zhang   ahci: add "em_buf...
2489
  		hpriv->em_buf_sz = ((em_loc & 0xff) * 4);
008dbd61e   Harry Zhang   ahci: EM message ...
2490
  		hpriv->em_msg_type = messages;
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2491
2492
2493
2494
2495
2496
  		pi->flags |= ATA_FLAG_EM;
  		if (!(em_ctl & EM_CTL_ALHD))
  			pi->flags |= ATA_FLAG_SW_ACTIVITY;
  	}
  }
  EXPORT_SYMBOL_GPL(ahci_set_em_messages);
d684a90d3   Dan Williams   ahci: per-port ms...
2497
  static int ahci_host_activate_multi_irqs(struct ata_host *host,
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2498
  					 struct scsi_host_template *sht)
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2499
  {
d684a90d3   Dan Williams   ahci: per-port ms...
2500
  	struct ahci_host_priv *hpriv = host->private_data;
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2501
2502
2503
2504
2505
  	int i, rc;
  
  	rc = ata_host_start(host);
  	if (rc)
  		return rc;
21bfd1aa9   Robert Richter   ahci: Store irq n...
2506
2507
2508
2509
  	/*
  	 * Requests IRQs according to AHCI-1.1 when multiple MSIs were
  	 * allocated. That is one MSI per port, starting from @irq.
  	 */
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2510
2511
  	for (i = 0; i < host->n_ports; i++) {
  		struct ahci_port_priv *pp = host->ports[i]->private_data;
0b9e2988a   Christoph Hellwig   ahci: use pci_all...
2512
  		int irq = hpriv->get_irq_vector(host, i);
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2513
2514
2515
  
  		/* Do not receive interrupts sent by dummy ports */
  		if (!pp) {
9b4b3f6a0   Christoph Hellwig   ahci: disable cor...
2516
  			disable_irq(irq);
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2517
2518
  			continue;
  		}
a6b7fb764   Dan Williams   ahci: switch from...
2519
2520
  		rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard,
  				0, pp->irq_desc, host->ports[i]);
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2521
  		if (rc)
0a142b269   Dan Williams   ahci: cleanup ahc...
2522
  			return rc;
d684a90d3   Dan Williams   ahci: per-port ms...
2523
  		ata_port_desc(host->ports[i], "irq %d", irq);
0a142b269   Dan Williams   ahci: cleanup ahc...
2524
  	}
d684a90d3   Dan Williams   ahci: per-port ms...
2525

0a142b269   Dan Williams   ahci: cleanup ahc...
2526
  	return ata_host_register(host, sht);
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2527
  }
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2528
2529
2530
2531
  
  /**
   *	ahci_host_activate - start AHCI host, request IRQs and register it
   *	@host: target ATA host
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2532
2533
   *	@sht: scsi_host_template to use when registering the host
   *
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2534
2535
2536
2537
2538
2539
   *	LOCKING:
   *	Inherited from calling layer (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno otherwise.
   */
21bfd1aa9   Robert Richter   ahci: Store irq n...
2540
  int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2541
2542
  {
  	struct ahci_host_priv *hpriv = host->private_data;
21bfd1aa9   Robert Richter   ahci: Store irq n...
2543
  	int irq = hpriv->irq;
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2544
  	int rc;
0b9e2988a   Christoph Hellwig   ahci: use pci_all...
2545
  	if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
f070d6715   Suman Tripathi   libahci: Implemen...
2546
  		if (hpriv->irq_handler)
d991c872a   Sander Eikelenboom   libata: Fixup awk...
2547
2548
2549
  			dev_warn(host->dev,
  			         "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented
  ");
0b9e2988a   Christoph Hellwig   ahci: use pci_all...
2550
2551
2552
2553
2554
2555
  		if (!hpriv->get_irq_vector) {
  			dev_err(host->dev,
  				"AHCI_HFLAG_MULTI_MSI requires ->get_irq_vector!
  ");
  			return -EIO;
  		}
f070d6715   Suman Tripathi   libahci: Implemen...
2556

d684a90d3   Dan Williams   ahci: per-port ms...
2557
  		rc = ahci_host_activate_multi_irqs(host, sht);
f070d6715   Suman Tripathi   libahci: Implemen...
2558
2559
  	} else {
  		rc = ata_host_activate(host, irq, hpriv->irq_handler,
7865f83fd   Tejun Heo   Revert "AHCI: Opt...
2560
  				       IRQF_SHARED, sht);
f070d6715   Suman Tripathi   libahci: Implemen...
2561
  	}
d1028e2f9   Alexander Gordeev   AHCI: Move host a...
2562
2563
  	return rc;
  }
1c62854f5   Alexander Gordeev   AHCI: Move ahci_h...
2564
  EXPORT_SYMBOL_GPL(ahci_host_activate);
365cfa1ed   Anton Vorontsov   ahci: Move generi...
2565
2566
2567
  MODULE_AUTHOR("Jeff Garzik");
  MODULE_DESCRIPTION("Common AHCI SATA low-level routines");
  MODULE_LICENSE("GPL");