1,8 → 1,8 |
#include <ddk.h> |
#include <linux/mm.h> |
#include <linux/err.h> |
#include <drm/drmP.h> |
#include <linux/hdmi.h> |
#include "radeon.h" |
|
int x86_clflush_size; |
unsigned int tsc_khz; |
12,7 → 12,7 |
struct file *filep; |
int count; |
|
filep = malloc(sizeof(*filep)); |
filep = __builtin_malloc(sizeof(*filep)); |
|
if(unlikely(filep == NULL)) |
return ERR_PTR(-ENOMEM); |
159,7 → 159,6 |
} |
|
|
|
//const char hex_asc[] = "0123456789abcdef"; |
|
/** |
378,45 → 377,93 |
buf, len, true); |
} |
|
void msleep(unsigned int msecs) |
{ |
msecs /= 10; |
if(!msecs) msecs = 1; |
|
static inline void __cpuid(unsigned int *eax, unsigned int *ebx, |
unsigned int *ecx, unsigned int *edx) |
__asm__ __volatile__ ( |
"call *__imp__Delay" |
::"b" (msecs)); |
__asm__ __volatile__ ( |
"":::"ebx"); |
|
}; |
|
|
/* simple loop based delay: */ |
static void delay_loop(unsigned long loops) |
{ |
/* ecx is often an input as well as an output. */ |
asm volatile("cpuid" |
: "=a" (*eax), |
"=b" (*ebx), |
"=c" (*ecx), |
"=d" (*edx) |
: "0" (*eax), "2" (*ecx) |
: "memory"); |
asm volatile( |
" test %0,%0 \n" |
" jz 3f \n" |
" jmp 1f \n" |
|
".align 16 \n" |
"1: jmp 2f \n" |
|
".align 16 \n" |
"2: dec %0 \n" |
" jnz 2b \n" |
"3: dec %0 \n" |
|
: /* we don't need output */ |
:"a" (loops) |
); |
} |
|
static inline void cpuid(unsigned int op, |
unsigned int *eax, unsigned int *ebx, |
unsigned int *ecx, unsigned int *edx) |
|
static void (*delay_fn)(unsigned long) = delay_loop; |
|
void __delay(unsigned long loops) |
{ |
*eax = op; |
*ecx = 0; |
__cpuid(eax, ebx, ecx, edx); |
delay_fn(loops); |
} |
|
void cpu_detect() |
|
inline void __const_udelay(unsigned long xloops) |
{ |
u32 junk, tfms, cap0, misc; |
int d0; |
|
cpuid(0x00000001, &tfms, &misc, &junk, &cap0); |
xloops *= 4; |
asm("mull %%edx" |
: "=d" (xloops), "=&a" (d0) |
: "1" (xloops), "" |
(loops_per_jiffy * (HZ/4))); |
|
if (cap0 & (1<<19)) |
__delay(++xloops); |
} |
|
void __udelay(unsigned long usecs) |
{ |
x86_clflush_size = ((misc >> 8) & 0xff) * 8; |
__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ |
} |
|
tsc_khz = GetCpuFreq()/1000; |
unsigned int _sw_hweight32(unsigned int w) |
{ |
#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER |
w -= (w >> 1) & 0x55555555; |
w = (w & 0x33333333) + ((w >> 2) & 0x33333333); |
w = (w + (w >> 4)) & 0x0f0f0f0f; |
return (w * 0x01010101) >> 24; |
#else |
unsigned int res = w - ((w >> 1) & 0x55555555); |
res = (res & 0x33333333) + ((res >> 2) & 0x33333333); |
res = (res + (res >> 4)) & 0x0F0F0F0F; |
res = res + (res >> 8); |
return (res + (res >> 16)) & 0x000000FF; |
#endif |
} |
EXPORT_SYMBOL(_sw_hweight32); |
|
|
void usleep_range(unsigned long min, unsigned long max) |
{ |
udelay(max); |
} |
EXPORT_SYMBOL(usleep_range); |
|
|
void *kmemdup(const void *src, size_t len, gfp_t gfp) |
{ |
void *p; |
427,26 → 474,504 |
return p; |
} |
|
void cpu_detect1() |
{ |
|
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) |
u32 junk, tfms, cap0, misc; |
int i; |
|
cpuid(0x00000001, &tfms, &misc, &junk, &cap0); |
|
if (cap0 & (1<<19)) |
{ |
const unsigned long *p = addr; |
unsigned long result = 0; |
unsigned long tmp; |
x86_clflush_size = ((misc >> 8) & 0xff) * 8; |
} |
|
while (size & ~(BITS_PER_LONG-1)) { |
if (~(tmp = *(p++))) |
goto found; |
result += BITS_PER_LONG; |
size -= BITS_PER_LONG; |
#if 0 |
cpuid(0x80000002, (unsigned int*)&cpuinfo.model_name[0], (unsigned int*)&cpuinfo.model_name[4], |
(unsigned int*)&cpuinfo.model_name[8], (unsigned int*)&cpuinfo.model_name[12]); |
cpuid(0x80000003, (unsigned int*)&cpuinfo.model_name[16], (unsigned int*)&cpuinfo.model_name[20], |
(unsigned int*)&cpuinfo.model_name[24], (unsigned int*)&cpuinfo.model_name[28]); |
cpuid(0x80000004, (unsigned int*)&cpuinfo.model_name[32], (unsigned int*)&cpuinfo.model_name[36], |
(unsigned int*)&cpuinfo.model_name[40], (unsigned int*)&cpuinfo.model_name[44]); |
|
printf("\n%s\n\n",cpuinfo.model_name); |
|
cpuinfo.def_mtrr = read_msr(MSR_MTRRdefType); |
cpuinfo.mtrr_cap = read_msr(IA32_MTRRCAP); |
|
printf("MSR_MTRRdefType %016llx\n\n", cpuinfo.def_mtrr); |
|
cpuinfo.var_mtrr_count = (u8_t)cpuinfo.mtrr_cap; |
|
for(i = 0; i < cpuinfo.var_mtrr_count; i++) |
{ |
u64_t mtrr_base; |
u64_t mtrr_mask; |
|
cpuinfo.var_mtrr[i].base = read_msr(MTRRphysBase_MSR(i)); |
cpuinfo.var_mtrr[i].mask = read_msr(MTRRphysMask_MSR(i)); |
|
printf("MTRR_%d base: %016llx mask: %016llx\n", i, |
cpuinfo.var_mtrr[i].base, |
cpuinfo.var_mtrr[i].mask); |
}; |
|
unsigned int cr0, cr3, cr4, eflags; |
|
eflags = safe_cli(); |
|
/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */ |
cr0 = read_cr0() | (1<<30); |
write_cr0(cr0); |
wbinvd(); |
|
cr4 = read_cr4(); |
write_cr4(cr4 & ~(1<<7)); |
|
cr3 = read_cr3(); |
write_cr3(cr3); |
|
/* Save MTRR state */ |
rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi); |
|
/* Disable MTRRs, and set the default type to uncached */ |
native_write_msr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi); |
wbinvd(); |
|
i = 0; |
set_mtrr(i++,0,0x80000000>>12,MTRR_WB); |
set_mtrr(i++,0x80000000>>12,0x40000000>>12,MTRR_WB); |
set_mtrr(i++,0xC0000000>>12,0x20000000>>12,MTRR_WB); |
set_mtrr(i++,0xdb800000>>12,0x00800000>>12,MTRR_UC); |
set_mtrr(i++,0xdc000000>>12,0x04000000>>12,MTRR_UC); |
set_mtrr(i++,0xE0000000>>12,0x10000000>>12,MTRR_WC); |
|
for(; i < cpuinfo.var_mtrr_count; i++) |
set_mtrr(i,0,0,0); |
|
write_cr3(cr3); |
|
/* Intel (P6) standard MTRRs */ |
native_write_msr(MSR_MTRRdefType, deftype_lo, deftype_hi); |
|
/* Enable caches */ |
write_cr0(read_cr0() & ~(1<<30)); |
|
/* Restore value of CR4 */ |
write_cr4(cr4); |
|
safe_sti(eflags); |
|
printf("\nnew MTRR map\n\n"); |
|
for(i = 0; i < cpuinfo.var_mtrr_count; i++) |
{ |
u64_t mtrr_base; |
u64_t mtrr_mask; |
|
cpuinfo.var_mtrr[i].base = read_msr(MTRRphysBase_MSR(i)); |
cpuinfo.var_mtrr[i].mask = read_msr(MTRRphysMask_MSR(i)); |
|
printf("MTRR_%d base: %016llx mask: %016llx\n", i, |
cpuinfo.var_mtrr[i].base, |
cpuinfo.var_mtrr[i].mask); |
}; |
#endif |
|
tsc_khz = (unsigned int)(GetCpuFreq()/1000); |
} |
if (!size) |
return result; |
|
tmp = (*p) | (~0UL << size); |
if (tmp == ~0UL) /* Are any bits zero? */ |
return result + size; /* Nope. */ |
found: |
return result + ffz(tmp); |
|
static atomic_t fence_context_counter = ATOMIC_INIT(0); |
|
/** |
* fence_context_alloc - allocate an array of fence contexts |
* @num: [in] amount of contexts to allocate |
* |
* This function will return the first index of the number of fences allocated. |
* The fence context is used for setting fence->context to a unique number. |
*/ |
unsigned fence_context_alloc(unsigned num) |
{ |
BUG_ON(!num); |
return atomic_add_return(num, &fence_context_counter) - num; |
} |
EXPORT_SYMBOL(fence_context_alloc); |
|
|
int fence_signal(struct fence *fence) |
{ |
unsigned long flags; |
|
if (!fence) |
return -EINVAL; |
|
// if (!ktime_to_ns(fence->timestamp)) { |
// fence->timestamp = ktime_get(); |
// smp_mb__before_atomic(); |
// } |
|
if (test_and_set_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) |
return -EINVAL; |
|
// trace_fence_signaled(fence); |
|
if (test_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) { |
struct fence_cb *cur, *tmp; |
|
spin_lock_irqsave(fence->lock, flags); |
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { |
list_del_init(&cur->node); |
cur->func(fence, cur); |
} |
spin_unlock_irqrestore(fence->lock, flags); |
} |
return 0; |
} |
EXPORT_SYMBOL(fence_signal); |
|
int fence_signal_locked(struct fence *fence) |
{ |
struct fence_cb *cur, *tmp; |
int ret = 0; |
|
if (WARN_ON(!fence)) |
return -EINVAL; |
|
// if (!ktime_to_ns(fence->timestamp)) { |
// fence->timestamp = ktime_get(); |
// smp_mb__before_atomic(); |
// } |
|
if (test_and_set_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { |
ret = -EINVAL; |
|
/* |
* we might have raced with the unlocked fence_signal, |
* still run through all callbacks |
*/ |
}// else |
// trace_fence_signaled(fence); |
|
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { |
list_del_init(&cur->node); |
cur->func(fence, cur); |
} |
return ret; |
} |
EXPORT_SYMBOL(fence_signal_locked); |
|
|
void fence_enable_sw_signaling(struct fence *fence) |
{ |
unsigned long flags; |
|
if (!test_and_set_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) && |
!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { |
// trace_fence_enable_signal(fence); |
|
spin_lock_irqsave(fence->lock, flags); |
|
if (!fence->ops->enable_signaling(fence)) |
fence_signal_locked(fence); |
|
spin_unlock_irqrestore(fence->lock, flags); |
} |
} |
EXPORT_SYMBOL(fence_enable_sw_signaling); |
|
|
|
signed long |
fence_wait_timeout(struct fence *fence, bool intr, signed long timeout) |
{ |
signed long ret; |
|
if (WARN_ON(timeout < 0)) |
return -EINVAL; |
|
// trace_fence_wait_start(fence); |
ret = fence->ops->wait(fence, intr, timeout); |
// trace_fence_wait_end(fence); |
return ret; |
} |
EXPORT_SYMBOL(fence_wait_timeout); |
|
void fence_release(struct kref *kref) |
{ |
struct fence *fence = |
container_of(kref, struct fence, refcount); |
|
// trace_fence_destroy(fence); |
|
BUG_ON(!list_empty(&fence->cb_list)); |
|
if (fence->ops->release) |
fence->ops->release(fence); |
else |
fence_free(fence); |
} |
EXPORT_SYMBOL(fence_release); |
|
void fence_free(struct fence *fence) |
{ |
kfree_rcu(fence, rcu); |
} |
EXPORT_SYMBOL(fence_free); |
|
|
reservation_object_add_shared_inplace(struct reservation_object *obj, |
struct reservation_object_list *fobj, |
struct fence *fence) |
{ |
u32 i; |
|
fence_get(fence); |
|
// preempt_disable(); |
write_seqcount_begin(&obj->seq); |
|
for (i = 0; i < fobj->shared_count; ++i) { |
struct fence *old_fence; |
|
old_fence = rcu_dereference_protected(fobj->shared[i], |
reservation_object_held(obj)); |
|
if (old_fence->context == fence->context) { |
/* memory barrier is added by write_seqcount_begin */ |
RCU_INIT_POINTER(fobj->shared[i], fence); |
write_seqcount_end(&obj->seq); |
preempt_enable(); |
|
fence_put(old_fence); |
return; |
} |
} |
|
/* |
* memory barrier is added by write_seqcount_begin, |
* fobj->shared_count is protected by this lock too |
*/ |
RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); |
fobj->shared_count++; |
|
write_seqcount_end(&obj->seq); |
// preempt_enable(); |
} |
|
|
|
static void |
reservation_object_add_shared_replace(struct reservation_object *obj, |
struct reservation_object_list *old, |
struct reservation_object_list *fobj, |
struct fence *fence) |
{ |
unsigned i; |
struct fence *old_fence = NULL; |
|
fence_get(fence); |
|
if (!old) { |
RCU_INIT_POINTER(fobj->shared[0], fence); |
fobj->shared_count = 1; |
goto done; |
} |
|
/* |
* no need to bump fence refcounts, rcu_read access |
* requires the use of kref_get_unless_zero, and the |
* references from the old struct are carried over to |
* the new. |
*/ |
fobj->shared_count = old->shared_count; |
|
for (i = 0; i < old->shared_count; ++i) { |
struct fence *check; |
|
check = rcu_dereference_protected(old->shared[i], |
reservation_object_held(obj)); |
|
if (!old_fence && check->context == fence->context) { |
old_fence = check; |
RCU_INIT_POINTER(fobj->shared[i], fence); |
} else |
RCU_INIT_POINTER(fobj->shared[i], check); |
} |
if (!old_fence) { |
RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); |
fobj->shared_count++; |
} |
|
done: |
// preempt_disable(); |
write_seqcount_begin(&obj->seq); |
/* |
* RCU_INIT_POINTER can be used here, |
* seqcount provides the necessary barriers |
*/ |
RCU_INIT_POINTER(obj->fence, fobj); |
write_seqcount_end(&obj->seq); |
// preempt_enable(); |
|
if (old) |
kfree_rcu(old, rcu); |
|
if (old_fence) |
fence_put(old_fence); |
} |
|
|
int reservation_object_reserve_shared(struct reservation_object *obj) |
{ |
struct reservation_object_list *fobj, *old; |
u32 max; |
|
old = reservation_object_get_list(obj); |
|
if (old && old->shared_max) { |
if (old->shared_count < old->shared_max) { |
/* perform an in-place update */ |
kfree(obj->staged); |
obj->staged = NULL; |
return 0; |
} else |
max = old->shared_max * 2; |
} else |
max = 4; |
|
/* |
* resize obj->staged or allocate if it doesn't exist, |
* noop if already correct size |
*/ |
fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]), |
GFP_KERNEL); |
if (!fobj) |
return -ENOMEM; |
|
obj->staged = fobj; |
fobj->shared_max = max; |
return 0; |
} |
EXPORT_SYMBOL(reservation_object_reserve_shared); |
|
void reservation_object_add_shared_fence(struct reservation_object *obj, |
struct fence *fence) |
{ |
struct reservation_object_list *old, *fobj = obj->staged; |
|
old = reservation_object_get_list(obj); |
obj->staged = NULL; |
|
if (!fobj) { |
BUG_ON(old->shared_count >= old->shared_max); |
reservation_object_add_shared_inplace(obj, old, fence); |
} else |
reservation_object_add_shared_replace(obj, old, fobj, fence); |
} |
EXPORT_SYMBOL(reservation_object_add_shared_fence); |
|
|
void reservation_object_add_excl_fence(struct reservation_object *obj, |
struct fence *fence) |
{ |
struct fence *old_fence = reservation_object_get_excl(obj); |
struct reservation_object_list *old; |
u32 i = 0; |
|
old = reservation_object_get_list(obj); |
if (old) |
i = old->shared_count; |
|
if (fence) |
fence_get(fence); |
|
// preempt_disable(); |
write_seqcount_begin(&obj->seq); |
/* write_seqcount_begin provides the necessary memory barrier */ |
RCU_INIT_POINTER(obj->fence_excl, fence); |
if (old) |
old->shared_count = 0; |
write_seqcount_end(&obj->seq); |
// preempt_enable(); |
|
/* inplace update, no shared fences */ |
while (i--) |
fence_put(rcu_dereference_protected(old->shared[i], |
reservation_object_held(obj))); |
|
if (old_fence) |
fence_put(old_fence); |
} |
EXPORT_SYMBOL(reservation_object_add_excl_fence); |
|
void |
fence_init(struct fence *fence, const struct fence_ops *ops, |
spinlock_t *lock, unsigned context, unsigned seqno) |
{ |
BUG_ON(!lock); |
BUG_ON(!ops || !ops->wait || !ops->enable_signaling || |
!ops->get_driver_name || !ops->get_timeline_name); |
|
kref_init(&fence->refcount); |
fence->ops = ops; |
INIT_LIST_HEAD(&fence->cb_list); |
fence->lock = lock; |
fence->context = context; |
fence->seqno = seqno; |
fence->flags = 0UL; |
|
// trace_fence_init(fence); |
} |
EXPORT_SYMBOL(fence_init); |
|
|
#include <linux/rcupdate.h> |
|
struct rcu_ctrlblk { |
struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ |
struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ |
struct rcu_head **curtail; /* ->next pointer of last CB. */ |
// RCU_TRACE(long qlen); /* Number of pending CBs. */ |
// RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */ |
// RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */ |
// RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */ |
// RCU_TRACE(const char *name); /* Name of RCU type. */ |
}; |
|
/* Definition for rcupdate control block. */ |
static struct rcu_ctrlblk rcu_sched_ctrlblk = { |
.donetail = &rcu_sched_ctrlblk.rcucblist, |
.curtail = &rcu_sched_ctrlblk.rcucblist, |
// RCU_TRACE(.name = "rcu_sched") |
}; |
|
static void __call_rcu(struct rcu_head *head, |
void (*func)(struct rcu_head *rcu), |
struct rcu_ctrlblk *rcp) |
{ |
unsigned long flags; |
|
// debug_rcu_head_queue(head); |
head->func = func; |
head->next = NULL; |
|
local_irq_save(flags); |
*rcp->curtail = head; |
rcp->curtail = &head->next; |
// RCU_TRACE(rcp->qlen++); |
local_irq_restore(flags); |
} |
|
/* |
* Post an RCU callback to be invoked after the end of an RCU-sched grace |
* period. But since we have but one CPU, that would be after any |
* quiescent state. |
*/ |
void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) |
{ |
__call_rcu(head, func, &rcu_sched_ctrlblk); |
} |
|
|