kernel/generic: add ledtrig support to libata
authorJohn Crispin <john@openwrt.org>
Fri, 12 Dec 2014 20:24:21 +0000 (20:24 +0000)
committerJohn Crispin <john@openwrt.org>
Fri, 12 Dec 2014 20:24:21 +0000 (20:24 +0000)
SVN-Revision: 43674

target/linux/generic/patches-3.14/834-ledtrig-libata.patch [new file with mode: 0644]
target/linux/generic/patches-3.18/834-ledtrig-libata.patch [new file with mode: 0644]

diff --git a/target/linux/generic/patches-3.14/834-ledtrig-libata.patch b/target/linux/generic/patches-3.14/834-ledtrig-libata.patch
new file mode 100644 (file)
index 0000000..23663de
--- /dev/null
@@ -0,0 +1,162 @@
+From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 12 Dec 2014 13:38:33 +0100
+Subject: [PATCH] libata: add ledtrig support
+To: linux-ide@vger.kernel.org,
+    Tejun Heo <tj@kernel.org>
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index cd4cccb..7a085ec 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
+         If unsure, say Y.
++config ARCH_WANT_LIBATA_LEDS
++      bool
++
++config ATA_LEDS
++      bool "support ATA port LED triggers"
++      depends on ARCH_WANT_LIBATA_LEDS
++      select NEW_LEDS
++      select LEDS_CLASS
++      select LEDS_TRIGGERS
++      default y
++      help
++        This option adds a LED trigger for each registered ATA port.
++        It is used to drive disk activity leds connected via GPIO.
++
++        If unsure, say N.
++
+ config ATA_ACPI
+       bool "ATA ACPI Support"
+       depends on ACPI && PCI
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index 5c84fb5..eb49e02 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -725,6 +725,19 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+       return block;
+ }
++#if CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++      unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++      if (unlikely(!ap->ledtrig))
++              return;
++
++      led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *    ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *    @tf: Target ATA taskfile
+@@ -4761,6 +4774,9 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+                       break;
+               }
+       }
++#if CONFIG_ATA_LEDS
++      ata_led_act(ap);
++#endif
+       return qc;
+ }
+@@ -5671,6 +5687,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
+       ap->stats.unhandled_irq = 1;
+       ap->stats.idle_irq = 1;
+ #endif
++#if CONFIG_ATA_LEDS
++      ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+       ata_sff_port_init(ap);
+       return ap;
+@@ -5692,6 +5711,12 @@ static void ata_host_release(struct device *gendev, void *res)
+               kfree(ap->pmp_link);
+               kfree(ap->slave_link);
++#if CONFIG_ATA_LEDS
++              if (ap->ledtrig) {
++                      led_trigger_unregister(ap->ledtrig);
++                      kfree(ap->ledtrig);
++              };
++#endif
+               kfree(ap);
+               host->ports[i] = NULL;
+       }
+@@ -6138,7 +6163,23 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
+               host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+               host->ports[i]->local_port_no = i + 1;
+       }
++#if CONFIG_ATA_LEDS
++      for (i = 0; i < host->n_ports; i++) {
++              if (unlikely(!host->ports[i]->ledtrig))
++                      continue;
++
++              snprintf(host->ports[i]->ledtrig_name,
++                      sizeof(host->ports[i]->ledtrig_name), "ata%u",
++                      host->ports[i]->print_id);
++              host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++              if (led_trigger_register(host->ports[i]->ledtrig)) {
++                      kfree(host->ports[i]->ledtrig);
++                      host->ports[i]->ledtrig = NULL;
++              }
++      }
++#endif
+       /* Create associated sysfs transport objects  */
+       for (i = 0; i < host->n_ports; i++) {
+               rc = ata_tport_add(host->dev,host->ports[i]);
+diff --git a/include/linux/libata.h b/include/linux/libata.h
+index 2d18241..4428e2b 100644
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -38,6 +38,9 @@
+ #include <linux/acpi.h>
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
++#if IS_ENABLED(CONFIG_ATA_LEDS)
++#include <linux/leds.h>
++#endif
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -862,6 +865,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+       struct ata_acpi_gtm     __acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++      struct led_trigger      *ledtrig;
++      char                    ledtrig_name[8];
++#endif
++
+       /* owned by EH */
+       u8                      sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
+-- 
+2.1.3
+
diff --git a/target/linux/generic/patches-3.18/834-ledtrig-libata.patch b/target/linux/generic/patches-3.18/834-ledtrig-libata.patch
new file mode 100644 (file)
index 0000000..23663de
--- /dev/null
@@ -0,0 +1,162 @@
+From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 12 Dec 2014 13:38:33 +0100
+Subject: [PATCH] libata: add ledtrig support
+To: linux-ide@vger.kernel.org,
+    Tejun Heo <tj@kernel.org>
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index cd4cccb..7a085ec 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
+         If unsure, say Y.
++config ARCH_WANT_LIBATA_LEDS
++      bool
++
++config ATA_LEDS
++      bool "support ATA port LED triggers"
++      depends on ARCH_WANT_LIBATA_LEDS
++      select NEW_LEDS
++      select LEDS_CLASS
++      select LEDS_TRIGGERS
++      default y
++      help
++        This option adds a LED trigger for each registered ATA port.
++        It is used to drive disk activity leds connected via GPIO.
++
++        If unsure, say N.
++
+ config ATA_ACPI
+       bool "ATA ACPI Support"
+       depends on ACPI && PCI
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index 5c84fb5..eb49e02 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -725,6 +725,19 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+       return block;
+ }
++#if CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++      unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++      if (unlikely(!ap->ledtrig))
++              return;
++
++      led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *    ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *    @tf: Target ATA taskfile
+@@ -4761,6 +4774,9 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+                       break;
+               }
+       }
++#if CONFIG_ATA_LEDS
++      ata_led_act(ap);
++#endif
+       return qc;
+ }
+@@ -5671,6 +5687,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
+       ap->stats.unhandled_irq = 1;
+       ap->stats.idle_irq = 1;
+ #endif
++#if CONFIG_ATA_LEDS
++      ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+       ata_sff_port_init(ap);
+       return ap;
+@@ -5692,6 +5711,12 @@ static void ata_host_release(struct device *gendev, void *res)
+               kfree(ap->pmp_link);
+               kfree(ap->slave_link);
++#if CONFIG_ATA_LEDS
++              if (ap->ledtrig) {
++                      led_trigger_unregister(ap->ledtrig);
++                      kfree(ap->ledtrig);
++              };
++#endif
+               kfree(ap);
+               host->ports[i] = NULL;
+       }
+@@ -6138,7 +6163,23 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
+               host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+               host->ports[i]->local_port_no = i + 1;
+       }
++#if CONFIG_ATA_LEDS
++      for (i = 0; i < host->n_ports; i++) {
++              if (unlikely(!host->ports[i]->ledtrig))
++                      continue;
++
++              snprintf(host->ports[i]->ledtrig_name,
++                      sizeof(host->ports[i]->ledtrig_name), "ata%u",
++                      host->ports[i]->print_id);
++              host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++              if (led_trigger_register(host->ports[i]->ledtrig)) {
++                      kfree(host->ports[i]->ledtrig);
++                      host->ports[i]->ledtrig = NULL;
++              }
++      }
++#endif
+       /* Create associated sysfs transport objects  */
+       for (i = 0; i < host->n_ports; i++) {
+               rc = ata_tport_add(host->dev,host->ports[i]);
+diff --git a/include/linux/libata.h b/include/linux/libata.h
+index 2d18241..4428e2b 100644
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -38,6 +38,9 @@
+ #include <linux/acpi.h>
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
++#if IS_ENABLED(CONFIG_ATA_LEDS)
++#include <linux/leds.h>
++#endif
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -862,6 +865,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+       struct ata_acpi_gtm     __acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++      struct led_trigger      *ledtrig;
++      char                    ledtrig_name[8];
++#endif
++
+       /* owned by EH */
+       u8                      sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
+-- 
+2.1.3
+