]> Pileus Git - ~andy/linux/blob - drivers/staging/hv/osd.c
Staging: hv: remove WaitEventClose()
[~andy/linux] / drivers / staging / hv / osd.c
1 /*
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
24 #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>
30 #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
47 #include "include/osd.h"
48
49
50 /* Data types */
51
52
53 struct osd_callback_struct {
54         struct work_struct work;
55         void (*callback)(void *);
56         void *data;
57 };
58
59
60 void BitSet(unsigned int* addr, int bit)
61 {
62         set_bit(bit, (unsigned long*)addr);
63 }
64
65 int BitTest(unsigned int* addr, int bit)
66 {
67         return test_bit(bit, (unsigned long*)addr);
68 }
69
70 void BitClear(unsigned int* addr, int bit)
71 {
72         clear_bit(bit, (unsigned long*)addr);
73 }
74
75 int BitTestAndClear(unsigned int* addr, int bit)
76 {
77         return test_and_clear_bit(bit, (unsigned long*)addr);
78 }
79
80 int BitTestAndSet(unsigned int* addr, int bit)
81 {
82         return test_and_set_bit(bit, (unsigned long*)addr);
83 }
84
85
86 int InterlockedIncrement(int *val)
87 {
88         return atomic_inc_return((atomic_t*)val);
89 }
90
91 int InterlockedDecrement(int *val)
92 {
93         return atomic_dec_return((atomic_t*)val);
94 }
95
96 #ifndef atomic_cmpxchg
97 #define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
98 #endif
99 int InterlockedCompareExchange(int *val, int new, int curr)
100 {
101         /* return ((int)cmpxchg(((atomic_t*)val), curr, new)); */
102         return atomic_cmpxchg((atomic_t*)val, curr, new);
103
104 }
105
106 void* VirtualAllocExec(unsigned int size)
107 {
108 #ifdef __x86_64__
109         return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
110 #else
111         return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
112 #endif
113 }
114
115 void VirtualFree(void* VirtAddr)
116 {
117         return vfree(VirtAddr);
118 }
119
120 void* PageAlloc(unsigned int count)
121 {
122         void *p;
123         p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
124         if (p) memset(p, 0, count * PAGE_SIZE);
125         return p;
126
127         /* struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); */
128         /* void *p; */
129
130         /* BUGBUG: We need to use kmap in case we are in HIMEM region */
131         /* p = page_address(page); */
132         /* if (p) memset(p, 0, PAGE_SIZE); */
133         /* return p; */
134 }
135
136 void PageFree(void* page, unsigned int count)
137 {
138         free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
139         /*struct page* p = virt_to_page(page);
140         __free_page(p);*/
141 }
142
143
144 void* PageMapVirtualAddress(unsigned long Pfn)
145 {
146         return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
147 }
148
149 void PageUnmapVirtualAddress(void* VirtAddr)
150 {
151         kunmap_atomic(VirtAddr, KM_IRQ0);
152 }
153
154 void *MemMapIO(unsigned long phys, unsigned long size)
155 {
156         return (void*)GetVirtualAddress(phys); /* return ioremap_nocache(phys, size); */
157 }
158
159 void MemUnmapIO(void *virt)
160 {
161         /* iounmap(virt); */
162 }
163
164 static void TimerCallback(unsigned long data)
165 {
166         struct osd_timer *t = (struct osd_timer *) data;
167
168         t->callback(t->context);
169 }
170
171 struct osd_timer *TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
172 {
173         struct osd_timer *t = kmalloc(sizeof(struct osd_timer), GFP_KERNEL);
174         if (!t)
175         {
176                 return NULL;
177         }
178
179         t->callback = pfnTimerCB;
180         t->context = context;
181
182         init_timer(&t->timer);
183         t->timer.data = (unsigned long)t;
184         t->timer.function = TimerCallback;
185
186         return t;
187 }
188
189 void TimerStart(struct osd_timer *t, u32 expirationInUs)
190 {
191         t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
192         add_timer(&t->timer);
193 }
194
195 int TimerStop(struct osd_timer *t)
196 {
197         return del_timer(&t->timer);
198 }
199
200 void TimerClose(struct osd_timer *t)
201 {
202         del_timer(&t->timer);
203         kfree(t);
204 }
205
206 struct osd_waitevent *WaitEventCreate(void)
207 {
208         struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent), GFP_KERNEL);
209         if (!wait)
210         {
211                 return NULL;
212         }
213
214         wait->condition = 0;
215         init_waitqueue_head(&wait->event);
216         return wait;
217 }
218
219 void WaitEventSet(struct osd_waitevent *waitEvent)
220 {
221         waitEvent->condition = 1;
222         wake_up_interruptible(&waitEvent->event);
223 }
224
225 int WaitEventWait(struct osd_waitevent *waitEvent)
226 {
227         int ret=0;
228
229         ret = wait_event_interruptible(waitEvent->event,
230                                        waitEvent->condition);
231         waitEvent->condition = 0;
232         return ret;
233 }
234
235 int WaitEventWaitEx(struct osd_waitevent *waitEvent, u32 TimeoutInMs)
236 {
237         int ret=0;
238
239         ret = wait_event_interruptible_timeout(waitEvent->event,
240                                                waitEvent->condition,
241                                                msecs_to_jiffies(TimeoutInMs));
242         waitEvent->condition = 0;
243         return ret;
244 }
245
246 void* Physical2LogicalAddr(unsigned long PhysAddr)
247 {
248         void* logicalAddr = phys_to_virt(PhysAddr);
249         BUG_ON(!virt_addr_valid(logicalAddr));
250         return logicalAddr;
251 }
252
253 unsigned long Logical2PhysicalAddr(void * LogicalAddr)
254 {
255         BUG_ON(!virt_addr_valid(LogicalAddr));
256         return virt_to_phys(LogicalAddr);
257 }
258
259
260 unsigned long Virtual2Physical(void * VirtAddr)
261 {
262         unsigned long pfn = vmalloc_to_pfn(VirtAddr);
263
264         return pfn << PAGE_SHIFT;
265 }
266
267 static void osd_callback_work(struct work_struct *work)
268 {
269         struct osd_callback_struct *cb = container_of(work,
270                                                       struct osd_callback_struct,
271                                                       work);
272         (cb->callback)(cb->data);
273
274         kfree(cb);
275 }
276
277 int osd_schedule_callback(struct workqueue_struct *wq,
278                           void (*func)(void *),
279                           void *data)
280 {
281         struct osd_callback_struct *cb;
282
283         cb = kmalloc(sizeof(*cb), GFP_KERNEL);
284         if (!cb)
285         {
286                 printk(KERN_ERR "unable to allocate memory in osd_schedule_callback");
287                 return -1;
288         }
289
290         cb->callback = func;
291         cb->data = data;
292         INIT_WORK(&cb->work, osd_callback_work);
293         return queue_work(wq, &cb->work);
294 }
295