shared ARM updates
[tomato.git] / release / src-rt-6.x.4708 / shared / bcm_notif.c
blobf46e03f77eb4d40af029690153b730ec344c724a
1 /*
2 * Implementation of event notification component.
4 * Copyright (C) 2013, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id$
15 #include <bcm_cfg.h>
16 #include <typedefs.h>
17 #include <osl.h>
18 #include <bcmutils.h>
19 #include "bcm_notif_priv.h"
20 #include <bcm_notif_pub.h>
21 #include <bcm_mpool_pub.h>
24 #if defined(BCMDBG) || defined(BCMDBG_ERR)
25 #define NOTIF_ERROR(args) printf args
26 #else
27 #define NOTIF_ERROR(args)
28 #endif
31 static void dealloc_module(bcm_notif_module_t *notif_module);
35 * bcm_notif_attach()
37 * Notifier module attach-time initialization.
39 * Parameters:
40 * osh Operating system handle.
41 * mpm Memory pool manager handle.
42 * max_notif_servers Maximum number of supported servers.
43 * max_notif_clients Maximum number of supported clients.
44 * Returns:
45 * Global notifier module object. NULL on error.
47 bcm_notif_module_t* BCMATTACHFN(bcm_notif_attach)(osl_t *osh,
48 bcm_mpm_mgr_h mpm,
49 int max_notif_servers,
50 int max_notif_clients)
52 bcm_notif_module_t *notif_module;
53 int ret;
55 /* Allocate global notifier module state. */
56 if ((notif_module = MALLOC(osh, sizeof(*notif_module))) == NULL) {
57 NOTIF_ERROR(("%s: out of mem, malloced %d bytes\n",
58 __FUNCTION__, MALLOCED(osh)));
59 goto fail;
62 /* Init global notifier module state. */
63 memset(notif_module, 0, sizeof(*notif_module));
64 notif_module->osh = osh;
65 notif_module->mpm = mpm;
67 /* Create memory pool for server objects. */
68 ret = bcm_mpm_create_prealloc_pool(mpm,
69 sizeof(struct bcm_notif_list_struct),
70 max_notif_servers, NULL, 0,
71 "notif_s", &notif_module->server_mem_pool);
72 if (ret != BCME_OK) {
73 goto fail;
76 /* Create memory pool for client objects. */
77 ret = bcm_mpm_create_prealloc_pool(mpm,
78 sizeof(struct bcm_notif_client_request),
79 max_notif_clients, NULL, 0,
80 "notif_c", &notif_module->client_mem_pool);
81 if (ret != BCME_OK) {
82 goto fail;
86 /* Success. */
87 return (notif_module);
89 fail:
90 dealloc_module(notif_module);
92 return (NULL);
96 * bcm_notif_detach()
98 * Notifier module detach-time deinitialization.
100 * Parameters:
101 * notif_module Global notifier module object.
102 * Returns:
103 * Nothing.
105 void BCMATTACHFN(bcm_notif_detach)(bcm_notif_module_t *notif_module)
107 dealloc_module(notif_module);
112 * dealloc_module()
114 * Helper function to perform common resource deallocation.
116 * Parameters:
117 * notif_module Global notifier module object.
118 * Returns:
119 * Nothing.
121 static void BCMATTACHFN(dealloc_module)(bcm_notif_module_t *notif_module)
123 if (notif_module != NULL) {
125 if (notif_module->client_mem_pool != NULL) {
126 bcm_mpm_delete_prealloc_pool(notif_module->mpm,
127 &notif_module->client_mem_pool);
130 if (notif_module->server_mem_pool != NULL) {
131 bcm_mpm_delete_prealloc_pool(notif_module->mpm,
132 &notif_module->server_mem_pool);
135 MFREE(notif_module->osh, notif_module, sizeof(*notif_module));
141 * bcm_notif_create_list()
143 * Initialize new list. Allocates memory.
145 * Parameters:
146 * notif_module Global notifier module object.
147 * hdlp Pointer to opaque list handle.
148 * Returns:
149 * BCME_OK Object initialized successfully. May be used.
150 * BCME_NOMEM Initialization failed due to no memory. Object must not be used
152 int BCMATTACHFN(bcm_notif_create_list)(bcm_notif_module_t *notif_module, bcm_notif_h *hdlp)
154 int result = BCME_OK;
156 if ((*hdlp = bcm_mp_alloc(notif_module->server_mem_pool)) == NULL) {
157 result = BCME_NOMEM;
159 else {
160 memset(*hdlp, 0, sizeof(**hdlp));
161 (*hdlp)->allow_list_operations = TRUE;
162 (*hdlp)->notif_module = notif_module;
165 return (result);
169 * bcm_notif_add_interest()
171 * Add an interested client
173 * Parameters
174 * hdl Opaque list handle.
175 * callback Client callback routine
176 * passthru Client pass-thru data
177 * Returns:
178 * BCME_OK Client interest added successfully
179 * BCME_NOMEM Add failed due to no memory.
182 int bcm_notif_add_interest(bcm_notif_h hdl,
183 bcm_notif_client_callback callback,
184 bcm_notif_client_data passthru)
186 int result = BCME_OK;
187 struct bcm_notif_client_request *new_node = NULL;
188 bcm_notif_module_t *notif_module = hdl->notif_module;
191 /* Ensure that list operations are not performed within client callbacks. */
192 if (!(hdl->allow_list_operations))
193 return (BCME_BUSY);
196 /* Allocate a new node for the new client interest request */
197 if ((new_node = bcm_mp_alloc(notif_module->client_mem_pool)) == NULL) {
198 result = BCME_NOMEM;
200 else {
201 memset(new_node, 0, sizeof(*new_node));
203 /* Initialize the new node with the client's information */
204 new_node->callback = callback;
205 new_node->passthru = passthru;
206 /* Insert it at the tail of the linked list */
207 if (hdl->tail == NULL) {
208 /* This is now the first node in the list. */
209 new_node->next = new_node;
210 hdl->tail = new_node;
212 else {
213 /* This is not the first node in the list. */
214 /* Insert as new tail in circular list. */
215 new_node->next = hdl->tail->next;
216 hdl->tail->next = new_node;
217 hdl->tail = new_node;
221 return (result);
225 * bcm_notif_remove_interest()
227 * Remove an interested client. The callback and passthru must be identical to the data
228 * supplied during registration.
230 * Parameters
231 * hdl Opaque list handle.
232 * callback Client callback routine
233 * passthru Client pass-thru data
234 * Returns:
235 * BCME_OK Client interest added successfully
236 * BCME_NOTFOUND Could not locate this specific client registration for removal.
239 int bcm_notif_remove_interest(bcm_notif_h hdl,
240 bcm_notif_client_callback callback,
241 bcm_notif_client_data passthru)
243 int result = BCME_NOTFOUND;
244 struct bcm_notif_client_request * nodep = hdl->tail;
245 bcm_notif_module_t *notif_module = hdl->notif_module;
247 /* Ensure that list operations are not performed within client callbacks. */
248 if (!(hdl->allow_list_operations))
249 return (BCME_BUSY);
252 if (nodep && nodep == nodep->next) {
254 * Special case: list with just one node.
255 * If we get a hit, the list becomes empty because we delete the last node.
257 if (nodep->callback == callback && nodep->passthru == passthru) {
258 bcm_mp_free(notif_module->client_mem_pool, nodep);
259 hdl->tail = NULL;
260 result = BCME_OK;
262 } else {
264 * List with 0 or 2+ elements.
266 struct bcm_notif_client_request * prevp;
267 while (nodep) {
268 prevp = nodep;
269 nodep = nodep->next;
270 if (nodep->callback == callback && nodep->passthru == passthru) {
272 * If we got a hit at the tail of the list, need to adjust
273 * the main list "tail" pointer.
275 if (hdl->tail == nodep)
276 hdl->tail = prevp;
277 result = BCME_OK;
278 prevp->next = nodep->next;
279 bcm_mp_free(notif_module->client_mem_pool, nodep);
280 /* Setting nodep to be 0 breaks us out of the loop. */
281 nodep = 0;
286 return (result);
290 * bcm_notif_signal()
292 * Notify all clients on an event list that the event has occured. Invoke their
293 * callbacks and provide both the server data and the client passthru data.
295 * Parameters
296 * hdl Opaque list handle.
297 * server_data Server data for the notification
298 * Returns:
299 * BCME_OK Client interest added successfully
300 * BCME_ERROR General error
302 int bcm_notif_signal(bcm_notif_h hdl, bcm_notif_server_data data)
304 int result = BCME_OK;
305 struct bcm_notif_client_request * nodep = hdl->tail;
307 /* Ensure that list operations are not performed within client callbacks. */
308 if (!(hdl->allow_list_operations))
309 return (BCME_BUSY);
312 if (nodep) {
313 struct bcm_notif_client_request * firstp;
314 nodep = nodep->next;
315 firstp = nodep;
317 /* Mark list to prevent against list operations within client callbacks. */
318 hdl->allow_list_operations = FALSE;
320 do {
321 /* Signal the current client */
322 nodep->callback(nodep->passthru, data);
323 /* Advance to next client registration */
324 nodep = nodep->next;
325 } while (nodep != firstp);
327 /* Done client callbacks - allow list operations again. */
328 hdl->allow_list_operations = TRUE;
331 return (result);
335 * bcm_notif_delete_list()
337 * Remove all the nodes and the list itself.
339 * Parameters
340 * hdlp Pointer to opaque list handle.
341 * Returns:
342 * BCME_OK Event list successfully deleted.
343 * BCME_ERROR General error
345 int BCMATTACHFN(bcm_notif_delete_list)(bcm_notif_h *hdl)
347 /* First free all the nodes. */
348 struct bcm_notif_client_request * nodep = (*hdl)->tail;
349 struct bcm_notif_client_request * prevp;
350 bcm_notif_module_t *notif_module = (*hdl)->notif_module;
352 /* Ensure that list operations are not performed within client callbacks. */
353 if (!((*hdl)->allow_list_operations))
354 return (BCME_BUSY);
357 while (nodep) {
358 prevp = nodep;
359 nodep = nodep->next;
361 if (prevp == nodep) {
362 /* Deleting the last node. Special case. */
363 bcm_mp_free(notif_module->client_mem_pool, nodep);
364 nodep = prevp = NULL;
365 } else {
366 prevp->next = nodep->next;
367 bcm_mp_free(notif_module->client_mem_pool, nodep);
368 nodep = prevp->next;
372 /* Free the list itself in addition to the nodes. */
373 memset(*hdl, 0, sizeof(**hdl));
374 bcm_mp_free(notif_module->server_mem_pool, *hdl);
375 *hdl = NULL;
377 return (BCME_OK);
381 * bcm_notif_dump_list()
383 * For debugging, display interest list
385 * Parameters
386 * hdl Opaque list handle.
387 * b Output buffer.
388 * Returns:
389 * BCME_OK Event list successfully dumped.
390 * BCME_ERROR General error.
392 int bcm_notif_dump_list(bcm_notif_h hdl, struct bcmstrbuf *b)
394 #if defined(BCMDBG)
395 struct bcm_notif_client_request * nodep;
397 if (hdl == NULL)
398 bcm_bprintf(b, "<uninit list>\n");
399 else {
400 nodep = hdl->tail;
402 bcm_bprintf(b, "List id=0x%p: ", hdl);
404 if (nodep == NULL) {
405 bcm_bprintf(b, "(empty)");
406 } else {
407 /* List is not empty. Display all data in correct sequence. */
408 struct bcm_notif_client_request * firstp = hdl->tail->next;
409 nodep = nodep->next;
410 do {
411 bcm_bprintf(b, " [0x%p,0x%p]", nodep->callback,
412 nodep->passthru);
413 nodep = nodep->next;
414 } while (nodep != firstp);
418 bcm_bprintf(b, "\n");
419 #endif
421 return (BCME_OK);