blob: 50a2ca7dde2e9e16da67dcae90046e574ced6796 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
Hank Janssen3e7ee492009-07-13 16:02:34 -070024#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/types.h>
27#include <linux/mm.h>
28#include <linux/highmem.h>
29#include <linux/vmalloc.h>
Hank Janssen3e7ee492009-07-13 16:02:34 -070030#include <linux/ioport.h>
31#include <linux/irq.h>
32#include <linux/interrupt.h>
33#include <linux/wait.h>
34#include <linux/spinlock.h>
35#include <linux/workqueue.h>
36#include <linux/kernel.h>
37#include <linux/timer.h>
38#include <linux/jiffies.h>
39#include <linux/delay.h>
40#include <linux/time.h>
41
42#include <asm/io.h>
43#include <asm/bitops.h>
44#include <asm/kmap_types.h>
45#include <asm/atomic.h>
46
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070047#include "include/osd.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070048
Bill Pemberton454f18a2009-07-27 16:47:24 -040049
50/* Data types */
51
Hank Janssen3e7ee492009-07-13 16:02:34 -070052typedef struct _TIMER {
53 struct timer_list timer;
54 PFN_TIMER_CALLBACK callback;
55 void* context;
56}TIMER;
57
Hank Janssen3e7ee492009-07-13 16:02:34 -070058typedef struct _WORKITEM {
59 struct work_struct work;
60 PFN_WORKITEM_CALLBACK callback;
61 void* context;
62} WORKITEM;
63
64
Hank Janssen3e7ee492009-07-13 16:02:34 -070065void BitSet(unsigned int* addr, int bit)
66{
67 set_bit(bit, (unsigned long*)addr);
68}
69
70int BitTest(unsigned int* addr, int bit)
71{
72 return test_bit(bit, (unsigned long*)addr);
73}
74
75void BitClear(unsigned int* addr, int bit)
76{
77 clear_bit(bit, (unsigned long*)addr);
78}
79
80int BitTestAndClear(unsigned int* addr, int bit)
81{
82 return test_and_clear_bit(bit, (unsigned long*)addr);
83}
84
85int BitTestAndSet(unsigned int* addr, int bit)
86{
87 return test_and_set_bit(bit, (unsigned long*)addr);
88}
89
90
91int InterlockedIncrement(int *val)
92{
Hank Janssen3e7ee492009-07-13 16:02:34 -070093 return atomic_inc_return((atomic_t*)val);
Hank Janssen3e7ee492009-07-13 16:02:34 -070094}
95
96int InterlockedDecrement(int *val)
97{
Hank Janssen3e7ee492009-07-13 16:02:34 -070098 return atomic_dec_return((atomic_t*)val);
Hank Janssen3e7ee492009-07-13 16:02:34 -070099}
100
101#ifndef atomic_cmpxchg
102#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
103#endif
104int InterlockedCompareExchange(int *val, int new, int curr)
105{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400106 /* return ((int)cmpxchg(((atomic_t*)val), curr, new)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700107 return atomic_cmpxchg((atomic_t*)val, curr, new);
108
109}
110
Hank Janssen3e7ee492009-07-13 16:02:34 -0700111void* VirtualAllocExec(unsigned int size)
112{
113#ifdef __x86_64__
114 return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
115#else
116 return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
117#endif
118}
119
120void VirtualFree(void* VirtAddr)
121{
122 return vfree(VirtAddr);
123}
124
125void* PageAlloc(unsigned int count)
126{
127 void *p;
128 p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
129 if (p) memset(p, 0, count * PAGE_SIZE);
130 return p;
131
Bill Pemberton454f18a2009-07-27 16:47:24 -0400132 /* struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); */
133 /* void *p; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700134
Bill Pemberton454f18a2009-07-27 16:47:24 -0400135 /* BUGBUG: We need to use kmap in case we are in HIMEM region */
136 /* p = page_address(page); */
137 /* if (p) memset(p, 0, PAGE_SIZE); */
138 /* return p; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700139}
140
141void PageFree(void* page, unsigned int count)
142{
143 free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
144 /*struct page* p = virt_to_page(page);
145 __free_page(p);*/
146}
147
148
149void* PageMapVirtualAddress(unsigned long Pfn)
150{
151 return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
152}
153
154void PageUnmapVirtualAddress(void* VirtAddr)
155{
156 kunmap_atomic(VirtAddr, KM_IRQ0);
157}
158
Hank Janssen3e7ee492009-07-13 16:02:34 -0700159void *MemMapIO(unsigned long phys, unsigned long size)
160{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400161 return (void*)GetVirtualAddress(phys); /* return ioremap_nocache(phys, size); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700162}
163
164void MemUnmapIO(void *virt)
165{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400166 /* iounmap(virt); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700167}
168
Hank Janssen3e7ee492009-07-13 16:02:34 -0700169void TimerCallback(unsigned long data)
170{
171 TIMER* t = (TIMER*)data;
172
173 t->callback(t->context);
174}
175
176HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
177{
178 TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL);
179 if (!t)
180 {
181 return NULL;
182 }
183
184 t->callback = pfnTimerCB;
185 t->context = context;
186
187 init_timer(&t->timer);
188 t->timer.data = (unsigned long)t;
189 t->timer.function = TimerCallback;
190
191 return t;
192}
193
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700194void TimerStart(HANDLE hTimer, u32 expirationInUs)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700195{
196 TIMER* t = (TIMER* )hTimer;
197
198 t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
199 add_timer(&t->timer);
200}
201
202int TimerStop(HANDLE hTimer)
203{
204 TIMER* t = (TIMER* )hTimer;
205
206 return del_timer(&t->timer);
207}
208
209void TimerClose(HANDLE hTimer)
210{
211 TIMER* t = (TIMER* )hTimer;
212
213 del_timer(&t->timer);
214 kfree(t);
215}
216
Bill Pembertonaedb4442009-07-28 13:46:24 -0400217struct osd_waitevent *WaitEventCreate(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700218{
Bill Pembertonaedb4442009-07-28 13:46:24 -0400219 struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700220 if (!wait)
221 {
222 return NULL;
223 }
224
225 wait->condition = 0;
226 init_waitqueue_head(&wait->event);
227 return wait;
228}
229
Bill Pembertonaedb4442009-07-28 13:46:24 -0400230void WaitEventClose(struct osd_waitevent *waitEvent)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700231{
Hank Janssen3e7ee492009-07-13 16:02:34 -0700232 kfree(waitEvent);
233}
234
Bill Pembertonaedb4442009-07-28 13:46:24 -0400235void WaitEventSet(struct osd_waitevent *waitEvent)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700236{
Hank Janssen3e7ee492009-07-13 16:02:34 -0700237 waitEvent->condition = 1;
238 wake_up_interruptible(&waitEvent->event);
239}
240
Bill Pembertonaedb4442009-07-28 13:46:24 -0400241int WaitEventWait(struct osd_waitevent *waitEvent)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700242{
243 int ret=0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700244
Bill Pembertonaedb4442009-07-28 13:46:24 -0400245 ret = wait_event_interruptible(waitEvent->event,
246 waitEvent->condition);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700247 waitEvent->condition = 0;
248 return ret;
249}
250
Bill Pembertonaedb4442009-07-28 13:46:24 -0400251int WaitEventWaitEx(struct osd_waitevent *waitEvent, u32 TimeoutInMs)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700252{
253 int ret=0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700254
Bill Pembertonaedb4442009-07-28 13:46:24 -0400255 ret = wait_event_interruptible_timeout(waitEvent->event,
256 waitEvent->condition,
257 msecs_to_jiffies(TimeoutInMs));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700258 waitEvent->condition = 0;
259 return ret;
260}
261
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700262void* Physical2LogicalAddr(unsigned long PhysAddr)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700263{
264 void* logicalAddr = phys_to_virt(PhysAddr);
265 BUG_ON(!virt_addr_valid(logicalAddr));
266 return logicalAddr;
267}
268
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700269unsigned long Logical2PhysicalAddr(void * LogicalAddr)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270{
271 BUG_ON(!virt_addr_valid(LogicalAddr));
272 return virt_to_phys(LogicalAddr);
273}
274
275
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700276unsigned long Virtual2Physical(void * VirtAddr)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700277{
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700278 unsigned long pfn = vmalloc_to_pfn(VirtAddr);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700279
280 return pfn << PAGE_SHIFT;
281}
282
Hank Janssen3e7ee492009-07-13 16:02:34 -0700283void WorkItemCallback(struct work_struct *work)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700284{
285 WORKITEM* w = (WORKITEM*)work;
286
287 w->callback(w->context);
288
289 kfree(w);
290}
291
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400292struct workqueue_struct *WorkQueueCreate(char *name)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700293{
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400294 struct workqueue_struct *wq;
295 wq = create_workqueue(name);
296 if (unlikely(!wq))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700297 return NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700298 return wq;
299}
300
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400301void WorkQueueClose(struct workqueue_struct *hWorkQueue)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700302{
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400303 destroy_workqueue(hWorkQueue);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700304 return;
305}
306
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400307int WorkQueueQueueWorkItem(struct workqueue_struct *hWorkQueue,
308 PFN_WORKITEM_CALLBACK workItem,
309 void* context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700310{
Hank Janssen3e7ee492009-07-13 16:02:34 -0700311 WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
312 if (!w)
313 {
314 return -1;
315 }
316
317 w->callback = workItem,
318 w->context = context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700319 INIT_WORK(&w->work, WorkItemCallback);
Bill Pembertondf8d9b12009-07-27 16:47:45 -0400320 return queue_work(hWorkQueue, &w->work);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700321}
322
323void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context)
324{
325 WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
326 if (!w)
327 {
328 return;
329 }
330
331 w->callback = workItem,
332 w->context = context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700333 INIT_WORK(&w->work, WorkItemCallback);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700334 schedule_work(&w->work);
335}