1 /****************************************************************************
2 * Copyright 2002-2005: Level 5 Networks Inc.
3 * Copyright 2005-2008: Solarflare Communications Inc,
4 * 9501 Jeronimo Road, Suite 250,
5 * Irvine, CA 92618, USA
7 * Maintained by Solarflare Communications
8 * <linux-xen-drivers@solarflare.com>
9 * <onload-dev@solarflare.com>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 as published
13 * by the Free Software Foundation, incorporated herein by reference.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 ****************************************************************************
27 /*! \cidoxg_include_ci_tools_platform */
29 #ifndef __CI_TOOLS_LINUX_KERNEL_H__
30 #define __CI_TOOLS_LINUX_KERNEL_H__
32 /**********************************************************************
33 * Need to know the kernel version.
36 #ifndef LINUX_VERSION_CODE
37 # include <linux/version.h>
39 /* 2.6.18 onwards defines UTS_RELEASE in a separate header */
40 # include <linux/utsrelease.h>
44 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || \
45 LINUX_VERSION_CODE >= KERNEL_VERSION(2,7,0)
46 # error "Linux 2.6 required"
50 #include <linux/slab.h> /* kmalloc / kfree */
51 #include <linux/vmalloc.h> /* vmalloc / vfree */
52 #include <linux/interrupt.h>/* in_interrupt() */
54 #include <linux/in6.h>
55 #include <linux/spinlock.h>
56 #include <linux/highmem.h>
57 #include <linux/smp_lock.h>
58 #include <linux/ctype.h>
59 #include <linux/uio.h>
60 #include <asm/current.h>
61 #include <asm/errno.h>
62 #include <asm/kmap_types.h>
63 #include <asm/semaphore.h>
65 #include <ci/tools/config.h>
67 #define ci_in_irq in_irq
68 #define ci_in_interrupt in_interrupt
69 #define ci_in_atomic in_atomic
72 /**********************************************************************
80 ci_inline void* __ci_alloc(size_t n)
81 { return kmalloc(n, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)); }
83 ci_inline void* __ci_atomic_alloc(size_t n)
84 { return kmalloc(n, GFP_ATOMIC ); }
86 ci_inline void __ci_free(void* p) { return kfree(p); }
87 ci_inline void* __ci_vmalloc(size_t n) { return vmalloc(n); }
88 ci_inline void __ci_vfree(void* p) { return vfree(p); }
91 #if CI_MEMLEAK_DEBUG_ALLOC_TABLE
92 #define ci_alloc(s) ci_alloc_memleak_debug (s, __FILE__, __LINE__)
93 #define ci_atomic_alloc(s) ci_atomic_alloc_memleak_debug(s, __FILE__, __LINE__)
94 #define ci_free ci_free_memleak_debug
95 #define ci_vmalloc(s) ci_vmalloc_memleak_debug (s, __FILE__,__LINE__)
96 #define ci_vfree ci_vfree_memleak_debug
97 #define ci_alloc_fn ci_alloc_fn_memleak_debug
98 #define ci_vmalloc_fn ci_vmalloc_fn_memleak_debug
99 #else /* !CI_MEMLEAK_DEBUG_ALLOC_TABLE */
100 #define ci_alloc_fn __ci_alloc
101 #define ci_vmalloc_fn __ci_vmalloc
105 #define ci_atomic_alloc __ci_atomic_alloc
106 #define ci_alloc __ci_alloc
107 #define ci_free __ci_free
108 #define ci_vmalloc __ci_vmalloc
109 #define ci_vmalloc_fn __ci_vmalloc
110 #define ci_vfree __ci_vfree
113 #define ci_sprintf sprintf
114 #define ci_vsprintf vsprintf
115 #define ci_snprintf snprintf
116 #define ci_vsnprintf vsnprintf
117 #define ci_sscanf sscanf
120 #define CI_LOG_FN_DEFAULT ci_log_syslog
123 /*--------------------------------------------------------------------
125 * irqs_disabled - needed for kmap helpers on some kernels
127 *--------------------------------------------------------------------*/
129 # define ci_irqs_disabled irqs_disabled
131 # if defined(__i386__) | defined(__x86_64__)
132 # define ci_irqs_disabled(x) \
134 unsigned long flags; \
135 local_save_flags(flags); \
139 # error "Need to implement irqs_disabled() for your architecture"
144 /**********************************************************************
147 * Use ci_k(un)map for code paths which are not in an atomic context.
148 * For atomic code you need to use ci_k(un)map_in_atomic. This will grab
149 * one of the per-CPU kmap slots.
151 * NB in_interrupt != in_irq. If you don't know the difference then
152 * don't use kmap_in_atomic
154 * 2.4 allocates kmap slots by function. We are going to re-use the
155 * skb module's slot - we also use the same interlock
157 * 2.6 allocates kmap slots by type as well as by function. We are
158 * going to use the currently (2.6.10) unsused SOFTIRQ slot
162 ci_inline void* ci_kmap(struct page *page) {
163 CI_DEBUG(if( ci_in_atomic() | ci_in_interrupt() | ci_in_irq() ) BUG());
167 ci_inline void ci_kunmap(struct page *page) {
171 #define CI_KM_SLOT KM_SOFTIRQ0
174 typedef struct semaphore ci_semaphore_t;
177 ci_sem_init (ci_semaphore_t *sem, int val) {
178 sema_init (sem, val);
182 ci_sem_down (ci_semaphore_t *sem) {
187 ci_sem_trydown (ci_semaphore_t *sem) {
188 return down_trylock (sem);
192 ci_sem_up (ci_semaphore_t *sem) {
197 ci_sem_get_count(ci_semaphore_t *sem) {
198 return sem->count.counter;
201 ci_inline void* ci_kmap_in_atomic(struct page *page)
203 CI_DEBUG(if( ci_in_irq() ) BUG());
205 /* iSCSI can call without in_interrupt() but with irqs_disabled()
206 and in a context that can't sleep, so we need to check that
208 if(ci_in_interrupt() || ci_irqs_disabled())
209 return kmap_atomic(page, CI_KM_SLOT);
214 ci_inline void ci_kunmap_in_atomic(struct page *page, void* kaddr)
216 CI_DEBUG(if( ci_in_irq() ) BUG());
218 /* iSCSI can call without in_interrupt() but with irqs_disabled()
219 and in a context that can't sleep, so we need to check that
221 if(ci_in_interrupt() || ci_irqs_disabled())
222 kunmap_atomic(kaddr, CI_KM_SLOT);
227 /**********************************************************************
228 * spinlock implementation: used by <ci/tools/spinlock.h>
231 #define CI_HAVE_SPINLOCKS
233 typedef ci_uintptr_t ci_lock_holder_t;
234 #define ci_lock_thisthread (ci_lock_holder_t)current
235 #define ci_lock_no_holder (ci_lock_holder_t)NULL
237 typedef spinlock_t ci_lock_i;
238 typedef spinlock_t ci_irqlock_i;
239 typedef unsigned long ci_irqlock_state_t;
241 #define IRQLOCK_CYCLES 500000
243 #define ci_lock_ctor_i(l) spin_lock_init(l)
244 #define ci_lock_dtor_i(l) do{}while(0)
245 #define ci_lock_lock_i(l) spin_lock(l)
246 #define ci_lock_trylock_i(l) spin_trylock(l)
247 #define ci_lock_unlock_i(l) spin_unlock(l)
249 #define ci_irqlock_ctor_i(l) spin_lock_init(l)
250 #define ci_irqlock_dtor_i(l) do{}while(0)
251 #define ci_irqlock_lock_i(l,s) spin_lock_irqsave(l,*(s))
252 #define ci_irqlock_unlock_i(l,s) spin_unlock_irqrestore(l, *(s))
255 /**********************************************************************
261 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
262 typedef volatile void __iomem* ioaddr_t;
264 typedef unsigned long ioaddr_t;
269 /**********************************************************************
270 * thread implementation -- kernel dependancies probably should be
271 * moved to driver/linux_kernel.h
274 #define ci_linux_daemonize(name) daemonize(name)
276 #include <linux/workqueue.h>
280 void* (*fn)(void* arg);
284 struct completion exit_event;
285 struct work_struct keventd_witem;
286 } ci_kernel_thread_t;
289 typedef ci_kernel_thread_t* cithread_t;
292 extern int cithread_create(cithread_t* tid, void* (*fn)(void*), void* arg,
294 extern int cithread_detach(cithread_t kt);
295 extern int cithread_join(cithread_t kt);
298 /* Kernel sysctl variables. */
299 extern int sysctl_tcp_wmem[3];
300 extern int sysctl_tcp_rmem[3];
301 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
302 #define LINUX_HAS_SYSCTL_MEM_MAX
303 extern ci_uint32 sysctl_wmem_max;
304 extern ci_uint32 sysctl_rmem_max;
308 /*--------------------------------------------------------------------
310 * ci_bigbuf_t: An abstraction of a large buffer. Needed because in the
311 * Linux kernel, large buffers need to be allocated with vmalloc(), whereas
312 * smaller buffers should use kmalloc(). This abstraction chooses the
313 * appropriate mechansim.
315 *--------------------------------------------------------------------*/
323 ci_inline int ci_bigbuf_alloc(ci_bigbuf_t* bb, size_t bytes) {
324 if( bytes >= CI_PAGE_SIZE && ! ci_in_atomic() ) {
326 if( (bb->p = vmalloc(bytes)) ) return 0;
329 bb->p = kmalloc(bytes, ci_in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
330 return bb->p ? 0 : -ENOMEM;
333 ci_inline void ci_bigbuf_free(ci_bigbuf_t* bb) {
334 if( bb->is_vmalloc ) vfree(bb->p);
338 ci_inline char* ci_bigbuf_ptr(ci_bigbuf_t* bb)
341 /**********************************************************************
342 * struct iovec abstraction (for Windows port)
345 typedef struct iovec ci_iovec;
347 /* Accessors for buffer/length */
348 #define CI_IOVEC_BASE(i) ((i)->iov_base)
349 #define CI_IOVEC_LEN(i) ((i)->iov_len)
351 /**********************************************************************
356 ci_send_sig(int signum)
358 send_sig(signum, current, 0);
361 #endif /* __CI_TOOLS_LINUX_KERNEL_H__ */