1 /* _NVRM_COPYRIGHT_BEGIN_
3 * Copyright 2001-2002 by NVIDIA Corporation. All rights reserved. All
4 * information contained herein is proprietary and confidential to NVIDIA
5 * Corporation. Any use, reproduction, or disclosure without the written
6 * permission of NVIDIA Corporation is prohibited.
12 #include "os-interface.h"
14 #include "nv-freebsd.h"
17 /* DragonFly compat */
18 #include <machine/pmap_inval.h>
21 pmap_invalidate_range(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
23 struct pmap_inval_info info;
26 pmap_inval_init(&info);
27 for (va = sva; va < eva; va += PAGE_SIZE)
28 pmap_inval_add(&info, pmap, va);
29 pmap_inval_flush(&info);
34 * The NVIDIA kernel module's malloc identifier, needed for both tracking
35 * and actual allocation/freeing purposes. M_NVIDIA is declared elsewhere
36 * to make it known to other parts of the kernel module (nv-freebsd.h).
39 MALLOC_DEFINE(M_NVIDIA, "nvidia", "NVIDIA memory allocations");
42 #define MAX_ERROR_STRING 256
44 RM_STATUS NV_API_CALL os_alloc_contig_pages(
49 *address = contigmalloc(size, M_NVIDIA, 0, 0, ~0, PAGE_SIZE, 0);
50 return *address ? RM_OK : RM_ERROR;
53 void NV_API_CALL os_free_contig_pages(
58 contigfree(address, size, M_NVIDIA);
62 * The core resource manager's favorite source of memory, this routine is
63 * called from different contexts, including ISRs. This means that it can
64 * not be allowed to sleep when memory is low.
67 RM_STATUS NV_API_CALL os_alloc_mem(
72 /* XXX Fix me? (malloc flags) */
73 *address = malloc(size, M_NVIDIA, M_INTWAIT | M_ZERO | M_NULLOK);
74 return *address ? RM_OK : RM_ERROR;
77 void NV_API_CALL os_free_mem(void *address)
79 free(address, M_NVIDIA);
82 #define NV_MSECS_PER_TICK (1000 / hz)
83 #define NV_MSECS_TO_TICKS(ms) ((ms) * hz / 1000)
84 #define NV_USECS_PER_TICK (1000000 / hz)
85 #define NV_USECS_TO_TICKS(us) ((us) * hz / 1000000)
87 RM_STATUS NV_API_CALL os_delay(U032 MilliSeconds)
89 unsigned long MicroSeconds;
91 struct timeval tv_end, tv_aux;
93 getmicrotime(&tv_aux);
95 if (__NV_ITHREAD() && (MilliSeconds > NV_MAX_ISR_DELAY_MS))
99 DELAY(MilliSeconds * 1000);
103 MicroSeconds = MilliSeconds * 1000;
104 tv_end.tv_usec = MicroSeconds;
106 /* tv_end = tv_aux + tv_end */
107 NV_TIMERADD(&tv_aux, &tv_end, &tv_end);
109 ticks = NV_USECS_TO_TICKS(MicroSeconds);
113 tsleep((void *)os_delay, PCATCH, "delay", ticks);
114 getmicrotime(&tv_aux);
115 if (NV_TIMERCMP(&tv_aux, &tv_end, <)) {
116 /* tv_aux = tv_end - tv_aux */
117 NV_TIMERSUB(&tv_end, &tv_aux, &tv_aux);
118 MicroSeconds = tv_aux.tv_usec + (tv_aux.tv_sec * 1000000);
121 } while ((ticks = NV_USECS_TO_TICKS(MicroSeconds)) > 0);
124 if (MicroSeconds > 0)
130 RM_STATUS NV_API_CALL os_delay_us(U032 MicroSeconds)
132 if (__NV_ITHREAD() && (MicroSeconds > NV_MAX_ISR_DELAY_US))
138 U032 NV_API_CALL os_get_cpu_frequency(void)
140 return ((tsc_frequency + 4999) / 1000000);
143 U032 NV_API_CALL os_get_current_process(void)
145 return curproc->p_pid;
148 RM_STATUS NV_API_CALL os_get_current_time(
163 BOOL NV_API_CALL os_is_administrator(PHWINFO pDev)
165 return suser(CURTHREAD) ? FALSE : TRUE;
168 U008 NV_API_CALL os_io_read_byte(
173 /* XXX Fix me? (bus_space access) */
177 void NV_API_CALL os_io_write_byte(
183 /* XXX Fix me? (bus_space access) */
184 outb(address, value);
187 U016 NV_API_CALL os_io_read_word(
192 /* XXX Fix me? (bus_space access) */
196 void NV_API_CALL os_io_write_word(
202 /* XXX Fix me? (bus_space access) */
203 return outw(address, value);
206 U032 NV_API_CALL os_io_read_dword(
211 /* XXX Fix me? (bus_space access) */
215 void NV_API_CALL os_io_write_dword(
221 /* XXX Fix me? (bus_space access) */
222 outl(address, value);
225 void* NV_API_CALL os_map_kernel_space(
233 #if defined(NVCPU_X86) && !defined(PAE)
234 if (start > 0xffffffff)
238 if (start & PAGE_MASK)
241 size = NV_ALIGN_UP(size, PAGE_SIZE);
244 case NV_MEMORY_CACHED:
245 map_mode = PAT_WRITE_BACK;
247 case NV_MEMORY_WRITECOMBINED:
248 map_mode = PAT_WRITE_COMBINING;
250 case NV_MEMORY_UNCACHED:
251 case NV_MEMORY_DEFAULT:
252 map_mode = PAT_UNCACHEABLE;
255 nv_printf(NV_DBG_ERRORS,
256 "NVRM: unknown mode in os_map_kernel_space()\n");
260 return pmap_mapdev_attr(start, size, map_mode);
263 void NV_API_CALL os_unmap_kernel_space(
268 pmap_unmapdev_attr((vm_offset_t)address, size);
271 void* NV_API_CALL os_map_kernel_space_high(
277 if (!(pfn & ~0xfffff)) {
278 start = pfn << PAGE_SHIFT;
279 return os_map_kernel_space(start, size, NV_MEMORY_CACHED);
284 void NV_API_CALL os_unmap_kernel_space_high(
290 os_unmap_kernel_space(addr, size);
293 RM_STATUS NV_API_CALL os_set_mem_range(
300 struct mem_range_desc mrd;
304 mrd.mr_flags = MDF_WRITECOMBINE;
306 strcpy(mrd.mr_owner, "NVIDIA");
307 arg = MEMRANGE_SET_UPDATE;
309 if (mem_range_attr_set(&mrd, &arg))
315 RM_STATUS NV_API_CALL os_unset_mem_range(
321 struct mem_range_desc mrd;
325 arg = MEMRANGE_SET_REMOVE;
327 if (mem_range_attr_set(&mrd, &arg))
335 * The current debug level is used to determine if certain debug messages
336 * are printed to the system console/log files or not. It defaults to the
337 * highest debug level, i.e. the lowest debug output.
340 U032 cur_debuglevel = 0xffffffff;
342 void NV_API_CALL os_dbg_init(void)
347 NV_UMA_ZONE_ALLOC_STACK(sp);
351 if (rm_read_registry_dword(sp, NULL, "NVreg", "ResmanDebugLevel",
352 &new_debuglevel) == RM_OK) {
353 if (new_debuglevel != 0xffffffff)
354 cur_debuglevel = new_debuglevel;
357 NV_UMA_ZONE_FREE_STACK(sp);
360 RM_STATUS NV_API_CALL os_schedule(void)
362 return RM_ERR_NOT_SUPPORTED;
365 void NV_API_CALL os_dbg_set_level(U032 new_debuglevel)
367 cur_debuglevel = new_debuglevel;
370 void NV_API_CALL os_dbg_breakpoint(void)
377 void NV_API_CALL out_string(const char *message)
379 #if defined(DEBUG) || defined(QA_BUILD)
380 kprintf("%s", message);
384 static char nv_error_string[MAX_ERROR_STRING];
386 int NV_API_CALL nv_printf(
392 char *message = nv_error_string;
394 int chars_written = 0;
396 if (debuglevel >= ((cur_debuglevel >> 4) & 3)) {
397 __va_start(arglist, format);
398 chars_written = kvsprintf(message, format, arglist);
400 kprintf("%s", message);
403 return chars_written;
406 int NV_API_CALL nv_snprintf(
416 __va_start(arglist, fmt);
417 chars_written = kvsnprintf(buf, size, fmt, arglist);
420 return chars_written;
423 void NV_API_CALL nv_os_log(
430 ksprintf(nv_error_string, "NVRM: ");
431 l = strlen(nv_error_string);
432 kvsnprintf(nv_error_string + l, MAX_ERROR_STRING - l, fmt, ap);
433 kprintf("%s", nv_error_string);
436 S032 NV_API_CALL os_mem_cmp(
442 return memcmp(buf0, buf1, length);
445 U008* NV_API_CALL os_mem_copy(
451 #if defined(NVCPU_X86_64)
453 for (i = 0; i < length; i++) dst[i] = src[i];
456 return memcpy(dst, src, length);
460 RM_STATUS NV_API_CALL os_memcpy_from_user(
466 if (src < (void *) VM_MAX_USER_ADDRESS)
467 return copyin(src, dst, length) ? RM_ERR_INVALID_POINTER : RM_OK;
469 return os_mem_copy(dst, src, length) ? RM_ERR_INVALID_POINTER : RM_OK;
472 RM_STATUS NV_API_CALL os_memcpy_to_user(
478 if (dst < (void *) VM_MAX_USER_ADDRESS)
479 return copyout(src, dst, length) ? RM_ERR_INVALID_POINTER : RM_OK;
481 return os_mem_copy(dst, src, length) ? RM_ERR_INVALID_POINTER : RM_OK;
484 void* NV_API_CALL os_mem_set(
490 return memset(b, c, length);
493 S032 NV_API_CALL os_string_compare(
498 return strcmp(s1, s2);
501 char* NV_API_CALL os_string_copy(
506 return strcpy(dst, src);
509 U032 NV_API_CALL os_string_length(const char* s)
514 RM_STATUS NV_API_CALL os_strncpy_from_user(
520 return copyinstr(src, dst, n, NULL) ? RM_ERR_INVALID_POINTER : RM_OK;
523 U032 NV_API_CALL os_get_page_size(void)
528 NvU64 NV_API_CALL os_get_page_mask(void)
531 * On FreeBSD, PAGE_MASK means (PAGE_SIZE - 1); on Linux it means the
532 * opposite, ~(PAGE_SIZE - 1); that is what this function is expected
538 NvU64 NV_API_CALL os_get_system_memory_size(void)
540 return ((NvU64)physmem * PAGE_SIZE) / RM_PAGE_SIZE;
543 U032 NV_API_CALL os_get_cpu_count(void)
548 RM_STATUS NV_API_CALL os_flush_cpu_cache(void)
551 * XXX This will do for now, but this may need to be extended
552 * to make IPI calls (flushing all caches).
554 __asm__ __volatile__("wbinvd": : :"memory");
558 void NV_API_CALL os_flush_cpu_write_combine_buffer(void)
560 __asm__ __volatile__("sfence": : :"memory");
563 RM_STATUS NV_API_CALL os_raise_smp_barrier(void)
565 return RM_ERR_NOT_SUPPORTED;
568 RM_STATUS NV_API_CALL os_clear_smp_barrier(void)
570 return RM_ERR_NOT_SUPPORTED;
575 struct spinlock lock;
579 RM_STATUS NV_API_CALL os_alloc_sema(void **semaphore)
582 struct os_mutex *mtx;
585 NV_UMA_ZONE_ALLOC_STACK(sp);
587 return RM_ERR_NO_FREE_MEM;
589 status = os_alloc_mem((void **)&mtx, sizeof(struct os_mutex));
590 if (status != RM_OK) {
591 NV_UMA_ZONE_FREE_STACK(sp);
595 spin_init(&mtx->lock);
600 *semaphore = (void *) mtx;
605 RM_STATUS NV_API_CALL os_free_sema(void *semaphore)
607 struct os_mutex *mtx = semaphore;
611 NV_UMA_ZONE_FREE_STACK(sp);
613 spin_uninit(&mtx->lock);
615 os_free_mem(semaphore);
620 RM_STATUS NV_API_CALL os_acquire_sema(void *semaphore)
622 struct os_mutex *mtx = semaphore;
624 spin_lock_wr(&mtx->lock);
626 rm_disable_interrupts(mtx->sp);
629 msleep(mtx, &mtx->lock, 0, "nvsemaq", 0);
630 spin_unlock_wr(&mtx->lock);
635 BOOL NV_API_CALL os_cond_acquire_sema(void *semaphore)
637 struct os_mutex *mtx = semaphore;
639 spin_lock_wr(&mtx->lock);
640 if (mtx->refcnt < 1) {
641 spin_unlock_wr(&mtx->lock);
644 rm_disable_interrupts(mtx->sp);
646 spin_unlock_wr(&mtx->lock);
652 RM_STATUS NV_API_CALL os_release_sema(void *semaphore)
654 struct os_mutex *mtx = semaphore;
656 spin_lock_wr(&mtx->lock);
660 rm_enable_interrupts(mtx->sp);
662 spin_unlock_wr(&mtx->lock);
667 BOOL NV_API_CALL os_is_acquired_sema(void *semaphore)
669 struct os_mutex *mtx = semaphore;
670 return (mtx->refcnt < 1);
673 BOOL NV_API_CALL os_pat_supported(void)
676 * FreeBSD has no native PAT support and there's no good
677 * way to implement it privately as we do on Linux.
682 RM_STATUS NV_API_CALL os_set_mlock_capability()
687 S032 NV_API_CALL os_mlock_user_memory(
695 S032 NV_API_CALL os_munlock_user_memory(
703 RM_STATUS NV_API_CALL os_check_process_map_limit(
704 NvU64 proc_max_map_count
710 void NV_API_CALL os_register_compatible_ioctl(
717 void NV_API_CALL os_unregister_compatible_ioctl(
724 RM_STATUS NV_API_CALL os_disable_console_access(void)
729 RM_STATUS NV_API_CALL os_enable_console_access(void)