diff options
-rw-r--r-- | drivers/ata/sata_fsl.c | 111 |
1 files changed, 107 insertions, 4 deletions
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 0120b0d1e9a5..d6577b93bee3 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Author: Ashish Kalra <ashish.kalra@freescale.com> | 6 | * Author: Ashish Kalra <ashish.kalra@freescale.com> |
7 | * Li Yang <leoli@freescale.com> | 7 | * Li Yang <leoli@freescale.com> |
8 | * | 8 | * |
9 | * Copyright (c) 2006-2007, 2011 Freescale Semiconductor, Inc. | 9 | * Copyright (c) 2006-2007, 2011-2012 Freescale Semiconductor, Inc. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
12 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
@@ -26,6 +26,15 @@ | |||
26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
27 | #include <linux/of_platform.h> | 27 | #include <linux/of_platform.h> |
28 | 28 | ||
29 | static unsigned int intr_coalescing_count; | ||
30 | module_param(intr_coalescing_count, int, S_IRUGO); | ||
31 | MODULE_PARM_DESC(intr_coalescing_count, | ||
32 | "INT coalescing count threshold (1..31)"); | ||
33 | |||
34 | static unsigned int intr_coalescing_ticks; | ||
35 | module_param(intr_coalescing_ticks, int, S_IRUGO); | ||
36 | MODULE_PARM_DESC(intr_coalescing_ticks, | ||
37 | "INT coalescing timer threshold in AHB ticks"); | ||
29 | /* Controller information */ | 38 | /* Controller information */ |
30 | enum { | 39 | enum { |
31 | SATA_FSL_QUEUE_DEPTH = 16, | 40 | SATA_FSL_QUEUE_DEPTH = 16, |
@@ -83,6 +92,16 @@ enum { | |||
83 | }; | 92 | }; |
84 | 93 | ||
85 | /* | 94 | /* |
95 | * Interrupt Coalescing Control Register bitdefs */ | ||
96 | enum { | ||
97 | ICC_MIN_INT_COUNT_THRESHOLD = 1, | ||
98 | ICC_MAX_INT_COUNT_THRESHOLD = ((1 << 5) - 1), | ||
99 | ICC_MIN_INT_TICKS_THRESHOLD = 0, | ||
100 | ICC_MAX_INT_TICKS_THRESHOLD = ((1 << 19) - 1), | ||
101 | ICC_SAFE_INT_TICKS = 1, | ||
102 | }; | ||
103 | |||
104 | /* | ||
86 | * Host Controller command register set - per port | 105 | * Host Controller command register set - per port |
87 | */ | 106 | */ |
88 | enum { | 107 | enum { |
@@ -263,8 +282,65 @@ struct sata_fsl_host_priv { | |||
263 | void __iomem *csr_base; | 282 | void __iomem *csr_base; |
264 | int irq; | 283 | int irq; |
265 | int data_snoop; | 284 | int data_snoop; |
285 | struct device_attribute intr_coalescing; | ||
266 | }; | 286 | }; |
267 | 287 | ||
288 | static void fsl_sata_set_irq_coalescing(struct ata_host *host, | ||
289 | unsigned int count, unsigned int ticks) | ||
290 | { | ||
291 | struct sata_fsl_host_priv *host_priv = host->private_data; | ||
292 | void __iomem *hcr_base = host_priv->hcr_base; | ||
293 | |||
294 | if (count > ICC_MAX_INT_COUNT_THRESHOLD) | ||
295 | count = ICC_MAX_INT_COUNT_THRESHOLD; | ||
296 | else if (count < ICC_MIN_INT_COUNT_THRESHOLD) | ||
297 | count = ICC_MIN_INT_COUNT_THRESHOLD; | ||
298 | |||
299 | if (ticks > ICC_MAX_INT_TICKS_THRESHOLD) | ||
300 | ticks = ICC_MAX_INT_TICKS_THRESHOLD; | ||
301 | else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks) && | ||
302 | (count > ICC_MIN_INT_COUNT_THRESHOLD)) | ||
303 | ticks = ICC_SAFE_INT_TICKS; | ||
304 | |||
305 | spin_lock(&host->lock); | ||
306 | iowrite32((count << 24 | ticks), hcr_base + ICC); | ||
307 | |||
308 | intr_coalescing_count = count; | ||
309 | intr_coalescing_ticks = ticks; | ||
310 | spin_unlock(&host->lock); | ||
311 | |||
312 | DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n", | ||
313 | intr_coalescing_count, intr_coalescing_ticks); | ||
314 | DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n", | ||
315 | hcr_base, ioread32(hcr_base + ICC)); | ||
316 | } | ||
317 | |||
318 | static ssize_t fsl_sata_intr_coalescing_show(struct device *dev, | ||
319 | struct device_attribute *attr, char *buf) | ||
320 | { | ||
321 | return sprintf(buf, "%d %d\n", | ||
322 | intr_coalescing_count, intr_coalescing_ticks); | ||
323 | } | ||
324 | |||
325 | static ssize_t fsl_sata_intr_coalescing_store(struct device *dev, | ||
326 | struct device_attribute *attr, | ||
327 | const char *buf, size_t count) | ||
328 | { | ||
329 | unsigned int coalescing_count, coalescing_ticks; | ||
330 | |||
331 | if (sscanf(buf, "%d%d", | ||
332 | &coalescing_count, | ||
333 | &coalescing_ticks) != 2) { | ||
334 | printk(KERN_ERR "fsl-sata: wrong parameter format.\n"); | ||
335 | return -EINVAL; | ||
336 | } | ||
337 | |||
338 | fsl_sata_set_irq_coalescing(dev_get_drvdata(dev), | ||
339 | coalescing_count, coalescing_ticks); | ||
340 | |||
341 | return strlen(buf); | ||
342 | } | ||
343 | |||
268 | static inline unsigned int sata_fsl_tag(unsigned int tag, | 344 | static inline unsigned int sata_fsl_tag(unsigned int tag, |
269 | void __iomem *hcr_base) | 345 | void __iomem *hcr_base) |
270 | { | 346 | { |
@@ -346,10 +422,10 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, | |||
346 | (unsigned long long)sg_addr, sg_len); | 422 | (unsigned long long)sg_addr, sg_len); |
347 | 423 | ||
348 | /* warn if each s/g element is not dword aligned */ | 424 | /* warn if each s/g element is not dword aligned */ |
349 | if (sg_addr & 0x03) | 425 | if (unlikely(sg_addr & 0x03)) |
350 | ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n", | 426 | ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n", |
351 | (unsigned long long)sg_addr); | 427 | (unsigned long long)sg_addr); |
352 | if (sg_len & 0x03) | 428 | if (unlikely(sg_len & 0x03)) |
353 | ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n", | 429 | ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n", |
354 | sg_len); | 430 | sg_len); |
355 | 431 | ||
@@ -1245,6 +1321,13 @@ static int sata_fsl_init_controller(struct ata_host *host) | |||
1245 | iowrite32(0x00000FFFF, hcr_base + CE); | 1321 | iowrite32(0x00000FFFF, hcr_base + CE); |
1246 | iowrite32(0x00000FFFF, hcr_base + DE); | 1322 | iowrite32(0x00000FFFF, hcr_base + DE); |
1247 | 1323 | ||
1324 | /* | ||
1325 | * reset the number of command complete bits which will cause the | ||
1326 | * interrupt to be signaled | ||
1327 | */ | ||
1328 | fsl_sata_set_irq_coalescing(host, intr_coalescing_count, | ||
1329 | intr_coalescing_ticks); | ||
1330 | |||
1248 | /* | 1331 | /* |
1249 | * host controller will be brought on-line, during xx_port_start() | 1332 | * host controller will be brought on-line, during xx_port_start() |
1250 | * callback, that should also initiate the OOB, COMINIT sequence | 1333 | * callback, that should also initiate the OOB, COMINIT sequence |
@@ -1309,7 +1392,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) | |||
1309 | void __iomem *csr_base = NULL; | 1392 | void __iomem *csr_base = NULL; |
1310 | struct sata_fsl_host_priv *host_priv = NULL; | 1393 | struct sata_fsl_host_priv *host_priv = NULL; |
1311 | int irq; | 1394 | int irq; |
1312 | struct ata_host *host; | 1395 | struct ata_host *host = NULL; |
1313 | u32 temp; | 1396 | u32 temp; |
1314 | 1397 | ||
1315 | struct ata_port_info pi = sata_fsl_port_info[0]; | 1398 | struct ata_port_info pi = sata_fsl_port_info[0]; |
@@ -1356,6 +1439,10 @@ static int sata_fsl_probe(struct platform_device *ofdev) | |||
1356 | 1439 | ||
1357 | /* allocate host structure */ | 1440 | /* allocate host structure */ |
1358 | host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS); | 1441 | host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS); |
1442 | if (!host) { | ||
1443 | retval = -ENOMEM; | ||
1444 | goto error_exit_with_cleanup; | ||
1445 | } | ||
1359 | 1446 | ||
1360 | /* host->iomap is not used currently */ | 1447 | /* host->iomap is not used currently */ |
1361 | host->private_data = host_priv; | 1448 | host->private_data = host_priv; |
@@ -1373,10 +1460,24 @@ static int sata_fsl_probe(struct platform_device *ofdev) | |||
1373 | 1460 | ||
1374 | dev_set_drvdata(&ofdev->dev, host); | 1461 | dev_set_drvdata(&ofdev->dev, host); |
1375 | 1462 | ||
1463 | host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show; | ||
1464 | host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store; | ||
1465 | sysfs_attr_init(&host_priv->intr_coalescing.attr); | ||
1466 | host_priv->intr_coalescing.attr.name = "intr_coalescing"; | ||
1467 | host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR; | ||
1468 | retval = device_create_file(host->dev, &host_priv->intr_coalescing); | ||
1469 | if (retval) | ||
1470 | goto error_exit_with_cleanup; | ||
1471 | |||
1376 | return 0; | 1472 | return 0; |
1377 | 1473 | ||
1378 | error_exit_with_cleanup: | 1474 | error_exit_with_cleanup: |
1379 | 1475 | ||
1476 | if (host) { | ||
1477 | dev_set_drvdata(&ofdev->dev, NULL); | ||
1478 | ata_host_detach(host); | ||
1479 | } | ||
1480 | |||
1380 | if (hcr_base) | 1481 | if (hcr_base) |
1381 | iounmap(hcr_base); | 1482 | iounmap(hcr_base); |
1382 | if (host_priv) | 1483 | if (host_priv) |
@@ -1390,6 +1491,8 @@ static int sata_fsl_remove(struct platform_device *ofdev) | |||
1390 | struct ata_host *host = dev_get_drvdata(&ofdev->dev); | 1491 | struct ata_host *host = dev_get_drvdata(&ofdev->dev); |
1391 | struct sata_fsl_host_priv *host_priv = host->private_data; | 1492 | struct sata_fsl_host_priv *host_priv = host->private_data; |
1392 | 1493 | ||
1494 | device_remove_file(&ofdev->dev, &host_priv->intr_coalescing); | ||
1495 | |||
1393 | ata_host_detach(host); | 1496 | ata_host_detach(host); |
1394 | 1497 | ||
1395 | dev_set_drvdata(&ofdev->dev, NULL); | 1498 | dev_set_drvdata(&ofdev->dev, NULL); |