| /* |
| * arch/arm/common/fiq_debugger_ringbuf.c |
| * |
| * simple lockless ringbuffer |
| * |
| * Copyright (C) 2010 Google, Inc. |
| * |
| * This software is licensed under the terms of the GNU General Public |
| * License version 2, as published by the Free Software Foundation, and |
| * may be copied, distributed, and modified under those terms. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/slab.h> |
| |
| struct fiq_debugger_ringbuf { |
| int len; |
| int head; |
| int tail; |
| u8 buf[]; |
| }; |
| |
| |
| static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len) |
| { |
| struct fiq_debugger_ringbuf *rbuf; |
| |
| rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL); |
| if (rbuf == NULL) |
| return NULL; |
| |
| rbuf->len = len; |
| rbuf->head = 0; |
| rbuf->tail = 0; |
| smp_mb(); |
| |
| return rbuf; |
| } |
| |
| static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf) |
| { |
| kfree(rbuf); |
| } |
| |
| static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf) |
| { |
| int level = rbuf->head - rbuf->tail; |
| |
| if (level < 0) |
| level = rbuf->len + level; |
| |
| return level; |
| } |
| |
| static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf) |
| { |
| return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1; |
| } |
| |
| static inline u8 |
| fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i) |
| { |
| return rbuf->buf[(rbuf->tail + i) % rbuf->len]; |
| } |
| |
| static inline int |
| fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count) |
| { |
| count = min(count, fiq_debugger_ringbuf_level(rbuf)); |
| |
| rbuf->tail = (rbuf->tail + count) % rbuf->len; |
| smp_mb(); |
| |
| return count; |
| } |
| |
| static inline int |
| fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum) |
| { |
| if (fiq_debugger_ringbuf_room(rbuf) == 0) |
| return 0; |
| |
| rbuf->buf[rbuf->head] = datum; |
| smp_mb(); |
| rbuf->head = (rbuf->head + 1) % rbuf->len; |
| smp_mb(); |
| |
| return 1; |
| } |