blob: 7317aac734121a7d02ee77a90de13e075edddc1e [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30#ifndef BCMOS_COMMON2_H_
31#define BCMOS_COMMON2_H_
32
33#ifndef BCMOS_SYSTEM_H_
34#error Please do not include bcmos_common2.h directly. Include bcmos_system.h
35#endif
36
37#include "bcmos_endian.h"
38
39/* \addtogroup system
40 * @{
41 */
42
43#define BCMOS_MAX_NAME_LENGTH 48
44
45/** \addtogroup system_task
46 * @{
47 */
48
49/** Task control block */
50struct bcmos_task
51{
52 /* OS independent fields */
53 bcmos_task_parm parm; /**< Task creation parameters */
54 bcmos_module *modules[BCMOS_MAX_MODULES_PER_TASK];
55 uint32_t active_modules; /**< Bitmask of modules for which events are pending */
56 bcmos_sem active_sem; /**< Semaphore used to wait for module activity */
57 bcmos_fastlock active_lock; /**< Lock protecting active_modules */
58 bcmos_module_id current_module; /**< Current module */
59 bcmos_bool destroy_request; /**< Task destroy request pending */
60 bcmos_bool destroyed; /**< Set by task handler before it terminates */
61 STAILQ_ENTRY(bcmos_task) list; /**< Next task pointer */
62 char name[BCMOS_MAX_NAME_LENGTH]; /**< Task name */
63 bcmos_sys_task sys_task; /**< OS-specific task extension */
64 uint32_t magic; /* magic number */
65#define BCMOS_TASK_MAGIC (('t' << 24) | ('a' << 16) | ('s' << 8) | 'k')
66#define BCMOS_TASK_MAGIC_DESTROYED (('t' << 24) | ('a' << 16) | ('s' << 8) | '~')
67};
68
69/** \addtogroup system_mem
70 * @{
71 */
72
73#ifndef BCMOS_CALLOC_INLINE
74
75/** Allocate memory from the main heap and clear it
76 * \ingroup system_heap
77 * \param[in] size
78 * \returns memory block pointer or NULL
79 */
80static inline void *bcmos_calloc(uint32_t size)
81{
82 void *ptr = bcmos_alloc(size);
83 if (ptr)
84 memset(ptr, 0, size);
85 return ptr;
86}
87#endif /* #ifndef BCMOS_CALLOC_INLINE */
88
89#ifndef BCMOS_DMA_ALLOC_FREE_INLINE
90
91/** Allocate DMA-able memory
92 * \param[in] device Device id
93 * \param[in] size Block size (bytes)
94 * \returns memory block pointer or NULL
95 */
96void *bcmos_dma_alloc(uint8_t device, uint32_t size);
97
98/** Release DMA-able memory
99 * \param[in] device Device id
100 * \param[in] ptr Block pointer
101 */
102void bcmos_dma_free(uint8_t device, void *ptr);
103
104#endif /* #ifndef BCMOS_DMA_ALLOC_FREE_INLINE */
105
106#ifndef BCMOS_VIRT_TO_PHYS_INLINE
107
108/** Convert virtual address to physical address
109 *
110 * \param[in] va Virtual address
111 * \returns - physical address va is mapped to
112 */
113unsigned long bcmos_virt_to_phys(void *va);
114
115#endif /* #ifndef BCMOS_VIRT_TO_PHYS_INLINE */
116
117/** @} */
118
119/** \addtogroup blk_pool
120 * @{
121 */
122
123/* Memory block header */
124typedef struct bcmos_memblk bcmos_memblk;
125
126/* Memory block list */
127typedef STAILQ_HEAD(, bcmos_memblk) bcmos_memblk_list;
128
129/* Block memory pool control block */
130struct bcmos_blk_pool
131{
132 bcmos_fastlock lock; /**< Pool protection lock */
133 bcmos_memblk_list free_list;/**< Free block list */
134 bcmos_blk_pool_parm parm; /**< Pool parameters */
135 bcmos_blk_pool_stat stat; /**< Pool statistics */
136 void *start; /**< Pool start pointer */
137 char name[BCMOS_MAX_NAME_LENGTH]; /**< Pool name */
138 uint32_t magic; /**< magic number */
139#define BCMOS_BLK_POOL_VALID (('b'<<24) | ('l' << 16) | ('p' << 8) | 'o')
140#define BCMOS_BLK_POOL_DELETED (('b'<<24) | ('l' << 16) | ('p' << 8) | '~')
141 STAILQ_ENTRY(bcmos_blk_pool) list; /* Pool list */
142};
143
144/* Total memory occupied by all block pools */
145extern uint32_t bcmos_total_blk_pool_size;
146
147/** @} blk_pool */
148
149/** \addtogroup system_msg
150 * @{
151 */
152
153/** Release message
154 * \param[in] msg Message handle
155 */
156static inline void bcmos_msg_free(bcmos_msg *msg)
157{
158 if (msg->release)
159 {
160 msg->release(msg);
161 }
162 else
163 {
164 bcmos_free(msg);
165 }
166}
167
168typedef STAILQ_HEAD(, bcmos_msg) bcmos_msg_list;
169
170/** Simple Message queue control block.
171 * Simple message queue doesn't support waiting on.
172 * It is used in module queue mechanisms.
173 */
174typedef struct bcmos_msg_queue_nw
175{
176 bcmos_msg_queue_parm parm; /**< Queue parameters */
177 bcmos_msg_queue_stat stat; /**< Queue statistics */
178 bcmos_fastlock lock; /**< Queue protection lock */
179 bcmos_msg_list msgl; /**< Message list */
180 bcmos_msg_list msgl_urg; /**< Urgent message list */
181 uint32_t flags; /**< Queue flags */
182} bcmos_msg_queue_nw;
183
184/** Message queue control block */
185struct bcmos_msg_queue
186{
187 bcmos_msg_queue_nw q; /**< Queue control block */
188 bcmos_sem m; /**< Mutex to suspend waiting task on */
189 bcmos_bool is_waiting; /**< TRUE if task is waiting on queue */
190 char name[BCMOS_MAX_NAME_LENGTH]; /**< Queue name */
191#ifdef BCMOS_MSG_QUEUE_REMOTE_SUPPORT
192 long ep; /**< Endpoint handle (e.g., socket) */
193 void *ep_extra_data; /**< Extra data - depending on ep type */
194 uint32_t ep_extra_data_size;/**< Extra data size */
195 uint8_t *send_buf; /**< Send buffer */
196 uint8_t *recv_buf; /**< Receive buffer */
197 bcmos_mutex send_lock; /**< Mutex that protects send_buf */
198#endif
199 uint32_t magic; /**< magic number */
200#define BCMOS_MSG_QUEUE_VALID (('m'<<24) | ('q' << 16) | ('u' << 8) | 'e')
201#define BCMOS_MSG_QUEUE_DELETED (('m'<<24) | ('q' << 16) | ('u' << 8) | '~')
202 STAILQ_ENTRY(bcmos_msg_queue) list; /* Queue list */
203};
204
205/** Message queue group control block */
206struct bcmos_msg_qgroup
207{
208 bcmos_msg_qgroup_parm parm; /**< Queue group parameters */
209 bcmos_msg_list *msgl; /**< Array of parm.nqueues message lists */
210 bcmos_msg_queue_stat stat; /**< Queue group statistics */
211 bcmos_sem m; /**< Mutex to suspend waiting task on */
212 bcmos_fastlock lock; /**< Queue group protection lock */
213 uint32_t active_mask; /**< Bitmask of queues containing messages */
214 bcmos_bool is_waiting; /**< TRUE if task is waiting on queue group */
215 char name[BCMOS_MAX_NAME_LENGTH]; /**< Queue group name */
216 uint32_t magic; /**< magic number */
217#define BCMOS_MSG_QGROUP_VALID (('m'<<24) | ('q' << 16) | ('g' << 8) | 'r')
218#define BCMOS_MSG_QGROUP_DELETED (('m'<<24) | ('q' << 16) | ('g' << 8) | '~')
219 STAILQ_ENTRY(bcmos_msg_qgroup) list; /* Queue group list */
220};
221
222/** Message pool control block */
223struct bcmos_msg_pool
224{
225 bcmos_blk_pool blk_pool; /**< Underlying block memory pool */
226 bcmos_msg_pool_parm parm; /**< Pool parameters */
227};
228
229/* Total memory occupied by all message pools */
230extern uint32_t bcmos_total_msg_pool_size;
231
232/** @} system_msg */
233
234/** \addtogroup system_timer */
235
236/* Timer precision. Must be a multiple of 2.
237 * Timed expiration timestamp is rounded up to the nearest multiple of timer precision
238 */
239#define BCMOS_TIMER_PRECISION_US 32
240#if (BCMOS_TIMER_PRECISION_US & (BCMOS_TIMER_PRECISION_US - 1))
241 #error BCMOS_TIMER_PRECISION_US must be a multiple of 2
242#endif
243
244/* There are 2 timer implementations
245 * - DLIST-based - works well when most of active timers have the same duration
246 * - RB-tree based - more expensive in simple case, but scales better for large number of timers
247 * with arbitrary durations
248 */
249#define BCMOS_TIMER_RB_TREE
250
251/** Timer control block */
252struct bcmos_timer
253{
254 bcmos_msg msg; /**< Timer message */
255 bcmos_timer_parm parm; /**< Timer parameters */
256 F_bcmos_timer_handler handler; /**< Timer handler */
257 uint32_t period; /**< Timer period (us) if periodic */
258 uint32_t expire_at; /**< Timestamp when timer should expire */
259 uint32_t flags; /* Internal flags */
260#define BCMOS_TIMER_FLAG_RUNNING 0x00000001 /* Timer is running */
261#define BCMOS_TIMER_FLAG_EXPIRED 0x00000002 /* Timer has expired, but not yet handled */
262#define BCMOS_TIMER_FLAG_ACTIVE (BCMOS_TIMER_FLAG_RUNNING | BCMOS_TIMER_FLAG_EXPIRED)
263#define BCMOS_TIMER_FLAG_VALID 0x00000004
264 bcmos_msg_queue_nw *queue; /**< Queue expired timer is on */
265 bcmos_task *task; /**< Task that executes timer handler */
266#ifdef BCMOS_TIMER_RB_TREE
267 RB_ENTRY(bcmos_timer) entry; /**< Timer pool entry */
268#else
269 TAILQ_ENTRY(bcmos_timer) entry;
270#endif
271};
272
273/** Check if timer is running
274 * \param[in] timer Timer handle
275 * \returns TRUE if timer is running
276 */
277static inline bcmos_bool bcmos_timer_is_running(const bcmos_timer *timer)
278{
279 bcmos_bool running = ((timer->flags & BCMOS_TIMER_FLAG_RUNNING) != 0) ||
280 (timer->parm.periodic && ((timer->flags & BCMOS_TIMER_FLAG_EXPIRED) != 0));
281 return running;
282}
283
284static inline bcmos_timer *_bcmos_msg_to_timer(bcmos_msg *msg)
285{
286 BUG_ON(msg->type != BCMOS_MSG_ID_INTERNAL_TIMER);
287 return (bcmos_timer *)msg;
288}
289
290/** @} */
291
292/** \addtogroup system_module
293 * @{
294 */
295
296/** Module control block */
297struct bcmos_module
298{
299 bcmos_module_parm parm; /**< Module parameters */
300 bcmos_module_id id; /**< Module id */
301 int idx; /**< Module index in task control block */
302 bcmos_msg_queue_nw msgq; /**< Message queue */
303 bcmos_task *my_task; /**< Task the module is associated with */
304 void *context; /**< User-defined context */
305 char name[BCMOS_MAX_NAME_LENGTH]; /**< Module name */
306};
307
308/** @} system_module */
309
310/** \addtogroup system_event
311 * @{
312 */
313
314/** Event control block */
315struct bcmos_event
316{
317 bcmos_msg msg; /**< Message header. Used to deliver event to module's queue */
318 bcmos_event_id id; /**< Event set id */
319 bcmos_event_parm parm; /**< Event parameters */
320 bcmos_fastlock lock; /**< Protects event control block */
321 uint32_t active_bits; /**< Active event bits */
322
323 bcmos_sem m; /**< Mutex to suspend task on. Traditional mode only */
324 bcmos_bool is_waiting; /**< TRUE if task is waiting for event */
325 char name[BCMOS_MAX_NAME_LENGTH]; /**< Event name */
326};
327
328
329static inline bcmos_event *_bcmos_msg_to_event(bcmos_msg *msg)
330{
331 BUG_ON(msg->type != BCMOS_MSG_ID_INTERNAL_EVENT);
332 return (bcmos_event *)msg;
333}
334
335/*
336 * Low level services
337 */
338
339/** \addtogroup system_buf
340 * @{
341 */
342
343#ifndef BCMOS_BUF_OS_SPECIFIC
344#define BCMOS_BUF_DATA_INLINE
345#endif
346
347#ifdef BCMOS_BUF_INLINE
348#define BCMOS_BUF_ALLOC_FREE_INLINE
349#define BCMOS_BUF_DATA_INLINE
350#endif
351
352#ifndef BCMOS_BUF_DATA_GUARD
353#define BCMOS_BUF_DATA_GUARD 0
354#endif
355
356#ifndef BCMOS_BUF_DATA_ALIGNMENT
357#define BCMOS_BUF_DATA_ALIGNMENT 64
358#endif
359
360#ifndef BCMOS_BUF_ALLOC_FREE_INLINE
361
362/** Allocate transport buffer.
363 * The buffer can accommodate up to size bytes of data.
364 * In addition it reserves BCMTR_BUF_EXTRA_HEADROOM headroom bytes
365 * for extra headers.
366 *
367 * \param[in] size Data size
368 * \returns buffer pointer or NULL if no memory
369 */
370bcmos_buf *bcmos_buf_alloc(uint32_t size);
371
372 /** Release transport buffer allocated by bcmos_buf_alloc()
373 *
374 * \param[in] buf Buffer to be released
375 */
376void bcmos_buf_free(bcmos_buf *buf);
377
378#endif /* BCMOS_BUF_ALLOC_FREE_INLINE */
379
380#ifndef BCMOS_BUF_DATA_INLINE
381
382/** Get data length
383 *
384 * \param[in] buf Buffer
385 * \returns data length
386 */
387uint32_t bcmos_buf_length(bcmos_buf *buf);
388
389/** Set data length
390 *
391 * \param[in] buf Buffer
392 * \param[in] length Data length
393 * \returns 0=OK, or BCM_ERR_OVERFLOW if length exceeds size
394 */
395bcmos_errno bcmos_buf_length_set(bcmos_buf *buf, uint32_t length);
396
397/** Get buffer data pointer.
398 * \param[in] buf Buffer
399 * \returns data pointer
400 */
401uint8_t *bcmos_buf_data(bcmos_buf *buf);
402
403#endif /* BCMOS_BUF_DATA_INLINE */
404
405#ifndef BCMOS_BUF_OS_SPECIFIC
406
407#ifndef unlikely
408#define unlikely(x) (x)
409#endif
410
411/* Generic (not os-specific) sysb implementation */
412
413/*
414 * Network / transport buffer
415 */
416
417
418/* Memory block list */
419typedef STAILQ_HEAD(, bcmos_buf) bcmos_buf_list_head;
420
421typedef struct
422{
423 bcmos_buf_list_head head; /**< Buffer list head */
424} bcmos_buf_queue;
425
426/* System buffer. We probably can use mbuf as well. */
427struct bcmos_buf
428{
429 uint8_t *start;
430 uint8_t *data;
431 bcmos_blk_pool *pool;
432 uint32_t size;
433 uint32_t len;
434 STAILQ_ENTRY(bcmos_buf) list; /**< Next buffer pointer */
435 uint8_t channel;
436};
437
438
439#ifndef BCMTR_BUF_EXTRA_HEADROOM
440#define BCMTR_BUF_EXTRA_HEADROOM 0
441#endif
442
443
444/** Initialize buffer queue
445 * \param[in] q Buffer queue
446 */
447static inline void bcmos_buf_queue_init(bcmos_buf_queue *q)
448{
449 STAILQ_INIT(&q->head);
450}
451
452/* Check if buffer queue is empty
453 * \param[in] q Buffer queue
454 * \returns TRUE if the queue is empty
455 */
456static inline bcmos_bool bcmos_buf_queue_is_empty(bcmos_buf_queue *q)
457{
458 return (bcmos_bool)STAILQ_EMPTY(&q->head);
459}
460
461/** Enqueue buffer
462 *
463 * Must be called under lock, e.g., q->lock
464 *
465 * \param[in] q Buffer queue
466 * \param[in] buf Buffer
467 */
468static inline void bcmos_buf_queue_put(bcmos_buf_queue *q, bcmos_buf *buf)
469{
470 STAILQ_INSERT_TAIL(&q->head, buf, list);
471}
472
473/* Dequeue buffer
474 *
475 * Must be called under lock, e.g., q->lock
476 *
477 * Remove and return the 1st queued buffer.
478 * \param[in] q Buffer queue
479 * \returns the buffer pointer
480 */
481static inline bcmos_buf *bcmos_buf_queue_get(bcmos_buf_queue *q)
482{
483 bcmos_buf *buf;
484 buf = STAILQ_FIRST(&q->head);
485 if (buf)
486 STAILQ_REMOVE_HEAD(&q->head, list);
487 return buf;
488}
489
490/* Peek into queue and return the 1st buffer without dequeing it
491 *
492 * Must be called under lock, e.g., q->lock
493 * \param[in] q Buffer queue
494 * \returns the buffer pointer
495 */
496static inline bcmos_buf *bcmos_buf_queue_peek(bcmos_buf_queue *q)
497{
498 return STAILQ_FIRST(&q->head);
499}
500
501/* Initialize buffer */
502static inline bcmos_buf *bcmos_buf_init(bcmos_buf *buf, uint8_t *start,
503 uint8_t *data, uint32_t size, uint32_t len)
504{
505 BUG_ON((void *)(buf +1) != start);
506 buf->start = start;
507 buf->data = data;
508 buf->size = size;
509 buf->len = len;
510 buf->pool = NULL;
511 return buf;
512}
513
514/* Get data length */
515static inline uint32_t bcmos_buf_length(bcmos_buf *buf)
516{
517 return buf->len;
518}
519
520/* Set data length */
521static inline bcmos_errno bcmos_buf_length_set(bcmos_buf *buf, uint32_t length)
522{
523 if (unlikely(length > buf->size - (buf->data - buf->start)))
524 {
525 BCMOS_TRACE_ERR("!!!%s: length=%u size=%u data=%p start=%p data-start=%u\n",
526 __FUNCTION__, length, buf->size, buf->data, buf->start, (uint32_t)(buf->data - buf->start));
527 return BCM_ERR_OVERFLOW;
528 }
529 buf->len = length;
530 return BCM_ERR_OK;
531}
532
533/* Get buffer data pointer. */
534static inline uint8_t *bcmos_buf_data(bcmos_buf *buf)
535{
536 return buf->data;
537}
538
539/* Get buffer channel. */
540static inline uint8_t bcmos_buf_channel(bcmos_buf *buf)
541{
542 return buf->channel;
543}
544
545/* Set buffer channel. */
546static inline void bcmos_buf_channel_set(bcmos_buf *buf, uint8_t channel)
547{
548 buf->channel = channel;
549}
550
551#endif /* #ifndef BCMOS_BUF_OS_SPECIFIC */
552
553/** @} bcmos_buf */
554
555/** \addtogroup system_cache
556 * @{
557 */
558
559#ifndef BCMOS_CACHE_INLINE
560
561/** Invalidate address area in data cache. Dirty cache lines content is discarded.
562 * \param[in] start Address area start
563 * \param[in] size Address area size
564 */
565void bcmos_dcache_inv(void *start, uint32_t size);
566
567/** Flush address area in data cache. Dirty cache lines are committed to memory.
568 * \param[in] start Address area start
569 * \param[in] size Address area size
570 */
571void bcmos_dcache_flush(void *start, uint32_t size);
572
573#endif /* BCMOS_CACHE_INLINE */
574
575/** Prepare for DMA write.
576 * On h/w platforms that support DMA-cache coherency, this function should
577 * perform write barrier.
578 * On platforms that don't support DMA cache coherency this function should
579 * flush the relevant dcache area
580 *
581 * \param[in] start DMA buffer start address
582 * \param[in] size DMA buffer size
583 */
584static inline void bcmos_prepare_for_dma_write(void *start, uint32_t size)
585{
586#ifdef BCMOS_DMA_CACHE_COHERENCY
587 bcmos_barrier();
588#else
589 bcmos_dcache_flush(start, size);
590#endif
591}
592
593/** Prepare for DMA read.
594 * On h/w platforms that support DMA-cache coherency, this function should
595 * perform write barrier.
596 * On platforms that don't support DMA cache coherency this function should
597 * invalidate the relevant dcache area
598 *
599 * \param[in] start DMA buffer start address
600 * \param[in] size DMA buffer size
601 */
602static inline void bcmos_prepare_for_dma_read(void *start, uint32_t size)
603{
604#ifdef BCMOS_DMA_CACHE_COHERENCY
605 bcmos_barrier();
606#else
607 bcmos_dcache_inv(start, size);
608#endif
609}
610
611/** @} system_cache */
612
613/** \addtogroup system_interrupt
614 * @{
615 */
616
617#ifdef BCMOS_INTERRUPT_INLINE
618#define BCMOS_INTERRUPT_CONNECT_DISCONNECT_INLINE
619#define BCMOS_INTERRUPT_ENABLE_DISABLE_INLINE
620#endif
621
622#ifndef BCMOS_INTERRUPT_CONNECT_DISCONNECT_INLINE
623/** Connect system interrupt
624 * \param[in] irq IRQ number
625 * \param[in] cpu CPU number (for SMP)
626 * \param[in] flags IRQ flags
627 * \param[in] isr ISR
628 * \param[in] name device name
629 * \param[in] priv Private cookie
630 * \returns 0=OK, <0- error
631 */
632int bcmos_int_connect(int irq, int cpu, int flags,
633 int (*isr)(int irq, void *priv), const char *name, void *priv);
634
635/** Disconnect system interrupt
636 * \param[in] irq IRQ number
637 * \param[in] priv Private cookie passed in bcmos_int_connect()
638 * \returns 0=OK, <0- error
639 */
640void bcmos_int_disconnect(int irq, void *priv);
641#endif
642
643#ifndef BCMOS_INTERRUPT_ENABLE_DISABLE_INLINE
644/** Unmask IRQ
645 * \param[in] irq IRQ
646 */
647void bcmos_int_enable(int irq);
648
649/** Mask IRQ
650 * \param[in] irq IRQ
651 */
652void bcmos_int_disable(int irq);
653#endif
654
655/** @} */
656
657/* Get char, put char support */
658#ifndef BCMOS_GETCHAR_INLINE
659static inline int bcmos_getchar(void)
660{
661 return getchar();
662}
663#endif
664
665#ifndef BCMOS_PUTCHAR_INLINE
666void bcmos_putchar(int c);
667#endif
668
669#ifndef BCMOS_SEM_POST_IS_ALLOWED_INLINE
670static inline bcmos_bool bcmos_sem_post_is_allowed(void)
671{
672 return BCMOS_TRUE;
673}
674#endif
675
676#endif /* BCMOS_COMMON2_H_ */