History

HSI: hsi: Rework hsi_event interface

Remove custom hack and make use of the notifier chain interfaces for delivering events from the ports to their associated clients. Clients that want to receive port events need to register their callbacks using hsi_register_port_event(). The callbacks can be called in interrupt context. Use hsi_unregestier_port_event() to undo the registration.

Carlos Chinea committed 14 years ago

Commit ec1c56f1 parent 6f02b9e2 files · +68 −58Browse files

Unified · Split

2 files
  1. drivers/hsi/hsi.c +54 −47
  2. include/linux/hsi/hsi.h +14 −11
drivers/hsi/hsi.c+54−47
@@ -21,12 +21,11 @@ · 20 unmodified lines
2121 */
2222 #include <linux/hsi/hsi.h>
2323 #include <linux/compiler.h>
24−#include <linux/rwsem.h>
2524 #include <linux/list.h>
26−#include <linux/spinlock.h>
2725 #include <linux/kobject.h>
2826 #include <linux/slab.h>
2927 #include <linux/string.h>
28+#include <linux/notifier.h>
3029 #include "hsi_core.h"
3130
3231 static ssize_t modalias_show(struct device *dev,
@@ -67,7 +66,6 @@ static void hsi_client_release(struct device *dev) · 34 unmodified lines
6766 static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
6867 {
6968 struct hsi_client *cl;
70− unsigned long flags;
7169
7270 cl = kzalloc(sizeof(*cl), GFP_KERNEL);
7371 if (!cl)
@@ -79,9 +77,6 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) · 5 unmodified lines
7977 cl->device.release = hsi_client_release;
8078 dev_set_name(&cl->device, info->name);
8179 cl->device.platform_data = info->platform_data;
82− spin_lock_irqsave(&port->clock, flags);
83− list_add_tail(&cl->link, &port->clients);
84− spin_unlock_irqrestore(&port->clock, flags);
8580 if (info->archdata)
8681 cl->device.archdata = *info->archdata;
8782 if (device_register(&cl->device) < 0) {
@@ -106,13 +101,6 @@ static void hsi_scan_board_info(struct hsi_controller *hsi) · 18 unmodified lines
106101
107102 static int hsi_remove_client(struct device *dev, void *data __maybe_unused)
108103 {
109− struct hsi_client *cl = to_hsi_client(dev);
110− struct hsi_port *port = to_hsi_port(dev->parent);
111− unsigned long flags;
112−
113− spin_lock_irqsave(&port->clock, flags);
114− list_del(&cl->link);
115− spin_unlock_irqrestore(&port->clock, flags);
116104 device_unregister(dev);
117105
118106 return 0;
@@ -271,8 +259,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) · 152 unmodified lines
271259 port[i]->stop_tx = hsi_dummy_cl;
272260 port[i]->release = hsi_dummy_cl;
273261 mutex_init(&port[i]->lock);
274− INIT_LIST_HEAD(&hsi->port[i]->clients);
275− spin_lock_init(&hsi->port[i]->clock);
262+ ATOMIC_INIT_NOTIFIER_HEAD(&port[i]->n_head);
276263 dev_set_name(&port[i]->device, "port%d", i);
277264 hsi->port[i]->device.release = hsi_port_release;
278265 device_initialize(&hsi->port[i]->device);
@@ -420,37 +407,67 @@ void hsi_release_port(struct hsi_client *cl) · 141 unmodified lines
420407 }
421408 EXPORT_SYMBOL_GPL(hsi_release_port);
422409
423−static int hsi_start_rx(struct hsi_client *cl, void *data __maybe_unused)
410+static int hsi_event_notifier_call(struct notifier_block *nb,
411+ unsigned long event, void *data __maybe_unused)
424412 {
425− if (cl->hsi_start_rx)
426− (*cl->hsi_start_rx)(cl);
413+ struct hsi_client *cl = container_of(nb, struct hsi_client, nb);
414+
415+ (*cl->ehandler)(cl, event);
427416
428417 return 0;
429418 }
430419
431−static int hsi_stop_rx(struct hsi_client *cl, void *data __maybe_unused)
420+/**
421+ * hsi_register_port_event - Register a client to receive port events
422+ * @cl: HSI client that wants to receive port events
423+ * @cb: Event handler callback
424+ *
425+ * Clients should register a callback to be able to receive
426+ * events from the ports. Registration should happen after
427+ * claiming the port.
428+ * The handler can be called in interrupt context.
429+ *
430+ * Returns -errno on error, or 0 on success.
431+ */
432+int hsi_register_port_event(struct hsi_client *cl,
433+ void (*handler)(struct hsi_client *, unsigned long))
432434 {
433− if (cl->hsi_stop_rx)
434− (*cl->hsi_stop_rx)(cl);
435+ struct hsi_port *port = hsi_get_port(cl);
435436
436− return 0;
437+ if (!handler || cl->ehandler)
438+ return -EINVAL;
439+ if (!hsi_port_claimed(cl))
440+ return -EACCES;
441+ cl->ehandler = handler;
442+ cl->nb.notifier_call = hsi_event_notifier_call;
443+
444+ return atomic_notifier_chain_register(&port->n_head, &cl->nb);
437445 }
446+EXPORT_SYMBOL_GPL(hsi_register_port_event);
438447
439−static int hsi_port_for_each_client(struct hsi_port *port, void *data,
440− int (*fn)(struct hsi_client *cl, void *data))
448+/**
449+ * hsi_unregister_port_event - Stop receiving port events for a client
450+ * @cl: HSI client that wants to stop receiving port events
451+ *
452+ * Clients should call this function before releasing their associated
453+ * port.
454+ *
455+ * Returns -errno on error, or 0 on success.
456+ */
457+int hsi_unregister_port_event(struct hsi_client *cl)
441458 {
442− struct hsi_client *cl;
459+ struct hsi_port *port = hsi_get_port(cl);
460+ int err;
443461
444− spin_lock(&port->clock);
445− list_for_each_entry(cl, &port->clients, link) {
446− spin_unlock(&port->clock);
447− (*fn)(cl, data);
448− spin_lock(&port->clock);
449− }
450− spin_unlock(&port->clock);
462+ WARN_ON(!hsi_port_claimed(cl));
451463
452− return 0;
464+ err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb);
465+ if (!err)
466+ cl->ehandler = NULL;
467+
468+ return err;
453469 }
470+EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
454471
455472 /**
456473 * hsi_event -Notifies clients about port events
@@ -464,22 +481,12 @@ static int hsi_port_for_each_client(struct hsi_port *port, void *data, · 7 unmodified lines
464481 * Events:
465482 * HSI_EVENT_START_RX - Incoming wake line high
466483 * HSI_EVENT_STOP_RX - Incoming wake line down
484+ *
485+ * Returns -errno on error, or 0 on success.
467486 */
468−void hsi_event(struct hsi_port *port, unsigned int event)
487+int hsi_event(struct hsi_port *port, unsigned long event)
469488 {
470− int (*fn)(struct hsi_client *cl, void *data);
471−
472− switch (event) {
473− case HSI_EVENT_START_RX:
474− fn = hsi_start_rx;
475− break;
476− case HSI_EVENT_STOP_RX:
477− fn = hsi_stop_rx;
478− break;
479− default:
480− return;
481− }
482− hsi_port_for_each_client(port, NULL, fn);
489+ return atomic_notifier_call_chain(&port->n_head, event, NULL);
483490 }
484491 EXPORT_SYMBOL_GPL(hsi_event);
485492
include/linux/hsi/hsi.h+14−11
@@ -26,9 +26,9 @@ · 25 unmodified lines
2626 #include <linux/device.h>
2727 #include <linux/mutex.h>
2828 #include <linux/scatterlist.h>
29−#include <linux/spinlock.h>
3029 #include <linux/list.h>
3130 #include <linux/module.h>
31+#include <linux/notifier.h>
3232
3333 /* HSI message ttype */
3434 #define HSI_MSG_READ 0
@@ -121,18 +121,18 @@ static inline int hsi_register_board_info(struct hsi_board_info const *info, · 86 unmodified lines
121121 * @device: Driver model representation of the device
122122 * @tx_cfg: HSI TX configuration
123123 * @rx_cfg: HSI RX configuration
124− * @hsi_start_rx: Called after incoming wake line goes high
125− * @hsi_stop_rx: Called after incoming wake line goes low
124+ * @e_handler: Callback for handling port events (RX Wake High/Low)
125+ * @pclaimed: Keeps tracks if the clients claimed its associated HSI port
126+ * @nb: Notifier block for port events
126127 */
127128 struct hsi_client {
128129 struct device device;
129130 struct hsi_config tx_cfg;
130131 struct hsi_config rx_cfg;
131− void (*hsi_start_rx)(struct hsi_client *cl);
132− void (*hsi_stop_rx)(struct hsi_client *cl);
133132 /* private: */
133+ void (*ehandler)(struct hsi_client *, unsigned long);
134134 unsigned int pclaimed:1;
135− struct list_head link;
135+ struct notifier_block nb;
136136 };
137137
138138 #define to_hsi_client(dev) container_of(dev, struct hsi_client, device)
@@ -147,6 +147,10 @@ static inline void *hsi_client_drvdata(struct hsi_client *cl) · 8 unmodified lines
147147 return dev_get_drvdata(&cl->device);
148148 }
149149
150+int hsi_register_port_event(struct hsi_client *cl,
151+ void (*handler)(struct hsi_client *, unsigned long));
152+int hsi_unregister_port_event(struct hsi_client *cl);
153+
150154 /**
151155 * struct hsi_client_driver - Driver associated to an HSI client
152156 * @driver: Driver model representation of the driver
@@ -214,8 +218,7 @@ void hsi_free_msg(struct hsi_msg *msg); · 61 unmodified lines
214218 * @start_tx: Callback to inform that a client wants to TX data
215219 * @stop_tx: Callback to inform that a client no longer wishes to TX data
216220 * @release: Callback to inform that a client no longer uses the port
217− * @clients: List of hsi_clients using the port.
218− * @clock: Lock to serialize access to the clients list.
221+ * @n_head: Notifier chain for signaling port events to the clients.
219222 */
220223 struct hsi_port {
221224 struct device device;
@@ -231,14 +234,14 @@ struct hsi_port { · 9 unmodified lines
231234 int (*start_tx)(struct hsi_client *cl);
232235 int (*stop_tx)(struct hsi_client *cl);
233236 int (*release)(struct hsi_client *cl);
234− struct list_head clients;
235− spinlock_t clock;
237+ /* private */
238+ struct atomic_notifier_head n_head;
236239 };
237240
238241 #define to_hsi_port(dev) container_of(dev, struct hsi_port, device)
239242 #define hsi_get_port(cl) to_hsi_port((cl)->device.parent)
240243
241−void hsi_event(struct hsi_port *port, unsigned int event);
244+int hsi_event(struct hsi_port *port, unsigned long event);
242245 int hsi_claim_port(struct hsi_client *cl, unsigned int share);
243246 void hsi_release_port(struct hsi_client *cl);
244247