blob: 2fbbb5461bad6b8ddca2cad464b740b68423a338 [file] [log] [blame]
developerf11ee162022-04-12 11:17:45 +08001From: Daniel Golle <daniel@makrotopia.org>
2Subject: libata: add ledtrig support
3
4This adds a LED trigger for each ATA port indicating disk activity.
5
6As this is needed only on specific platforms (NAS SoCs and such),
7these platforms should define ARCH_WANTS_LIBATA_LEDS if there
8are boards with LED(s) intended to indicate ATA disk activity and
9need the OS to take care of that.
10In that way, if not selected, LED trigger support not will be
11included in libata-core and both, codepaths and structures remain
12untouched.
13
14Signed-off-by: Daniel Golle <daniel@makrotopia.org>
15---
16 drivers/ata/Kconfig | 16 ++++++++++++++++
17 drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
18 include/linux/libata.h | 9 +++++++++
19 3 files changed, 66 insertions(+)
20
21--- a/drivers/ata/Kconfig
22+++ b/drivers/ata/Kconfig
23@@ -45,6 +45,22 @@ config ATA_VERBOSE_ERROR
24
25 If unsure, say Y.
26
27+config ARCH_WANT_LIBATA_LEDS
28+ bool
29+
30+config ATA_LEDS
31+ bool "support ATA port LED triggers"
32+ depends on ARCH_WANT_LIBATA_LEDS
33+ select NEW_LEDS
34+ select LEDS_CLASS
35+ select LEDS_TRIGGERS
36+ default y
37+ help
38+ This option adds a LED trigger for each registered ATA port.
39+ It is used to drive disk activity leds connected via GPIO.
40+
41+ If unsure, say N.
42+
43 config ATA_ACPI
44 bool "ATA ACPI Support"
45 depends on ACPI
46--- a/drivers/ata/libata-core.c
47+++ b/drivers/ata/libata-core.c
48@@ -714,6 +714,19 @@ u64 ata_tf_read_block(const struct ata_t
49 return block;
50 }
51
52+#ifdef CONFIG_ATA_LEDS
53+#define LIBATA_BLINK_DELAY 20 /* ms */
54+static inline void ata_led_act(struct ata_port *ap)
55+{
56+ unsigned long led_delay = LIBATA_BLINK_DELAY;
57+
58+ if (unlikely(!ap->ledtrig))
59+ return;
60+
61+ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
62+}
63+#endif
64+
65 /**
66 * ata_build_rw_tf - Build ATA taskfile for given read/write request
67 * @tf: Target ATA taskfile
68@@ -5152,6 +5165,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
69 if (tag < 0)
70 return NULL;
71 }
72+#ifdef CONFIG_ATA_LEDS
73+ ata_led_act(ap);
74+#endif
75
76 qc = __ata_qc_from_tag(ap, tag);
77 qc->tag = qc->hw_tag = tag;
78@@ -6088,6 +6104,9 @@ struct ata_port *ata_port_alloc(struct a
79 ap->stats.unhandled_irq = 1;
80 ap->stats.idle_irq = 1;
81 #endif
82+#ifdef CONFIG_ATA_LEDS
83+ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
84+#endif
85 ata_sff_port_init(ap);
86
87 return ap;
88@@ -6123,6 +6142,12 @@ static void ata_host_release(struct kref
89
90 kfree(ap->pmp_link);
91 kfree(ap->slave_link);
92+#ifdef CONFIG_ATA_LEDS
93+ if (ap->ledtrig) {
94+ led_trigger_unregister(ap->ledtrig);
95+ kfree(ap->ledtrig);
96+ };
97+#endif
98 kfree(ap);
99 host->ports[i] = NULL;
100 }
101@@ -6586,7 +6611,23 @@ int ata_host_register(struct ata_host *h
102 host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
103 host->ports[i]->local_port_no = i + 1;
104 }
105+#ifdef CONFIG_ATA_LEDS
106+ for (i = 0; i < host->n_ports; i++) {
107+ if (unlikely(!host->ports[i]->ledtrig))
108+ continue;
109
110+ snprintf(host->ports[i]->ledtrig_name,
111+ sizeof(host->ports[i]->ledtrig_name), "ata%u",
112+ host->ports[i]->print_id);
113+
114+ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
115+
116+ if (led_trigger_register(host->ports[i]->ledtrig)) {
117+ kfree(host->ports[i]->ledtrig);
118+ host->ports[i]->ledtrig = NULL;
119+ }
120+ }
121+#endif
122 /* Create associated sysfs transport objects */
123 for (i = 0; i < host->n_ports; i++) {
124 rc = ata_tport_add(host->dev,host->ports[i]);
125--- a/include/linux/libata.h
126+++ b/include/linux/libata.h
127@@ -23,6 +23,9 @@
128 #include <linux/cdrom.h>
129 #include <linux/sched.h>
130 #include <linux/async.h>
131+#ifdef CONFIG_ATA_LEDS
132+#include <linux/leds.h>
133+#endif
134
135 /*
136 * Define if arch has non-standard setup. This is a _PCI_ standard
137@@ -882,6 +885,12 @@ struct ata_port {
138 #ifdef CONFIG_ATA_ACPI
139 struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
140 #endif
141+
142+#ifdef CONFIG_ATA_LEDS
143+ struct led_trigger *ledtrig;
144+ char ledtrig_name[8];
145+#endif
146+
147 /* owned by EH */
148 u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
149 };