No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / ndis / subr_hal.c
blobe1017e610094e96db969e9a551776ad05a4bf567
1 /*-
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.13.2.3 2005/03/31 04:24:35 wpaul Exp $");
36 #endif
37 #ifdef __NetBSD__
38 __KERNEL_RCSID(0, "$NetBSD: subr_hal.c,v 1.6 2009/03/14 15:36:16 dsl Exp $");
39 #endif
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/errno.h>
45 #include <sys/callout.h>
46 #include <sys/kernel.h>
47 #include <sys/lock.h>
48 #ifdef __FreeBSD__
49 #include <sys/mutex.h>
50 #endif
51 #include <sys/proc.h>
52 #include <sys/sched.h>
53 #ifdef __FreeBSD__
54 #include <sys/module.h>
55 #endif
57 #include <sys/systm.h>
58 #ifdef __FreeBSD__
59 #include <machine/clock.h>
60 #include <machine/bus_memio.h>
61 #include <machine/bus_pio.h>
62 #endif
63 #include <sys/bus.h>
65 #ifdef __FreeBSD__
66 #include <sys/bus.h>
67 #include <sys/rman.h>
68 #endif
70 #include <compat/ndis/pe_var.h>
71 #include <compat/ndis/ntoskrnl_var.h>
72 #include <compat/ndis/hal_var.h>
74 __stdcall static void KeStallExecutionProcessor(uint32_t);
75 __stdcall static void WRITE_PORT_BUFFER_ULONG(uint32_t *,
76 uint32_t *, uint32_t);
77 __stdcall static void WRITE_PORT_BUFFER_USHORT(uint16_t *,
78 uint16_t *, uint32_t);
79 __stdcall static void WRITE_PORT_BUFFER_UCHAR(uint8_t *,
80 uint8_t *, uint32_t);
81 __stdcall static void WRITE_PORT_ULONG(uint32_t *, uint32_t);
82 __stdcall static void WRITE_PORT_USHORT(uint16_t *, uint16_t);
83 __stdcall static void WRITE_PORT_UCHAR(uint8_t *, uint8_t);
84 __stdcall static uint32_t READ_PORT_ULONG(uint32_t *);
85 __stdcall static uint16_t READ_PORT_USHORT(uint16_t *);
86 __stdcall static uint8_t READ_PORT_UCHAR(uint8_t *);
87 __stdcall static void READ_PORT_BUFFER_ULONG(uint32_t *,
88 uint32_t *, uint32_t);
89 __stdcall static void READ_PORT_BUFFER_USHORT(uint16_t *,
90 uint16_t *, uint32_t);
91 __stdcall static void READ_PORT_BUFFER_UCHAR(uint8_t *,
92 uint8_t *, uint32_t);
93 __stdcall static uint64_t KeQueryPerformanceCounter(uint64_t *);
94 __stdcall static void dummy (void);
96 extern struct mtx_pool *ndis_mtxpool;
98 int
99 hal_libinit(void)
101 image_patch_table *patch;
103 patch = hal_functbl;
104 while (patch->ipt_func != NULL) {
105 windrv_wrap((funcptr)patch->ipt_func,
106 (funcptr *)&patch->ipt_wrap);
107 patch++;
110 return(0);
114 hal_libfini(void)
116 image_patch_table *patch;
118 patch = hal_functbl;
119 while (patch->ipt_func != NULL) {
120 windrv_unwrap(patch->ipt_wrap);
121 patch++;
124 return(0);
127 __stdcall static void
128 KeStallExecutionProcessor(uint32_t usecs)
130 DELAY(usecs);
131 return;
134 __stdcall static void
135 WRITE_PORT_ULONG(uint32_t *port, uint32_t val)
137 bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
138 return;
141 __stdcall static void
142 WRITE_PORT_USHORT(uint16_t *port, uint16_t val)
144 bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
145 return;
148 __stdcall static void
149 WRITE_PORT_UCHAR(uint8_t *port, uint8_t val)
151 bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
152 return;
155 __stdcall static void
156 WRITE_PORT_BUFFER_ULONG(uint32_t *port, uint32_t *val, uint32_t cnt)
158 bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0,
159 (bus_size_t)port, val, cnt);
160 return;
163 __stdcall static void
164 WRITE_PORT_BUFFER_USHORT(uint16_t *port, uint16_t *val, uint32_t cnt)
166 bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0,
167 (bus_size_t)port, val, cnt);
168 return;
171 __stdcall static void
172 WRITE_PORT_BUFFER_UCHAR(uint8_t *port, uint8_t *val, uint32_t cnt)
174 bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0,
175 (bus_size_t)port, val, cnt);
176 return;
179 __stdcall static uint16_t
180 READ_PORT_USHORT(uint16_t *port)
182 return(bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
185 __stdcall static uint32_t
186 READ_PORT_ULONG(uint32_t *port)
188 return(bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
191 __stdcall static uint8_t
192 READ_PORT_UCHAR(uint8_t *port)
194 return(bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
197 __stdcall static void
198 READ_PORT_BUFFER_ULONG(uint32_t *port, uint32_t *val, uint32_t cnt)
200 bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0,
201 (bus_size_t)port, val, cnt);
202 return;
205 __stdcall static void
206 READ_PORT_BUFFER_USHORT(uint16_t *port, uint16_t *val, uint32_t cnt)
208 bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0,
209 (bus_size_t)port, val, cnt);
210 return;
213 __stdcall static void
214 READ_PORT_BUFFER_UCHAR(uint8_t *port, uint8_t *val, uint32_t cnt)
216 bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0,
217 (bus_size_t)port, val, cnt);
218 return;
222 * The spinlock implementation in Windows differs from that of FreeBSD.
223 * The basic operation of spinlocks involves two steps: 1) spin in a
224 * tight loop while trying to acquire a lock, 2) after obtaining the
225 * lock, disable preemption. (Note that on uniprocessor systems, you're
226 * allowed to skip the first step and just lock out pre-emption, since
227 * it's not possible for you to be in contention with another running
228 * thread.) Later, you release the lock then re-enable preemption.
229 * The difference between Windows and FreeBSD lies in how preemption
230 * is disabled. In FreeBSD, it's done using critical_enter(), which on
231 * the x86 arch translates to a cli instruction. This masks off all
232 * interrupts, and effectively stops the scheduler from ever running
233 * so _nothing_ can execute except the current thread. In Windows,
234 * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL.
235 * This stops other threads from running, but does _not_ block device
236 * interrupts. This means ISRs can still run, and they can make other
237 * threads runable, but those other threads won't be able to execute
238 * until the current thread lowers the IRQL to something less than
239 * DISPATCH_LEVEL.
241 * There's another commonly used IRQL in Windows, which is APC_LEVEL.
242 * An APC is an Asynchronous Procedure Call, which differs from a DPC
243 * (Defered Procedure Call) in that a DPC is queued up to run in
244 * another thread, while an APC runs in the thread that scheduled
245 * it (similar to a signal handler in a UNIX process). We don't
246 * actually support the notion of APCs in FreeBSD, so for now, the
247 * only IRQLs we're interested in are DISPATCH_LEVEL and PASSIVE_LEVEL.
249 * To simulate DISPATCH_LEVEL, we raise the current thread's priority
250 * to PI_REALTIME, which is the highest we can give it. This should,
251 * if I understand things correctly, prevent anything except for an
252 * interrupt thread from preempting us. PASSIVE_LEVEL is basically
253 * everything else.
255 * Be aware that, at least on the x86 arch, the Windows spinlock
256 * functions are divided up in peculiar ways. The actual spinlock
257 * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and
258 * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(),
259 * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
260 * live in ntoskrnl.exe. Most Windows source code will call
261 * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just
262 * macros that call KfAcquireSpinLock() and KfReleaseSpinLock().
263 * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
264 * perform the lock aquisition/release functions without doing the
265 * IRQL manipulation, and are used when one is already running at
266 * DISPATCH_LEVEL. Make sense? Good.
268 * According to the Microsoft documentation, any thread that calls
269 * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
270 * we detect someone trying to acquire a spinlock from DEVICE_LEVEL
271 * or HIGH_LEVEL, we panic.
274 __fastcall uint8_t
275 KfAcquireSpinLock(REGARGS1(kspin_lock *lock))
277 uint8_t oldirql;
279 /* I am so going to hell for this. */
280 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
281 panic("IRQL_NOT_LESS_THAN_OR_EQUAL");
283 oldirql = KeRaiseIrql(DISPATCH_LEVEL);
284 KeAcquireSpinLockAtDpcLevel(lock);
286 return(oldirql);
289 __fastcall void
290 KfReleaseSpinLock(REGARGS2(kspin_lock *lock, uint8_t newirql))
292 KeReleaseSpinLockFromDpcLevel(lock);
293 KeLowerIrql(newirql);
295 return;
298 __stdcall uint8_t
299 KeGetCurrentIrql(void)
301 if (AT_DISPATCH_LEVEL(curthread))
302 return(DISPATCH_LEVEL);
303 return(PASSIVE_LEVEL);
306 __stdcall static uint64_t
307 KeQueryPerformanceCounter(uint64_t *freq)
309 if (freq != NULL)
310 *freq = hz;
312 return((uint64_t)ticks);
316 static int old_ipl;
317 static int ipl_raised = FALSE;
319 __fastcall uint8_t
320 KfRaiseIrql(REGARGS1(uint8_t irql))
322 uint8_t oldirql = 0;
323 //#ifdef __NetBSD__
324 // uint8_t s;
325 //#endif
327 if (irql < KeGetCurrentIrql())
328 panic("IRQL_NOT_LESS_THAN");
330 if (KeGetCurrentIrql() == DISPATCH_LEVEL)
331 return(DISPATCH_LEVEL);
332 #ifdef __NetBSD__
333 if(irql >= DISPATCH_LEVEL && !ipl_raised) {
334 old_ipl = splsoftclock();
335 ipl_raised = TRUE;
336 oldirql = win_irql;
337 win_irql = irql;
339 #else /* __FreeBSD__ */
340 mtx_lock_spin(&sched_lock);
341 oldirql = curthread->td_base_pri;
342 sched_prio(curthread, PI_REALTIME);
343 #if __FreeBSD_version < 600000
344 curthread->td_base_pri = PI_REALTIME;
345 #endif
346 mtx_unlock_spin(&sched_lock);
347 #endif /* __FreeBSD__ */
349 return(oldirql);
352 __fastcall void
353 KfLowerIrql(REGARGS1(uint8_t oldirql))
355 //#ifdef __NetBSD__
356 // uint8_t s;
357 //#endif
359 if (oldirql == DISPATCH_LEVEL)
360 return;
362 #ifdef __FreeBSD__
363 if (KeGetCurrentIrql() != DISPATCH_LEVEL)
364 panic("IRQL_NOT_GREATER_THAN");
365 #else /* __NetBSD__ */
366 if (KeGetCurrentIrql() < oldirql)
367 panic("IRQL_NOT_GREATER_THAN");
368 #endif
370 #ifdef __NetBSD__
371 if(oldirql < DISPATCH_LEVEL && ipl_raised) {
372 splx(old_ipl);
373 ipl_raised = FALSE;
374 win_irql = oldirql;
376 #else
377 mtx_lock_spin(&sched_lock);
378 #if __FreeBSD_version < 600000
379 curthread->td_base_pri = oldirql;
380 #endif
381 sched_prio(curthread, oldirql);
382 mtx_unlock_spin(&sched_lock);
383 #endif /* __NetBSD__ */
385 return;
388 __stdcall
389 static void dummy(void)
391 printf ("hal dummy called...\n");
392 return;
395 image_patch_table hal_functbl[] = {
396 IMPORT_FUNC(KeStallExecutionProcessor),
397 IMPORT_FUNC(WRITE_PORT_ULONG),
398 IMPORT_FUNC(WRITE_PORT_USHORT),
399 IMPORT_FUNC(WRITE_PORT_UCHAR),
400 IMPORT_FUNC(WRITE_PORT_BUFFER_ULONG),
401 IMPORT_FUNC(WRITE_PORT_BUFFER_USHORT),
402 IMPORT_FUNC(WRITE_PORT_BUFFER_UCHAR),
403 IMPORT_FUNC(READ_PORT_ULONG),
404 IMPORT_FUNC(READ_PORT_USHORT),
405 IMPORT_FUNC(READ_PORT_UCHAR),
406 IMPORT_FUNC(READ_PORT_BUFFER_ULONG),
407 IMPORT_FUNC(READ_PORT_BUFFER_USHORT),
408 IMPORT_FUNC(READ_PORT_BUFFER_UCHAR),
409 IMPORT_FUNC(KfAcquireSpinLock),
410 IMPORT_FUNC(KfReleaseSpinLock),
411 IMPORT_FUNC(KeGetCurrentIrql),
412 IMPORT_FUNC(KeQueryPerformanceCounter),
413 IMPORT_FUNC(KfLowerIrql),
414 IMPORT_FUNC(KfRaiseIrql),
417 * This last entry is a catch-all for any function we haven't
418 * implemented yet. The PE import list patching routine will
419 * use it for any function that doesn't have an explicit match
420 * in this table.
423 { NULL, (FUNC)dummy, NULL },
425 /* End of list. */
427 { NULL, NULL, NULL }