mirror of https://gitee.com/openkylin/linux.git
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
This is a major rework of the nouveau driver core, to reflect more closely how the hw is used and to make it easier to implement newer features now that the GPUs are more clearly understood than when nouveau started. It also contains a few other bits: thermal patches nv41/44 pcie gart fixes i2c unregistering fixes. * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (191 commits) drm/nv98/crypt: fix fuc build with latest envyas drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering drm/nv41/vm: fix and enable use of "real" pciegart drm/nv44/vm: fix and enable use of "real" pciegart drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie drm/nouveau: store supported dma mask in vmmgr drm/nvc0/ibus: initial implementation of subdev drm/nouveau/therm: add support for fan-control modes drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules drm/nouveau/therm: calculate the pwm divisor on nv50+ drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster drm/nouveau/therm: move thermal-related functions to the therm subdev drm/nouveau/bios: parse the pwm divisor from the perf table drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices drm/nouveau/therm: rework thermal table parsing drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table drm/nouveau: fix pm initialization order drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it drm/nouveau: log channel debug/error messages from client object rather than drm client drm/nouveau: have drm debugging macros build on top of core macros ... Conflicts: drivers/gpu/drm/nouveau/nouveau_dp.c
This commit is contained in:
commit
268d28371c
|
@ -133,7 +133,7 @@ character devices for this group:
|
|||
$ lspci -n -s 0000:06:0d.0
|
||||
06:0d.0 0401: 1102:0002 (rev 08)
|
||||
# echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
|
||||
# echo 1102 0002 > /sys/bus/pci/drivers/vfio/new_id
|
||||
# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
|
||||
|
||||
Now we need to look at what other devices are in the group to free
|
||||
it for use by VFIO:
|
||||
|
|
|
@ -3552,11 +3552,12 @@ K: \b(ABS|SYN)_MT_
|
|||
|
||||
INTEL C600 SERIES SAS CONTROLLER DRIVER
|
||||
M: Intel SCU Linux support <intel-linux-scu@intel.com>
|
||||
M: Lukasz Dorau <lukasz.dorau@intel.com>
|
||||
M: Maciej Patelczyk <maciej.patelczyk@intel.com>
|
||||
M: Dave Jiang <dave.jiang@intel.com>
|
||||
M: Ed Nadolski <edmund.nadolski@intel.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git
|
||||
S: Maintained
|
||||
T: git git://git.code.sf.net/p/intel-sas/isci
|
||||
S: Supported
|
||||
F: drivers/scsi/isci/
|
||||
F: firmware/isci/
|
||||
|
||||
|
@ -5544,6 +5545,8 @@ F: Documentation/devicetree/bindings/pwm/
|
|||
F: include/linux/pwm.h
|
||||
F: include/linux/of_pwm.h
|
||||
F: drivers/pwm/
|
||||
F: drivers/video/backlight/pwm_bl.c
|
||||
F: include/linux/pwm_backlight.h
|
||||
|
||||
PXA2xx/PXA3xx SUPPORT
|
||||
M: Eric Miao <eric.y.miao@gmail.com>
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 3
|
||||
PATCHLEVEL = 6
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc7
|
||||
EXTRAVERSION =
|
||||
NAME = Terrified Chipmunk
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -261,7 +261,7 @@ static void __init apx4devkit_init(void)
|
|||
enable_clk_enet_out();
|
||||
|
||||
if (IS_BUILTIN(CONFIG_PHYLIB))
|
||||
phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
|
||||
phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK,
|
||||
apx4devkit_phy_fixup);
|
||||
|
||||
mxsfb_pdata.mode_list = apx4devkit_video_modes;
|
||||
|
|
|
@ -204,6 +204,13 @@ void __init orion5x_wdt_init(void)
|
|||
void __init orion5x_init_early(void)
|
||||
{
|
||||
orion_time_set_base(TIMER_VIRT_BASE);
|
||||
|
||||
/*
|
||||
* Some Orion5x devices allocate their coherent buffers from atomic
|
||||
* context. Increase size of atomic coherent pool to make sure such
|
||||
* the allocations won't fail.
|
||||
*/
|
||||
init_dma_coherent_pool_size(SZ_1M);
|
||||
}
|
||||
|
||||
int orion5x_tclk;
|
||||
|
|
|
@ -346,6 +346,8 @@ static int __init atomic_pool_init(void)
|
|||
(unsigned)pool->size / 1024);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(pages);
|
||||
no_pages:
|
||||
kfree(bitmap);
|
||||
no_bitmap:
|
||||
|
|
|
@ -2,6 +2,7 @@ include include/asm-generic/Kbuild.asm
|
|||
|
||||
generic-y += atomic.h
|
||||
generic-y += auxvec.h
|
||||
generic-y += barrier.h
|
||||
generic-y += bitsperlong.h
|
||||
generic-y += bugs.h
|
||||
generic-y += cputime.h
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Port on Texas Instruments TMS320C6x architecture
|
||||
*
|
||||
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
|
||||
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef _ASM_C6X_BARRIER_H
|
||||
#define _ASM_C6X_BARRIER_H
|
||||
|
||||
#define nop() asm("NOP\n");
|
||||
|
||||
#define mb() barrier()
|
||||
#define rmb() barrier()
|
||||
#define wmb() barrier()
|
||||
#define set_mb(var, value) do { var = value; mb(); } while (0)
|
||||
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
|
||||
|
||||
#define smp_mb() barrier()
|
||||
#define smp_rmb() barrier()
|
||||
#define smp_wmb() barrier()
|
||||
#define smp_read_barrier_depends() do { } while (0)
|
||||
|
||||
#endif /* _ASM_C6X_BARRIER_H */
|
|
@ -25,21 +25,23 @@
|
|||
#include <linux/module.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#define GXIO_TRIO_OP_ALLOC_ASIDS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
|
||||
#define GXIO_TRIO_OP_DEALLOC_ASID IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400)
|
||||
#define GXIO_TRIO_OP_ALLOC_ASIDS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1401)
|
||||
|
||||
#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1402)
|
||||
#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404)
|
||||
|
||||
#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
|
||||
#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140f)
|
||||
#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412)
|
||||
|
||||
#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1417)
|
||||
#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1418)
|
||||
#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1419)
|
||||
#define GXIO_TRIO_OP_CONFIG_MSI_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x141a)
|
||||
#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414)
|
||||
|
||||
#define GXIO_TRIO_OP_SET_MPS_MRS IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141c)
|
||||
#define GXIO_TRIO_OP_FORCE_RC_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141d)
|
||||
#define GXIO_TRIO_OP_FORCE_EP_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
|
||||
#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e)
|
||||
#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141f)
|
||||
#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1420)
|
||||
#define GXIO_TRIO_OP_CONFIG_MSI_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1421)
|
||||
|
||||
#define GXIO_TRIO_OP_SET_MPS_MRS IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1423)
|
||||
#define GXIO_TRIO_OP_FORCE_RC_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1424)
|
||||
#define GXIO_TRIO_OP_FORCE_EP_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1425)
|
||||
#define GXIO_TRIO_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
|
||||
#define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
|
||||
|
||||
|
|
|
@ -20,14 +20,6 @@ struct mm_struct;
|
|||
|
||||
struct thread_struct {
|
||||
struct task_struct *saved_task;
|
||||
/*
|
||||
* This flag is set to 1 before calling do_fork (and analyzed in
|
||||
* copy_thread) to mark that we are begin called from userspace (fork /
|
||||
* vfork / clone), and reset to 0 after. It is left to 0 when called
|
||||
* from kernelspace (i.e. kernel_thread() or fork_idle(),
|
||||
* as of 2.6.11).
|
||||
*/
|
||||
int forking;
|
||||
struct pt_regs regs;
|
||||
int singlestep_syscall;
|
||||
void *fault_addr;
|
||||
|
@ -58,7 +50,6 @@ struct thread_struct {
|
|||
|
||||
#define INIT_THREAD \
|
||||
{ \
|
||||
.forking = 0, \
|
||||
.regs = EMPTY_REGS, \
|
||||
.fault_addr = NULL, \
|
||||
.prev_sched = NULL, \
|
||||
|
|
|
@ -7,16 +7,6 @@ DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK);
|
|||
DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT);
|
||||
DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
|
||||
|
||||
DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
|
||||
DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
|
||||
DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
|
||||
DEFINE_STR(UM_KERN_ERR, KERN_ERR);
|
||||
DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
|
||||
DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
|
||||
DEFINE_STR(UM_KERN_INFO, KERN_INFO);
|
||||
DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
|
||||
DEFINE_STR(UM_KERN_CONT, KERN_CONT);
|
||||
|
||||
DEFINE(UM_ELF_CLASS, ELF_CLASS);
|
||||
DEFINE(UM_ELFCLASS32, ELFCLASS32);
|
||||
DEFINE(UM_ELFCLASS64, ELFCLASS64);
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
extern void panic(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
/* Requires preincluding include/linux/kern_levels.h */
|
||||
#define UM_KERN_EMERG KERN_EMERG
|
||||
#define UM_KERN_ALERT KERN_ALERT
|
||||
#define UM_KERN_CRIT KERN_CRIT
|
||||
#define UM_KERN_ERR KERN_ERR
|
||||
#define UM_KERN_WARNING KERN_WARNING
|
||||
#define UM_KERN_NOTICE KERN_NOTICE
|
||||
#define UM_KERN_INFO KERN_INFO
|
||||
#define UM_KERN_DEBUG KERN_DEBUG
|
||||
#define UM_KERN_CONT KERN_CONT
|
||||
|
||||
#ifdef UML_CONFIG_PRINTK
|
||||
extern int printk(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
|
|
@ -39,34 +39,21 @@ void flush_thread(void)
|
|||
|
||||
void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
|
||||
{
|
||||
get_safe_registers(regs->regs.gp, regs->regs.fp);
|
||||
PT_REGS_IP(regs) = eip;
|
||||
PT_REGS_SP(regs) = esp;
|
||||
current->ptrace &= ~PT_DTRACE;
|
||||
#ifdef SUBARCH_EXECVE1
|
||||
SUBARCH_EXECVE1(regs->regs);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(start_thread);
|
||||
|
||||
static long execve1(const char *file,
|
||||
const char __user *const __user *argv,
|
||||
const char __user *const __user *env)
|
||||
{
|
||||
long error;
|
||||
|
||||
error = do_execve(file, argv, env, ¤t->thread.regs);
|
||||
if (error == 0) {
|
||||
task_lock(current);
|
||||
current->ptrace &= ~PT_DTRACE;
|
||||
#ifdef SUBARCH_EXECVE1
|
||||
SUBARCH_EXECVE1(¤t->thread.regs.regs);
|
||||
#endif
|
||||
task_unlock(current);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env)
|
||||
{
|
||||
long err;
|
||||
|
||||
err = execve1(file, argv, env);
|
||||
err = do_execve(file, argv, env, ¤t->thread.regs);
|
||||
if (!err)
|
||||
UML_LONGJMP(current->thread.exec_buf, 1);
|
||||
return err;
|
||||
|
@ -81,7 +68,7 @@ long sys_execve(const char __user *file, const char __user *const __user *argv,
|
|||
filename = getname(file);
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename)) goto out;
|
||||
error = execve1(filename, argv, env);
|
||||
error = do_execve(filename, argv, env, ¤t->thread.regs);
|
||||
putname(filename);
|
||||
out:
|
||||
return error;
|
||||
|
|
|
@ -181,11 +181,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
struct pt_regs *regs)
|
||||
{
|
||||
void (*handler)(void);
|
||||
int kthread = current->flags & PF_KTHREAD;
|
||||
int ret = 0;
|
||||
|
||||
p->thread = (struct thread_struct) INIT_THREAD;
|
||||
|
||||
if (current->thread.forking) {
|
||||
if (!kthread) {
|
||||
memcpy(&p->thread.regs.regs, ®s->regs,
|
||||
sizeof(p->thread.regs.regs));
|
||||
PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
|
||||
|
@ -195,8 +196,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
handler = fork_handler;
|
||||
|
||||
arch_copy_thread(¤t->thread.arch, &p->thread.arch);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
|
||||
p->thread.request.u.thread = current->thread.request.u.thread;
|
||||
handler = new_thread_handler;
|
||||
|
@ -204,7 +204,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
|
||||
new_thread(task_stack_page(p), &p->thread.switch_buf, handler);
|
||||
|
||||
if (current->thread.forking) {
|
||||
if (!kthread) {
|
||||
clear_flushed_tls(p);
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,9 +22,13 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
|
|||
struct k_sigaction *ka, siginfo_t *info)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
int singlestep = 0;
|
||||
unsigned long sp;
|
||||
int err;
|
||||
|
||||
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
|
||||
singlestep = 1;
|
||||
|
||||
/* Did we come from a system call? */
|
||||
if (PT_REGS_SYSCALL_NR(regs) >= 0) {
|
||||
/* If so, check system call restarting.. */
|
||||
|
@ -61,7 +65,7 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
|
|||
if (err)
|
||||
force_sigsegv(signr, current);
|
||||
else
|
||||
signal_delivered(signr, info, ka, regs, 0);
|
||||
signal_delivered(signr, info, ka, regs, singlestep);
|
||||
}
|
||||
|
||||
static int kern_do_signal(struct pt_regs *regs)
|
||||
|
|
|
@ -17,25 +17,25 @@
|
|||
|
||||
long sys_fork(void)
|
||||
{
|
||||
long ret;
|
||||
|
||||
current->thread.forking = 1;
|
||||
ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs),
|
||||
return do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs),
|
||||
¤t->thread.regs, 0, NULL, NULL);
|
||||
current->thread.forking = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
long sys_vfork(void)
|
||||
{
|
||||
long ret;
|
||||
|
||||
current->thread.forking = 1;
|
||||
ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
|
||||
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
|
||||
UPT_SP(¤t->thread.regs.regs),
|
||||
¤t->thread.regs, 0, NULL, NULL);
|
||||
current->thread.forking = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
void __user *parent_tid, void __user *child_tid)
|
||||
{
|
||||
if (!newsp)
|
||||
newsp = UPT_SP(¤t->thread.regs.regs);
|
||||
|
||||
return do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid,
|
||||
child_tid);
|
||||
}
|
||||
|
||||
long old_mmap(unsigned long addr, unsigned long len,
|
||||
|
|
|
@ -8,7 +8,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS))
|
|||
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
|
||||
|
||||
$(USER_OBJS:.o=.%): \
|
||||
c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include user.h $(CFLAGS_$(basetarget).o)
|
||||
c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o)
|
||||
|
||||
# These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of
|
||||
# using it directly.
|
||||
|
|
|
@ -21,6 +21,7 @@ config 64BIT
|
|||
config X86_32
|
||||
def_bool !64BIT
|
||||
select HAVE_AOUT
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
|
||||
config X86_64
|
||||
def_bool 64BIT
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
#define STR(x) #x
|
||||
#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
|
||||
|
||||
#define BLANK() asm volatile("\n->" : : )
|
||||
|
||||
#define OFFSET(sym, str, mem) \
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
extern long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
void __user *parent_tid, void __user *child_tid);
|
||||
#ifdef __i386__
|
||||
#include "syscalls_32.h"
|
||||
#else
|
||||
|
|
|
@ -416,9 +416,6 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
|
|||
PT_REGS_AX(regs) = (unsigned long) sig;
|
||||
PT_REGS_DX(regs) = (unsigned long) 0;
|
||||
PT_REGS_CX(regs) = (unsigned long) 0;
|
||||
|
||||
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
|
||||
ptrace_notify(SIGTRAP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -466,9 +463,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
|
|||
PT_REGS_AX(regs) = (unsigned long) sig;
|
||||
PT_REGS_DX(regs) = (unsigned long) &frame->info;
|
||||
PT_REGS_CX(regs) = (unsigned long) &frame->uc;
|
||||
|
||||
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
|
||||
ptrace_notify(SIGTRAP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define ptregs_execve sys_execve
|
||||
#define ptregs_iopl sys_iopl
|
||||
#define ptregs_vm86old sys_vm86old
|
||||
#define ptregs_clone sys_clone
|
||||
#define ptregs_clone i386_clone
|
||||
#define ptregs_vm86 sys_vm86
|
||||
#define ptregs_sigaltstack sys_sigaltstack
|
||||
#define ptregs_vfork sys_vfork
|
||||
|
|
|
@ -3,37 +3,24 @@
|
|||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/sched.h"
|
||||
#include "linux/shm.h"
|
||||
#include "linux/ipc.h"
|
||||
#include "linux/syscalls.h"
|
||||
#include "asm/mman.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "asm/unistd.h"
|
||||
#include <linux/syscalls.h>
|
||||
#include <sysdep/syscalls.h>
|
||||
|
||||
/*
|
||||
* The prototype on i386 is:
|
||||
*
|
||||
* int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
|
||||
* int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls
|
||||
*
|
||||
* and the "newtls" arg. on i386 is read by copy_thread directly from the
|
||||
* register saved on the stack.
|
||||
*/
|
||||
long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
int __user *parent_tid, void *newtls, int __user *child_tid)
|
||||
long i386_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
int __user *parent_tid, void *newtls, int __user *child_tid)
|
||||
{
|
||||
long ret;
|
||||
|
||||
if (!newsp)
|
||||
newsp = UPT_SP(¤t->thread.regs.regs);
|
||||
|
||||
current->thread.forking = 1;
|
||||
ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid,
|
||||
child_tid);
|
||||
current->thread.forking = 0;
|
||||
return ret;
|
||||
return sys_clone(clone_flags, newsp, parent_tid, child_tid);
|
||||
}
|
||||
|
||||
|
||||
long sys_sigaction(int sig, const struct old_sigaction __user *act,
|
||||
struct old_sigaction __user *oact)
|
||||
{
|
||||
|
|
|
@ -5,12 +5,9 @@
|
|||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/linkage.h"
|
||||
#include "linux/personality.h"
|
||||
#include "linux/utsname.h"
|
||||
#include "asm/prctl.h" /* XXX This should get the constants from libc */
|
||||
#include "asm/uaccess.h"
|
||||
#include "os.h"
|
||||
#include <linux/sched.h>
|
||||
#include <asm/prctl.h> /* XXX This should get the constants from libc */
|
||||
#include <os.h>
|
||||
|
||||
long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
|
||||
{
|
||||
|
@ -79,20 +76,6 @@ long sys_arch_prctl(int code, unsigned long addr)
|
|||
return arch_prctl(current, code, (unsigned long __user *) addr);
|
||||
}
|
||||
|
||||
long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
void __user *parent_tid, void __user *child_tid)
|
||||
{
|
||||
long ret;
|
||||
|
||||
if (!newsp)
|
||||
newsp = UPT_SP(¤t->thread.regs.regs);
|
||||
current->thread.forking = 1;
|
||||
ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid,
|
||||
child_tid);
|
||||
current->thread.forking = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arch_switch_to(struct task_struct *to)
|
||||
{
|
||||
if ((to->thread.arch.fs == 0) || (to->mm == NULL))
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <asm/e820.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
|
||||
|
@ -544,4 +545,7 @@ void __init xen_arch_setup(void)
|
|||
disable_cpufreq();
|
||||
WARN_ON(set_pm_idle_to_default());
|
||||
fiddle_vdso();
|
||||
#ifdef CONFIG_NUMA
|
||||
numa_off = 1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ struct nvme_dev {
|
|||
char serial[20];
|
||||
char model[40];
|
||||
char firmware_rev[8];
|
||||
u32 max_hw_sectors;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -835,15 +836,15 @@ static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
|
|||
}
|
||||
|
||||
static int nvme_get_features(struct nvme_dev *dev, unsigned fid,
|
||||
unsigned dword11, dma_addr_t dma_addr)
|
||||
unsigned nsid, dma_addr_t dma_addr)
|
||||
{
|
||||
struct nvme_command c;
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.features.opcode = nvme_admin_get_features;
|
||||
c.features.nsid = cpu_to_le32(nsid);
|
||||
c.features.prp1 = cpu_to_le64(dma_addr);
|
||||
c.features.fid = cpu_to_le32(fid);
|
||||
c.features.dword11 = cpu_to_le32(dword11);
|
||||
|
||||
return nvme_submit_admin_cmd(dev, &c, NULL);
|
||||
}
|
||||
|
@ -862,11 +863,51 @@ static int nvme_set_features(struct nvme_dev *dev, unsigned fid,
|
|||
return nvme_submit_admin_cmd(dev, &c, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* nvme_cancel_ios - Cancel outstanding I/Os
|
||||
* @queue: The queue to cancel I/Os on
|
||||
* @timeout: True to only cancel I/Os which have timed out
|
||||
*/
|
||||
static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
|
||||
{
|
||||
int depth = nvmeq->q_depth - 1;
|
||||
struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
|
||||
unsigned long now = jiffies;
|
||||
int cmdid;
|
||||
|
||||
for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
|
||||
void *ctx;
|
||||
nvme_completion_fn fn;
|
||||
static struct nvme_completion cqe = {
|
||||
.status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1,
|
||||
};
|
||||
|
||||
if (timeout && !time_after(now, info[cmdid].timeout))
|
||||
continue;
|
||||
dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid);
|
||||
ctx = cancel_cmdid(nvmeq, cmdid, &fn);
|
||||
fn(nvmeq->dev, ctx, &cqe);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvme_free_queue_mem(struct nvme_queue *nvmeq)
|
||||
{
|
||||
dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
|
||||
(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
|
||||
dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
|
||||
nvmeq->sq_cmds, nvmeq->sq_dma_addr);
|
||||
kfree(nvmeq);
|
||||
}
|
||||
|
||||
static void nvme_free_queue(struct nvme_dev *dev, int qid)
|
||||
{
|
||||
struct nvme_queue *nvmeq = dev->queues[qid];
|
||||
int vector = dev->entry[nvmeq->cq_vector].vector;
|
||||
|
||||
spin_lock_irq(&nvmeq->q_lock);
|
||||
nvme_cancel_ios(nvmeq, false);
|
||||
spin_unlock_irq(&nvmeq->q_lock);
|
||||
|
||||
irq_set_affinity_hint(vector, NULL);
|
||||
free_irq(vector, nvmeq);
|
||||
|
||||
|
@ -876,18 +917,15 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid)
|
|||
adapter_delete_cq(dev, qid);
|
||||
}
|
||||
|
||||
dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
|
||||
(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
|
||||
dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
|
||||
nvmeq->sq_cmds, nvmeq->sq_dma_addr);
|
||||
kfree(nvmeq);
|
||||
nvme_free_queue_mem(nvmeq);
|
||||
}
|
||||
|
||||
static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
|
||||
int depth, int vector)
|
||||
{
|
||||
struct device *dmadev = &dev->pci_dev->dev;
|
||||
unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info));
|
||||
unsigned extra = DIV_ROUND_UP(depth, 8) + (depth *
|
||||
sizeof(struct nvme_cmd_info));
|
||||
struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL);
|
||||
if (!nvmeq)
|
||||
return NULL;
|
||||
|
@ -975,7 +1013,7 @@ static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev,
|
|||
|
||||
static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
|
||||
{
|
||||
int result;
|
||||
int result = 0;
|
||||
u32 aqa;
|
||||
u64 cap;
|
||||
unsigned long timeout;
|
||||
|
@ -1005,17 +1043,22 @@ static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
|
|||
timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
|
||||
dev->db_stride = NVME_CAP_STRIDE(cap);
|
||||
|
||||
while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
|
||||
while (!result && !(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
|
||||
msleep(100);
|
||||
if (fatal_signal_pending(current))
|
||||
return -EINTR;
|
||||
result = -EINTR;
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(&dev->pci_dev->dev,
|
||||
"Device not ready; aborting initialisation\n");
|
||||
return -ENODEV;
|
||||
result = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
nvme_free_queue_mem(nvmeq);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = queue_request_irq(dev, nvmeq, "nvme admin");
|
||||
dev->queues[0] = nvmeq;
|
||||
return result;
|
||||
|
@ -1037,6 +1080,8 @@ static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
|
|||
offset = offset_in_page(addr);
|
||||
count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
|
||||
pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
|
||||
if (!pages)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = get_user_pages_fast(addr, count, 1, pages);
|
||||
if (err < count) {
|
||||
|
@ -1146,14 +1191,13 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int nvme_user_admin_cmd(struct nvme_ns *ns,
|
||||
static int nvme_user_admin_cmd(struct nvme_dev *dev,
|
||||
struct nvme_admin_cmd __user *ucmd)
|
||||
{
|
||||
struct nvme_dev *dev = ns->dev;
|
||||
struct nvme_admin_cmd cmd;
|
||||
struct nvme_command c;
|
||||
int status, length;
|
||||
struct nvme_iod *iod;
|
||||
struct nvme_iod *uninitialized_var(iod);
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
@ -1204,7 +1248,7 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
|||
case NVME_IOCTL_ID:
|
||||
return ns->ns_id;
|
||||
case NVME_IOCTL_ADMIN_CMD:
|
||||
return nvme_user_admin_cmd(ns, (void __user *)arg);
|
||||
return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
|
||||
case NVME_IOCTL_SUBMIT_IO:
|
||||
return nvme_submit_io(ns, (void __user *)arg);
|
||||
default:
|
||||
|
@ -1218,26 +1262,6 @@ static const struct block_device_operations nvme_fops = {
|
|||
.compat_ioctl = nvme_ioctl,
|
||||
};
|
||||
|
||||
static void nvme_timeout_ios(struct nvme_queue *nvmeq)
|
||||
{
|
||||
int depth = nvmeq->q_depth - 1;
|
||||
struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
|
||||
unsigned long now = jiffies;
|
||||
int cmdid;
|
||||
|
||||
for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
|
||||
void *ctx;
|
||||
nvme_completion_fn fn;
|
||||
static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, };
|
||||
|
||||
if (!time_after(now, info[cmdid].timeout))
|
||||
continue;
|
||||
dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid);
|
||||
ctx = cancel_cmdid(nvmeq, cmdid, &fn);
|
||||
fn(nvmeq->dev, ctx, &cqe);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvme_resubmit_bios(struct nvme_queue *nvmeq)
|
||||
{
|
||||
while (bio_list_peek(&nvmeq->sq_cong)) {
|
||||
|
@ -1269,7 +1293,7 @@ static int nvme_kthread(void *data)
|
|||
spin_lock_irq(&nvmeq->q_lock);
|
||||
if (nvme_process_cq(nvmeq))
|
||||
printk("process_cq did something\n");
|
||||
nvme_timeout_ios(nvmeq);
|
||||
nvme_cancel_ios(nvmeq, true);
|
||||
nvme_resubmit_bios(nvmeq);
|
||||
spin_unlock_irq(&nvmeq->q_lock);
|
||||
}
|
||||
|
@ -1339,6 +1363,9 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid,
|
|||
ns->disk = disk;
|
||||
lbaf = id->flbas & 0xf;
|
||||
ns->lba_shift = id->lbaf[lbaf].ds;
|
||||
blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
|
||||
if (dev->max_hw_sectors)
|
||||
blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
|
||||
|
||||
disk->major = nvme_major;
|
||||
disk->minors = NVME_MINORS;
|
||||
|
@ -1383,7 +1410,7 @@ static int set_queue_count(struct nvme_dev *dev, int count)
|
|||
|
||||
static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
|
||||
{
|
||||
int result, cpu, i, nr_io_queues, db_bar_size;
|
||||
int result, cpu, i, nr_io_queues, db_bar_size, q_depth;
|
||||
|
||||
nr_io_queues = num_online_cpus();
|
||||
result = set_queue_count(dev, nr_io_queues);
|
||||
|
@ -1429,9 +1456,10 @@ static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
|
|||
cpu = cpumask_next(cpu, cpu_online_mask);
|
||||
}
|
||||
|
||||
q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1,
|
||||
NVME_Q_DEPTH);
|
||||
for (i = 0; i < nr_io_queues; i++) {
|
||||
dev->queues[i + 1] = nvme_create_queue(dev, i + 1,
|
||||
NVME_Q_DEPTH, i);
|
||||
dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i);
|
||||
if (IS_ERR(dev->queues[i + 1]))
|
||||
return PTR_ERR(dev->queues[i + 1]);
|
||||
dev->queue_count++;
|
||||
|
@ -1480,6 +1508,10 @@ static int __devinit nvme_dev_add(struct nvme_dev *dev)
|
|||
memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
|
||||
memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
|
||||
memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
|
||||
if (ctrl->mdts) {
|
||||
int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
|
||||
dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9);
|
||||
}
|
||||
|
||||
id_ns = mem;
|
||||
for (i = 1; i <= nn; i++) {
|
||||
|
@ -1523,8 +1555,6 @@ static int nvme_dev_remove(struct nvme_dev *dev)
|
|||
list_del(&dev->node);
|
||||
spin_unlock(&dev_list_lock);
|
||||
|
||||
/* TODO: wait all I/O finished or cancel them */
|
||||
|
||||
list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
|
||||
list_del(&ns->list);
|
||||
del_gendisk(ns->disk);
|
||||
|
@ -1560,15 +1590,33 @@ static void nvme_release_prp_pools(struct nvme_dev *dev)
|
|||
dma_pool_destroy(dev->prp_small_pool);
|
||||
}
|
||||
|
||||
/* XXX: Use an ida or something to let remove / add work correctly */
|
||||
static void nvme_set_instance(struct nvme_dev *dev)
|
||||
static DEFINE_IDA(nvme_instance_ida);
|
||||
|
||||
static int nvme_set_instance(struct nvme_dev *dev)
|
||||
{
|
||||
static int instance;
|
||||
dev->instance = instance++;
|
||||
int instance, error;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock(&dev_list_lock);
|
||||
error = ida_get_new(&nvme_instance_ida, &instance);
|
||||
spin_unlock(&dev_list_lock);
|
||||
} while (error == -EAGAIN);
|
||||
|
||||
if (error)
|
||||
return -ENODEV;
|
||||
|
||||
dev->instance = instance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvme_release_instance(struct nvme_dev *dev)
|
||||
{
|
||||
spin_lock(&dev_list_lock);
|
||||
ida_remove(&nvme_instance_ida, dev->instance);
|
||||
spin_unlock(&dev_list_lock);
|
||||
}
|
||||
|
||||
static int __devinit nvme_probe(struct pci_dev *pdev,
|
||||
|
@ -1601,7 +1649,10 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
|
|||
pci_set_drvdata(pdev, dev);
|
||||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
|
||||
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
|
||||
nvme_set_instance(dev);
|
||||
result = nvme_set_instance(dev);
|
||||
if (result)
|
||||
goto disable;
|
||||
|
||||
dev->entry[0].vector = pdev->irq;
|
||||
|
||||
result = nvme_setup_prp_pools(dev);
|
||||
|
@ -1704,15 +1755,17 @@ static struct pci_driver nvme_driver = {
|
|||
|
||||
static int __init nvme_init(void)
|
||||
{
|
||||
int result = -EBUSY;
|
||||
int result;
|
||||
|
||||
nvme_thread = kthread_run(nvme_kthread, NULL, "nvme");
|
||||
if (IS_ERR(nvme_thread))
|
||||
return PTR_ERR(nvme_thread);
|
||||
|
||||
nvme_major = register_blkdev(nvme_major, "nvme");
|
||||
if (nvme_major <= 0)
|
||||
result = register_blkdev(nvme_major, "nvme");
|
||||
if (result < 0)
|
||||
goto kill_kthread;
|
||||
else if (result > 0)
|
||||
nvme_major = result;
|
||||
|
||||
result = pci_register_driver(&nvme_driver);
|
||||
if (result)
|
||||
|
|
|
@ -246,13 +246,12 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
|
|||
{
|
||||
struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
|
||||
|
||||
rbd_get_dev(rbd_dev);
|
||||
|
||||
set_device_ro(bdev, rbd_dev->read_only);
|
||||
|
||||
if ((mode & FMODE_WRITE) && rbd_dev->read_only)
|
||||
return -EROFS;
|
||||
|
||||
rbd_get_dev(rbd_dev);
|
||||
set_device_ro(bdev, rbd_dev->read_only);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -391,7 +391,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
|
|||
for (j = 0; j < nr_channels; j++) {
|
||||
struct dimm_info *dimm = csrow->channels[j]->dimm;
|
||||
|
||||
dimm->nr_pages = nr_pages / nr_channels;
|
||||
dimm->nr_pages = nr_pages;
|
||||
dimm->grain = nr_pages << PAGE_SHIFT;
|
||||
dimm->mtype = MEM_DDR2;
|
||||
dimm->dtype = DEV_UNKNOWN;
|
||||
|
|
|
@ -1012,6 +1012,10 @@ static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
|
|||
/* add the number of COLUMN bits */
|
||||
addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
|
||||
|
||||
/* Dual-rank memories have twice the size */
|
||||
if (dinfo->dual_rank)
|
||||
addrBits++;
|
||||
|
||||
addrBits += 6; /* add 64 bits per DIMM */
|
||||
addrBits -= 20; /* divide by 2^^20 */
|
||||
addrBits -= 3; /* 8 bits per bytes */
|
||||
|
|
|
@ -513,7 +513,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
|||
{
|
||||
struct sbridge_pvt *pvt = mci->pvt_info;
|
||||
struct dimm_info *dimm;
|
||||
int i, j, banks, ranks, rows, cols, size, npages;
|
||||
unsigned i, j, banks, ranks, rows, cols, npages;
|
||||
u64 size;
|
||||
u32 reg;
|
||||
enum edac_type mode;
|
||||
enum mem_type mtype;
|
||||
|
@ -585,10 +586,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
|||
cols = numcol(mtr);
|
||||
|
||||
/* DDR3 has 8 I/O banks */
|
||||
size = (rows * cols * banks * ranks) >> (20 - 3);
|
||||
size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
|
||||
npages = MiB_TO_PAGES(size);
|
||||
|
||||
edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
|
||||
edac_dbg(0, "mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
|
||||
pvt->sbridge_dev->mc, i, j,
|
||||
size, npages,
|
||||
banks, ranks, rows, cols);
|
||||
|
|
|
@ -308,6 +308,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
|
|||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_level_p012(group, pin, value);
|
||||
__set_gpio_dir_p012(group, pin, 0);
|
||||
|
||||
return 0;
|
||||
|
@ -318,6 +319,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
|
|||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_level_p3(group, pin, value);
|
||||
__set_gpio_dir_p3(group, pin, 0);
|
||||
|
||||
return 0;
|
||||
|
@ -326,6 +328,9 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
|
|||
static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpo_level_p3(group, pin, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,34 @@ config DRM_NOUVEAU
|
|||
help
|
||||
Choose this option for open-source nVidia support.
|
||||
|
||||
config NOUVEAU_DEBUG
|
||||
int "Maximum debug level"
|
||||
depends on DRM_NOUVEAU
|
||||
range 0 7
|
||||
default 5
|
||||
help
|
||||
Selects the maximum debug level to compile support for.
|
||||
|
||||
0 - fatal
|
||||
1 - error
|
||||
2 - warning
|
||||
3 - info
|
||||
4 - debug
|
||||
5 - trace (recommended)
|
||||
6 - paranoia
|
||||
7 - spam
|
||||
|
||||
The paranoia and spam levels will add a lot of extra checks which
|
||||
may potentially slow down driver operation.
|
||||
|
||||
config NOUVEAU_DEBUG_DEFAULT
|
||||
int "Default debug level"
|
||||
depends on DRM_NOUVEAU
|
||||
range 0 7
|
||||
default 3
|
||||
help
|
||||
Selects the default debug level
|
||||
|
||||
config DRM_NOUVEAU_BACKLIGHT
|
||||
bool "Support for backlight control"
|
||||
depends on DRM_NOUVEAU
|
||||
|
@ -25,14 +53,6 @@ config DRM_NOUVEAU_BACKLIGHT
|
|||
Say Y here if you want to control the backlight of your display
|
||||
(e.g. a laptop panel).
|
||||
|
||||
config DRM_NOUVEAU_DEBUG
|
||||
bool "Build in Nouveau's debugfs support"
|
||||
depends on DRM_NOUVEAU && DEBUG_FS
|
||||
default y
|
||||
help
|
||||
Say Y here if you want Nouveau to output debugging information
|
||||
via debugfs.
|
||||
|
||||
menu "I2C encoder or helper chips"
|
||||
depends on DRM && DRM_KMS_HELPER && I2C
|
||||
|
||||
|
|
|
@ -3,49 +3,190 @@
|
|||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm
|
||||
nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
|
||||
nouveau_gpuobj.o nouveau_irq.o nouveau_notifier.o \
|
||||
nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
|
||||
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
|
||||
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
|
||||
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
|
||||
nouveau_hdmi.o nouveau_dp.o nouveau_ramht.o \
|
||||
nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
|
||||
nouveau_mm.o nouveau_vm.o nouveau_mxm.o nouveau_gpio.o \
|
||||
nouveau_abi16.o \
|
||||
nv04_timer.o \
|
||||
nv04_mc.o nv40_mc.o nv50_mc.o \
|
||||
nv04_fb.o nv10_fb.o nv20_fb.o nv30_fb.o nv40_fb.o \
|
||||
nv50_fb.o nvc0_fb.o \
|
||||
nv04_fifo.o nv10_fifo.o nv17_fifo.o nv40_fifo.o nv50_fifo.o \
|
||||
nv84_fifo.o nvc0_fifo.o nve0_fifo.o \
|
||||
nv04_fence.o nv10_fence.o nv84_fence.o nvc0_fence.o \
|
||||
nv04_software.o nv50_software.o nvc0_software.o \
|
||||
nv04_graph.o nv10_graph.o nv20_graph.o \
|
||||
nv40_graph.o nv50_graph.o nvc0_graph.o nve0_graph.o \
|
||||
nv40_grctx.o nv50_grctx.o nvc0_grctx.o nve0_grctx.o \
|
||||
nv84_crypt.o nv98_crypt.o \
|
||||
nva3_copy.o nvc0_copy.o \
|
||||
nv31_mpeg.o nv50_mpeg.o \
|
||||
nv84_bsp.o \
|
||||
nv84_vp.o \
|
||||
nv98_ppp.o \
|
||||
nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
|
||||
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
|
||||
nv04_crtc.o nv04_display.o nv04_cursor.o \
|
||||
nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
|
||||
nv50_cursor.o nv50_display.o \
|
||||
nvd0_display.o \
|
||||
nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
|
||||
nv10_gpio.o nv50_gpio.o \
|
||||
nv50_calc.o \
|
||||
nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
|
||||
nv50_vram.o nvc0_vram.o \
|
||||
nv50_vm.o nvc0_vm.o nouveau_prime.o
|
||||
ccflags-y += -I$(src)/core/include
|
||||
ccflags-y += -I$(src)/core
|
||||
ccflags-y += -I$(src)
|
||||
|
||||
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
|
||||
nouveau-y := core/core/client.o
|
||||
nouveau-y += core/core/engctx.o
|
||||
nouveau-y += core/core/engine.o
|
||||
nouveau-y += core/core/enum.o
|
||||
nouveau-y += core/core/gpuobj.o
|
||||
nouveau-y += core/core/handle.o
|
||||
nouveau-y += core/core/mm.o
|
||||
nouveau-y += core/core/namedb.o
|
||||
nouveau-y += core/core/object.o
|
||||
nouveau-y += core/core/option.o
|
||||
nouveau-y += core/core/parent.o
|
||||
nouveau-y += core/core/printk.o
|
||||
nouveau-y += core/core/ramht.o
|
||||
nouveau-y += core/core/subdev.o
|
||||
|
||||
nouveau-y += core/subdev/bar/base.o
|
||||
nouveau-y += core/subdev/bar/nv50.o
|
||||
nouveau-y += core/subdev/bar/nvc0.o
|
||||
nouveau-y += core/subdev/bios/base.o
|
||||
nouveau-y += core/subdev/bios/bit.o
|
||||
nouveau-y += core/subdev/bios/conn.o
|
||||
nouveau-y += core/subdev/bios/dcb.o
|
||||
nouveau-y += core/subdev/bios/dp.o
|
||||
nouveau-y += core/subdev/bios/extdev.o
|
||||
nouveau-y += core/subdev/bios/gpio.o
|
||||
nouveau-y += core/subdev/bios/i2c.o
|
||||
nouveau-y += core/subdev/bios/init.o
|
||||
nouveau-y += core/subdev/bios/mxm.o
|
||||
nouveau-y += core/subdev/bios/perf.o
|
||||
nouveau-y += core/subdev/bios/pll.o
|
||||
nouveau-y += core/subdev/bios/therm.o
|
||||
nouveau-y += core/subdev/clock/nv04.o
|
||||
nouveau-y += core/subdev/clock/nv40.o
|
||||
nouveau-y += core/subdev/clock/nv50.o
|
||||
nouveau-y += core/subdev/clock/nva3.o
|
||||
nouveau-y += core/subdev/clock/nvc0.o
|
||||
nouveau-y += core/subdev/clock/pllnv04.o
|
||||
nouveau-y += core/subdev/clock/pllnva3.o
|
||||
nouveau-y += core/subdev/device/base.o
|
||||
nouveau-y += core/subdev/device/nv04.o
|
||||
nouveau-y += core/subdev/device/nv10.o
|
||||
nouveau-y += core/subdev/device/nv20.o
|
||||
nouveau-y += core/subdev/device/nv30.o
|
||||
nouveau-y += core/subdev/device/nv40.o
|
||||
nouveau-y += core/subdev/device/nv50.o
|
||||
nouveau-y += core/subdev/device/nvc0.o
|
||||
nouveau-y += core/subdev/device/nve0.o
|
||||
nouveau-y += core/subdev/devinit/base.o
|
||||
nouveau-y += core/subdev/devinit/nv04.o
|
||||
nouveau-y += core/subdev/devinit/nv05.o
|
||||
nouveau-y += core/subdev/devinit/nv10.o
|
||||
nouveau-y += core/subdev/devinit/nv1a.o
|
||||
nouveau-y += core/subdev/devinit/nv20.o
|
||||
nouveau-y += core/subdev/devinit/nv50.o
|
||||
nouveau-y += core/subdev/fb/base.o
|
||||
nouveau-y += core/subdev/fb/nv04.o
|
||||
nouveau-y += core/subdev/fb/nv10.o
|
||||
nouveau-y += core/subdev/fb/nv20.o
|
||||
nouveau-y += core/subdev/fb/nv30.o
|
||||
nouveau-y += core/subdev/fb/nv40.o
|
||||
nouveau-y += core/subdev/fb/nv50.o
|
||||
nouveau-y += core/subdev/fb/nvc0.o
|
||||
nouveau-y += core/subdev/gpio/base.o
|
||||
nouveau-y += core/subdev/gpio/nv10.o
|
||||
nouveau-y += core/subdev/gpio/nv50.o
|
||||
nouveau-y += core/subdev/gpio/nvd0.o
|
||||
nouveau-y += core/subdev/i2c/base.o
|
||||
nouveau-y += core/subdev/i2c/aux.o
|
||||
nouveau-y += core/subdev/i2c/bit.o
|
||||
nouveau-y += core/subdev/ibus/nvc0.o
|
||||
nouveau-y += core/subdev/ibus/nve0.o
|
||||
nouveau-y += core/subdev/instmem/base.o
|
||||
nouveau-y += core/subdev/instmem/nv04.o
|
||||
nouveau-y += core/subdev/instmem/nv40.o
|
||||
nouveau-y += core/subdev/instmem/nv50.o
|
||||
nouveau-y += core/subdev/ltcg/nvc0.o
|
||||
nouveau-y += core/subdev/mc/base.o
|
||||
nouveau-y += core/subdev/mc/nv04.o
|
||||
nouveau-y += core/subdev/mc/nv44.o
|
||||
nouveau-y += core/subdev/mc/nv50.o
|
||||
nouveau-y += core/subdev/mc/nv98.o
|
||||
nouveau-y += core/subdev/mc/nvc0.o
|
||||
nouveau-y += core/subdev/mxm/base.o
|
||||
nouveau-y += core/subdev/mxm/mxms.o
|
||||
nouveau-y += core/subdev/mxm/nv50.o
|
||||
nouveau-y += core/subdev/therm/base.o
|
||||
nouveau-y += core/subdev/therm/fan.o
|
||||
nouveau-y += core/subdev/therm/ic.o
|
||||
nouveau-y += core/subdev/therm/nv40.o
|
||||
nouveau-y += core/subdev/therm/nv50.o
|
||||
nouveau-y += core/subdev/therm/temp.o
|
||||
nouveau-y += core/subdev/timer/base.o
|
||||
nouveau-y += core/subdev/timer/nv04.o
|
||||
nouveau-y += core/subdev/vm/base.o
|
||||
nouveau-y += core/subdev/vm/nv04.o
|
||||
nouveau-y += core/subdev/vm/nv41.o
|
||||
nouveau-y += core/subdev/vm/nv44.o
|
||||
nouveau-y += core/subdev/vm/nv50.o
|
||||
nouveau-y += core/subdev/vm/nvc0.o
|
||||
|
||||
nouveau-y += core/engine/dmaobj/base.o
|
||||
nouveau-y += core/engine/dmaobj/nv04.o
|
||||
nouveau-y += core/engine/dmaobj/nv50.o
|
||||
nouveau-y += core/engine/dmaobj/nvc0.o
|
||||
nouveau-y += core/engine/bsp/nv84.o
|
||||
nouveau-y += core/engine/copy/nva3.o
|
||||
nouveau-y += core/engine/copy/nvc0.o
|
||||
nouveau-y += core/engine/copy/nve0.o
|
||||
nouveau-y += core/engine/crypt/nv84.o
|
||||
nouveau-y += core/engine/crypt/nv98.o
|
||||
nouveau-y += core/engine/disp/nv04.o
|
||||
nouveau-y += core/engine/disp/nv50.o
|
||||
nouveau-y += core/engine/disp/nvd0.o
|
||||
nouveau-y += core/engine/disp/vga.o
|
||||
nouveau-y += core/engine/fifo/base.o
|
||||
nouveau-y += core/engine/fifo/nv04.o
|
||||
nouveau-y += core/engine/fifo/nv10.o
|
||||
nouveau-y += core/engine/fifo/nv17.o
|
||||
nouveau-y += core/engine/fifo/nv40.o
|
||||
nouveau-y += core/engine/fifo/nv50.o
|
||||
nouveau-y += core/engine/fifo/nv84.o
|
||||
nouveau-y += core/engine/fifo/nvc0.o
|
||||
nouveau-y += core/engine/fifo/nve0.o
|
||||
nouveau-y += core/engine/graph/ctxnv40.o
|
||||
nouveau-y += core/engine/graph/ctxnv50.o
|
||||
nouveau-y += core/engine/graph/ctxnvc0.o
|
||||
nouveau-y += core/engine/graph/ctxnve0.o
|
||||
nouveau-y += core/engine/graph/nv04.o
|
||||
nouveau-y += core/engine/graph/nv10.o
|
||||
nouveau-y += core/engine/graph/nv20.o
|
||||
nouveau-y += core/engine/graph/nv25.o
|
||||
nouveau-y += core/engine/graph/nv2a.o
|
||||
nouveau-y += core/engine/graph/nv30.o
|
||||
nouveau-y += core/engine/graph/nv34.o
|
||||
nouveau-y += core/engine/graph/nv35.o
|
||||
nouveau-y += core/engine/graph/nv40.o
|
||||
nouveau-y += core/engine/graph/nv50.o
|
||||
nouveau-y += core/engine/graph/nvc0.o
|
||||
nouveau-y += core/engine/graph/nve0.o
|
||||
nouveau-y += core/engine/mpeg/nv31.o
|
||||
nouveau-y += core/engine/mpeg/nv40.o
|
||||
nouveau-y += core/engine/mpeg/nv50.o
|
||||
nouveau-y += core/engine/mpeg/nv84.o
|
||||
nouveau-y += core/engine/ppp/nv98.o
|
||||
nouveau-y += core/engine/software/nv04.o
|
||||
nouveau-y += core/engine/software/nv10.o
|
||||
nouveau-y += core/engine/software/nv50.o
|
||||
nouveau-y += core/engine/software/nvc0.o
|
||||
nouveau-y += core/engine/vp/nv84.o
|
||||
|
||||
# drm/core
|
||||
nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
|
||||
nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o
|
||||
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
|
||||
nouveau-y += nouveau_prime.o nouveau_abi16.o
|
||||
nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
|
||||
|
||||
# drm/kms
|
||||
nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
|
||||
nouveau-y += nouveau_connector.o nouveau_hdmi.o nouveau_dp.o
|
||||
nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
|
||||
|
||||
# drm/kms/nv04:nv50
|
||||
nouveau-y += nouveau_hw.o nouveau_calc.o
|
||||
nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
|
||||
nouveau-y += nv04_crtc.o nv04_display.o nv04_cursor.o
|
||||
|
||||
# drm/kms/nv50-
|
||||
nouveau-y += nv50_display.o nvd0_display.o
|
||||
nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
|
||||
nouveau-y += nv50_evo.o
|
||||
|
||||
# drm/pm
|
||||
nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
|
||||
nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
|
||||
nouveau-y += nouveau_mem.o
|
||||
|
||||
# other random bits
|
||||
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
|
||||
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
|
||||
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
|
||||
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
|
||||
|
||||
obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/client.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/option.h>
|
||||
|
||||
#include <subdev/device.h>
|
||||
|
||||
static void
|
||||
nouveau_client_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_client *client = (void *)object;
|
||||
nouveau_object_ref(NULL, &client->device);
|
||||
nouveau_handle_destroy(client->root);
|
||||
nouveau_namedb_destroy(&client->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nouveau_client_oclass = {
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.dtor = nouveau_client_dtor,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_client_create_(const char *name, u64 devname, const char *cfg,
|
||||
const char *dbg, int length, void **pobject)
|
||||
{
|
||||
struct nouveau_object *device;
|
||||
struct nouveau_client *client;
|
||||
int ret;
|
||||
|
||||
device = (void *)nouveau_device_find(devname);
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,
|
||||
NV_CLIENT_CLASS, nouveau_device_sclass,
|
||||
0, length, pobject);
|
||||
client = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_handle_create(nv_object(client), ~0, ~0,
|
||||
nv_object(client), &client->root);
|
||||
if (ret) {
|
||||
nouveau_namedb_destroy(&client->base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* prevent init/fini being called, os in in charge of this */
|
||||
atomic_set(&nv_object(client)->usecount, 2);
|
||||
|
||||
nouveau_object_ref(device, &client->device);
|
||||
snprintf(client->name, sizeof(client->name), "%s", name);
|
||||
client->debug = nouveau_dbgopt(dbg, "CLIENT");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_client_init(struct nouveau_client *client)
|
||||
{
|
||||
int ret;
|
||||
nv_debug(client, "init running\n");
|
||||
ret = nouveau_handle_init(client->root);
|
||||
nv_debug(client, "init completed with %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_client_fini(struct nouveau_client *client, bool suspend)
|
||||
{
|
||||
const char *name[2] = { "fini", "suspend" };
|
||||
int ret;
|
||||
|
||||
nv_debug(client, "%s running\n", name[suspend]);
|
||||
ret = nouveau_handle_fini(client->root, suspend);
|
||||
nv_debug(client, "%s completed with %d\n", name[suspend], ret);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/client.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <subdev/vm.h>
|
||||
|
||||
static inline int
|
||||
nouveau_engctx_exists(struct nouveau_object *parent,
|
||||
struct nouveau_engine *engine, void **pobject)
|
||||
{
|
||||
struct nouveau_engctx *engctx;
|
||||
struct nouveau_object *parctx;
|
||||
|
||||
list_for_each_entry(engctx, &engine->contexts, head) {
|
||||
parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
|
||||
if (parctx == parent) {
|
||||
atomic_inc(&nv_object(engctx)->refcount);
|
||||
*pobject = engctx;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_engctx_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engobj,
|
||||
struct nouveau_oclass *oclass,
|
||||
struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_client *client = nouveau_client(parent);
|
||||
struct nouveau_engine *engine = nv_engine(engobj);
|
||||
struct nouveau_object *engctx;
|
||||
unsigned long save;
|
||||
int ret;
|
||||
|
||||
/* check if this engine already has a context for the parent object,
|
||||
* and reference it instead of creating a new one
|
||||
*/
|
||||
spin_lock_irqsave(&engine->lock, save);
|
||||
ret = nouveau_engctx_exists(parent, engine, pobject);
|
||||
spin_unlock_irqrestore(&engine->lock, save);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* create the new context, supports creating both raw objects and
|
||||
* objects backed by instance memory
|
||||
*/
|
||||
if (size) {
|
||||
ret = nouveau_gpuobj_create_(parent, engobj, oclass,
|
||||
NV_ENGCTX_CLASS,
|
||||
pargpu, size, align, flags,
|
||||
length, pobject);
|
||||
} else {
|
||||
ret = nouveau_object_create_(parent, engobj, oclass,
|
||||
NV_ENGCTX_CLASS, length, pobject);
|
||||
}
|
||||
|
||||
engctx = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* must take the lock again and re-check a context doesn't already
|
||||
* exist (in case of a race) - the lock had to be dropped before as
|
||||
* it's not possible to allocate the object with it held.
|
||||
*/
|
||||
spin_lock_irqsave(&engine->lock, save);
|
||||
ret = nouveau_engctx_exists(parent, engine, pobject);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&engine->lock, save);
|
||||
nouveau_object_ref(NULL, &engctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (client->vm)
|
||||
atomic_inc(&client->vm->engref[nv_engidx(engobj)]);
|
||||
list_add(&nv_engctx(engctx)->head, &engine->contexts);
|
||||
nv_engctx(engctx)->addr = ~0ULL;
|
||||
spin_unlock_irqrestore(&engine->lock, save);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_engctx_destroy(struct nouveau_engctx *engctx)
|
||||
{
|
||||
struct nouveau_object *engobj = nv_object(engctx)->engine;
|
||||
struct nouveau_engine *engine = nv_engine(engobj);
|
||||
struct nouveau_client *client = nouveau_client(engctx);
|
||||
unsigned long save;
|
||||
|
||||
nouveau_gpuobj_unmap(&engctx->vma);
|
||||
spin_lock_irqsave(&engine->lock, save);
|
||||
list_del(&engctx->head);
|
||||
spin_unlock_irqrestore(&engine->lock, save);
|
||||
|
||||
if (client->vm)
|
||||
atomic_dec(&client->vm->engref[nv_engidx(engobj)]);
|
||||
|
||||
if (engctx->base.size)
|
||||
nouveau_gpuobj_destroy(&engctx->base);
|
||||
else
|
||||
nouveau_object_destroy(&engctx->base.base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_engctx_init(struct nouveau_engctx *engctx)
|
||||
{
|
||||
struct nouveau_object *object = nv_object(engctx);
|
||||
struct nouveau_subdev *subdev = nv_subdev(object->engine);
|
||||
struct nouveau_object *parent;
|
||||
struct nouveau_subdev *pardev;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_init(&engctx->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
|
||||
pardev = nv_subdev(parent->engine);
|
||||
if (nv_parent(parent)->context_attach) {
|
||||
mutex_lock(&pardev->mutex);
|
||||
ret = nv_parent(parent)->context_attach(parent, object);
|
||||
mutex_unlock(&pardev->mutex);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
nv_error(parent, "failed to attach %s context, %d\n",
|
||||
subdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(parent, "attached %s context\n", subdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
|
||||
{
|
||||
struct nouveau_object *object = nv_object(engctx);
|
||||
struct nouveau_subdev *subdev = nv_subdev(object->engine);
|
||||
struct nouveau_object *parent;
|
||||
struct nouveau_subdev *pardev;
|
||||
int ret = 0;
|
||||
|
||||
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
|
||||
pardev = nv_subdev(parent->engine);
|
||||
if (nv_parent(parent)->context_detach) {
|
||||
mutex_lock(&pardev->mutex);
|
||||
ret = nv_parent(parent)->context_detach(parent, suspend, object);
|
||||
mutex_unlock(&pardev->mutex);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
nv_error(parent, "failed to detach %s context, %d\n",
|
||||
subdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(parent, "detached %s context\n", subdev->name);
|
||||
return nouveau_gpuobj_fini(&engctx->base, suspend);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_engctx_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_engctx_destroy(nv_engctx(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_engctx_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_engctx_init(nv_engctx(object));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_nouveau_engctx_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_engctx_fini(nv_engctx(object), suspend);
|
||||
}
|
||||
|
||||
struct nouveau_object *
|
||||
nouveau_engctx_get(struct nouveau_engine *engine, u64 addr)
|
||||
{
|
||||
struct nouveau_engctx *engctx;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&engine->lock, flags);
|
||||
list_for_each_entry(engctx, &engine->contexts, head) {
|
||||
if (engctx->addr == addr) {
|
||||
engctx->save = flags;
|
||||
return nv_object(engctx);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&engine->lock, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_engctx_put(struct nouveau_object *object)
|
||||
{
|
||||
if (object) {
|
||||
struct nouveau_engine *engine = nv_engine(object->engine);
|
||||
struct nouveau_engctx *engctx = nv_engctx(object);
|
||||
spin_unlock_irqrestore(&engine->lock, engctx->save);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/device.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/option.h>
|
||||
|
||||
int
|
||||
nouveau_engine_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engobj,
|
||||
struct nouveau_oclass *oclass, bool enable,
|
||||
const char *iname, const char *fname,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
struct nouveau_engine *engine;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
|
||||
iname, fname, length, pobject);
|
||||
engine = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!nouveau_boolopt(device->cfgopt, iname, enable)) {
|
||||
if (!enable)
|
||||
nv_warn(engine, "disabled, %s=1 to enable\n", iname);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&engine->contexts);
|
||||
spin_lock_init(&engine->lock);
|
||||
return 0;
|
||||
}
|
|
@ -25,27 +25,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include "nouveau_util.h"
|
||||
|
||||
static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
|
||||
|
||||
void
|
||||
nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
{
|
||||
while (bf->name) {
|
||||
if (value & bf->mask) {
|
||||
printk(" %s", bf->name);
|
||||
value &= ~bf->mask;
|
||||
}
|
||||
|
||||
bf++;
|
||||
}
|
||||
|
||||
if (value)
|
||||
printk(" (unknown bits 0x%08x)", value);
|
||||
}
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_find(const struct nouveau_enum *en, u32 value)
|
||||
|
@ -63,16 +44,24 @@ void
|
|||
nouveau_enum_print(const struct nouveau_enum *en, u32 value)
|
||||
{
|
||||
en = nouveau_enum_find(en, value);
|
||||
if (en) {
|
||||
if (en)
|
||||
printk("%s", en->name);
|
||||
return;
|
||||
else
|
||||
printk("(unknown enum 0x%08x)", value);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
{
|
||||
while (bf->name) {
|
||||
if (value & bf->mask) {
|
||||
printk(" %s", bf->name);
|
||||
value &= ~bf->mask;
|
||||
}
|
||||
|
||||
bf++;
|
||||
}
|
||||
|
||||
printk("(unknown enum 0x%08x)", value);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_ratelimit(void)
|
||||
{
|
||||
return __ratelimit(&nouveau_ratelimit_state);
|
||||
if (value)
|
||||
printk(" (unknown bits 0x%08x)", value);
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/vm.h>
|
||||
|
||||
void
|
||||
nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
|
||||
for (i = 0; i < gpuobj->size; i += 4)
|
||||
nv_wo32(gpuobj, i, 0x00000000);
|
||||
}
|
||||
|
||||
if (gpuobj->heap.block_size)
|
||||
nouveau_mm_fini(&gpuobj->heap);
|
||||
|
||||
nouveau_object_destroy(&gpuobj->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_instmem *imem = nouveau_instmem(parent);
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
struct nouveau_mm *heap = NULL;
|
||||
int ret, i;
|
||||
u64 addr;
|
||||
|
||||
*pobject = NULL;
|
||||
|
||||
if (pargpu) {
|
||||
while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
|
||||
if (nv_gpuobj(pargpu)->heap.block_size)
|
||||
break;
|
||||
pargpu = pargpu->parent;
|
||||
}
|
||||
|
||||
if (unlikely(pargpu == NULL)) {
|
||||
nv_error(parent, "no gpuobj heap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr = nv_gpuobj(pargpu)->addr;
|
||||
heap = &nv_gpuobj(pargpu)->heap;
|
||||
atomic_inc(&parent->refcount);
|
||||
} else {
|
||||
ret = imem->alloc(imem, parent, size, align, &parent);
|
||||
pargpu = parent;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = nv_memobj(pargpu)->addr;
|
||||
size = nv_memobj(pargpu)->size;
|
||||
|
||||
if (bar && bar->alloc) {
|
||||
struct nouveau_instobj *iobj = (void *)parent;
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
struct nouveau_mem *node = *mem;
|
||||
if (!bar->alloc(bar, parent, node, &pargpu)) {
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
parent = pargpu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_GPUOBJ_CLASS, length, pobject);
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
gpuobj = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpuobj->parent = pargpu;
|
||||
gpuobj->flags = flags;
|
||||
gpuobj->addr = addr;
|
||||
gpuobj->size = size;
|
||||
|
||||
if (heap) {
|
||||
ret = nouveau_mm_head(heap, 1, size, size,
|
||||
max(align, (u32)1), &gpuobj->node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpuobj->addr += gpuobj->node->offset;
|
||||
}
|
||||
|
||||
if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
|
||||
ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
|
||||
for (i = 0; i < gpuobj->size; i += 4)
|
||||
nv_wo32(gpuobj, i, 0x00000000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct nouveau_gpuobj_class {
|
||||
struct nouveau_object *pargpu;
|
||||
u64 size;
|
||||
u32 align;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static int
|
||||
_nouveau_gpuobj_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_gpuobj_class *args = data;
|
||||
struct nouveau_gpuobj *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
|
||||
args->size, args->align, args->flags,
|
||||
&object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_gpuobj_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_gpuobj_destroy(nv_gpuobj(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_gpuobj_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_gpuobj_init(nv_gpuobj(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
|
||||
}
|
||||
|
||||
u32
|
||||
_nouveau_gpuobj_rd32(struct nouveau_object *object, u32 addr)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
|
||||
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
|
||||
if (gpuobj->node)
|
||||
addr += gpuobj->node->offset;
|
||||
return pfuncs->rd32(gpuobj->parent, addr);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_gpuobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
|
||||
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
|
||||
if (gpuobj->node)
|
||||
addr += gpuobj->node->offset;
|
||||
pfuncs->wr32(gpuobj->parent, addr, data);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
_nouveau_gpuobj_oclass = {
|
||||
.handle = 0x00000000,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = _nouveau_gpuobj_ctor,
|
||||
.dtor = _nouveau_gpuobj_dtor,
|
||||
.init = _nouveau_gpuobj_init,
|
||||
.fini = _nouveau_gpuobj_fini,
|
||||
.rd32 = _nouveau_gpuobj_rd32,
|
||||
.wr32 = _nouveau_gpuobj_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
struct nouveau_object *engine = parent;
|
||||
struct nouveau_gpuobj_class args = {
|
||||
.pargpu = pargpu,
|
||||
.size = size,
|
||||
.align = align,
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
if (!nv_iclass(engine, NV_SUBDEV_CLASS))
|
||||
engine = engine->engine;
|
||||
BUG_ON(engine == NULL);
|
||||
|
||||
return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
|
||||
&args, sizeof(args),
|
||||
(struct nouveau_object **)pgpuobj);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
|
||||
struct nouveau_vma *vma)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(gpuobj);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (bar && bar->umap) {
|
||||
struct nouveau_instobj *iobj = (void *)
|
||||
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
ret = bar->umap(bar, *mem, access, vma);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
|
||||
u32 access, struct nouveau_vma *vma)
|
||||
{
|
||||
struct nouveau_instobj *iobj = (void *)
|
||||
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_vm_map(vma, *mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_gpuobj_unmap(struct nouveau_vma *vma)
|
||||
{
|
||||
if (vma->node) {
|
||||
nouveau_vm_unmap(vma);
|
||||
nouveau_vm_put(vma);
|
||||
}
|
||||
}
|
||||
|
||||
/* the below is basically only here to support sharing the paged dma object
|
||||
* for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
|
||||
* anywhere else.
|
||||
*/
|
||||
|
||||
static void
|
||||
nouveau_gpudup_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = (void *)object;
|
||||
nouveau_object_ref(NULL, &gpuobj->parent);
|
||||
nouveau_object_destroy(&gpuobj->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nouveau_gpudup_oclass = {
|
||||
.handle = NV_GPUOBJ_CLASS,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.dtor = nouveau_gpudup_dtor,
|
||||
.init = nouveau_object_init,
|
||||
.fini = nouveau_object_fini,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create(parent, parent->engine,
|
||||
&nouveau_gpudup_oclass, 0, &gpuobj);
|
||||
*pgpuobj = gpuobj;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_object_ref(nv_object(base), &gpuobj->parent);
|
||||
gpuobj->addr = base->addr;
|
||||
gpuobj->size = base->size;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/client.h>
|
||||
|
||||
#define hprintk(h,l,f,a...) do { \
|
||||
struct nouveau_client *c = nouveau_client((h)->object); \
|
||||
struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
|
||||
nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
|
||||
} while(0)
|
||||
|
||||
int
|
||||
nouveau_handle_init(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_handle *item;
|
||||
int ret;
|
||||
|
||||
hprintk(handle, TRACE, "init running\n");
|
||||
ret = nouveau_object_inc(handle->object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hprintk(handle, TRACE, "init children\n");
|
||||
list_for_each_entry(item, &handle->tree, head) {
|
||||
ret = nouveau_handle_init(item);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "init completed\n");
|
||||
return 0;
|
||||
fail:
|
||||
hprintk(handle, ERROR, "init failed with %d\n", ret);
|
||||
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
|
||||
nouveau_handle_fini(item, false);
|
||||
}
|
||||
|
||||
nouveau_object_dec(handle->object, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
|
||||
{
|
||||
static char *name[2] = { "fini", "suspend" };
|
||||
struct nouveau_handle *item;
|
||||
int ret;
|
||||
|
||||
hprintk(handle, TRACE, "%s children\n", name[suspend]);
|
||||
list_for_each_entry(item, &handle->tree, head) {
|
||||
ret = nouveau_handle_fini(item, suspend);
|
||||
if (ret && suspend)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "%s running\n", name[suspend]);
|
||||
if (handle->object) {
|
||||
ret = nouveau_object_dec(handle->object, suspend);
|
||||
if (ret && suspend)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "%s completed\n", name[suspend]);
|
||||
return 0;
|
||||
fail:
|
||||
hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
|
||||
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
|
||||
int rret = nouveau_handle_init(item);
|
||||
if (rret)
|
||||
hprintk(handle, FATAL, "failed to restart, %d\n", rret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
|
||||
struct nouveau_object *object,
|
||||
struct nouveau_handle **phandle)
|
||||
{
|
||||
struct nouveau_object *namedb;
|
||||
struct nouveau_handle *handle;
|
||||
int ret;
|
||||
|
||||
namedb = parent;
|
||||
while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
|
||||
namedb = namedb->parent;
|
||||
|
||||
handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&handle->head);
|
||||
INIT_LIST_HEAD(&handle->tree);
|
||||
handle->name = _handle;
|
||||
handle->priv = ~0;
|
||||
|
||||
ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
|
||||
if (ret) {
|
||||
kfree(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (nv_parent(parent)->object_attach) {
|
||||
ret = nv_parent(parent)->object_attach(parent, object, _handle);
|
||||
if (ret < 0) {
|
||||
nouveau_handle_destroy(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
handle->priv = ret;
|
||||
}
|
||||
|
||||
if (object != namedb) {
|
||||
while (!nv_iclass(namedb, NV_CLIENT_CLASS))
|
||||
namedb = namedb->parent;
|
||||
|
||||
handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
|
||||
if (handle->parent) {
|
||||
list_add(&handle->head, &handle->parent->tree);
|
||||
nouveau_namedb_put(handle->parent);
|
||||
}
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "created\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_handle_destroy(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_handle *item, *temp;
|
||||
|
||||
hprintk(handle, TRACE, "destroy running\n");
|
||||
list_for_each_entry_safe(item, temp, &handle->tree, head) {
|
||||
nouveau_handle_destroy(item);
|
||||
}
|
||||
list_del(&handle->head);
|
||||
|
||||
if (handle->priv != ~0) {
|
||||
struct nouveau_object *parent = handle->parent->object;
|
||||
nv_parent(parent)->object_detach(parent, handle->priv);
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "destroy completed\n");
|
||||
nouveau_namedb_remove(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
struct nouveau_object *
|
||||
nouveau_handle_ref(struct nouveau_object *parent, u32 name)
|
||||
{
|
||||
struct nouveau_object *object = NULL;
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
while (!nv_iclass(parent, NV_NAMEDB_CLASS))
|
||||
parent = parent->parent;
|
||||
|
||||
handle = nouveau_namedb_get(nv_namedb(parent), name);
|
||||
if (handle) {
|
||||
nouveau_object_ref(handle->object, &object);
|
||||
nouveau_namedb_put(handle);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
|
||||
{
|
||||
struct nouveau_namedb *namedb;
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_class(namedb, oclass);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
|
||||
{
|
||||
struct nouveau_namedb *namedb;
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_vinst(namedb, vinst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
|
||||
{
|
||||
struct nouveau_namedb *namedb;
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_cinst(namedb, cinst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_handle_put(struct nouveau_handle *handle)
|
||||
{
|
||||
if (handle)
|
||||
nouveau_namedb_put(handle);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2010 Red Hat Inc.
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -22,20 +22,52 @@
|
|||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "nouveau_drv.h"
|
||||
#include "nouveau_mm.h"
|
||||
#include "core/os.h"
|
||||
#include "core/mm.h"
|
||||
|
||||
static inline void
|
||||
region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a)
|
||||
#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
|
||||
list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
|
||||
|
||||
void
|
||||
nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
|
||||
{
|
||||
list_del(&a->nl_entry);
|
||||
list_del(&a->fl_entry);
|
||||
kfree(a);
|
||||
struct nouveau_mm_node *this = *pthis;
|
||||
|
||||
if (this) {
|
||||
struct nouveau_mm_node *prev = node(this, prev);
|
||||
struct nouveau_mm_node *next = node(this, next);
|
||||
|
||||
if (prev && prev->type == 0) {
|
||||
prev->length += this->length;
|
||||
list_del(&this->nl_entry);
|
||||
kfree(this); this = prev;
|
||||
}
|
||||
|
||||
if (next && next->type == 0) {
|
||||
next->offset = this->offset;
|
||||
next->length += this->length;
|
||||
if (this->type == 0)
|
||||
list_del(&this->fl_entry);
|
||||
list_del(&this->nl_entry);
|
||||
kfree(this); this = NULL;
|
||||
}
|
||||
|
||||
if (this && this->type != 0) {
|
||||
list_for_each_entry(prev, &mm->free, fl_entry) {
|
||||
if (this->offset < prev->offset)
|
||||
break;
|
||||
}
|
||||
|
||||
list_add_tail(&this->fl_entry, &prev->fl_entry);
|
||||
this->type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*pthis = NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_mm_node *
|
||||
region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
|
||||
region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
|
||||
{
|
||||
struct nouveau_mm_node *b;
|
||||
|
||||
|
@ -57,38 +89,12 @@ region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
|
|||
return b;
|
||||
}
|
||||
|
||||
#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
|
||||
list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
|
||||
|
||||
void
|
||||
nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this)
|
||||
{
|
||||
struct nouveau_mm_node *prev = node(this, prev);
|
||||
struct nouveau_mm_node *next = node(this, next);
|
||||
|
||||
list_add(&this->fl_entry, &mm->free);
|
||||
this->type = 0;
|
||||
|
||||
if (prev && prev->type == 0) {
|
||||
prev->length += this->length;
|
||||
region_put(mm, this);
|
||||
this = prev;
|
||||
}
|
||||
|
||||
if (next && next->type == 0) {
|
||||
next->offset = this->offset;
|
||||
next->length += this->length;
|
||||
region_put(mm, this);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc,
|
||||
u32 align, struct nouveau_mm_node **pnode)
|
||||
nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
|
||||
u32 align, struct nouveau_mm_node **pnode)
|
||||
{
|
||||
struct nouveau_mm_node *prev, *this, *next;
|
||||
u32 min = size_nc ? size_nc : size;
|
||||
u32 align_mask = align - 1;
|
||||
u32 mask = align - 1;
|
||||
u32 splitoff;
|
||||
u32 s, e;
|
||||
|
||||
|
@ -104,16 +110,86 @@ nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc,
|
|||
if (next && next->type != type)
|
||||
e = rounddown(e, mm->block_size);
|
||||
|
||||
s = (s + align_mask) & ~align_mask;
|
||||
e &= ~align_mask;
|
||||
if (s > e || e - s < min)
|
||||
s = (s + mask) & ~mask;
|
||||
e &= ~mask;
|
||||
if (s > e || e - s < size_min)
|
||||
continue;
|
||||
|
||||
splitoff = s - this->offset;
|
||||
if (splitoff && !region_split(mm, this, splitoff))
|
||||
if (splitoff && !region_head(mm, this, splitoff))
|
||||
return -ENOMEM;
|
||||
|
||||
this = region_split(mm, this, min(size, e - s));
|
||||
this = region_head(mm, this, min(size_max, e - s));
|
||||
if (!this)
|
||||
return -ENOMEM;
|
||||
|
||||
this->type = type;
|
||||
list_del(&this->fl_entry);
|
||||
*pnode = this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static struct nouveau_mm_node *
|
||||
region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
|
||||
{
|
||||
struct nouveau_mm_node *b;
|
||||
|
||||
if (a->length == size)
|
||||
return a;
|
||||
|
||||
b = kmalloc(sizeof(*b), GFP_KERNEL);
|
||||
if (unlikely(b == NULL))
|
||||
return NULL;
|
||||
|
||||
a->length -= size;
|
||||
b->offset = a->offset + a->length;
|
||||
b->length = size;
|
||||
b->type = a->type;
|
||||
|
||||
list_add(&b->nl_entry, &a->nl_entry);
|
||||
if (b->type == 0)
|
||||
list_add(&b->fl_entry, &a->fl_entry);
|
||||
return b;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
|
||||
u32 align, struct nouveau_mm_node **pnode)
|
||||
{
|
||||
struct nouveau_mm_node *prev, *this, *next;
|
||||
u32 mask = align - 1;
|
||||
|
||||
list_for_each_entry_reverse(this, &mm->free, fl_entry) {
|
||||
u32 e = this->offset + this->length;
|
||||
u32 s = this->offset;
|
||||
u32 c = 0, a;
|
||||
|
||||
prev = node(this, prev);
|
||||
if (prev && prev->type != type)
|
||||
s = roundup(s, mm->block_size);
|
||||
|
||||
next = node(this, next);
|
||||
if (next && next->type != type) {
|
||||
e = rounddown(e, mm->block_size);
|
||||
c = next->offset - e;
|
||||
}
|
||||
|
||||
s = (s + mask) & ~mask;
|
||||
a = e - s;
|
||||
if (s > e || a < size_min)
|
||||
continue;
|
||||
|
||||
a = min(a, size_max);
|
||||
s = (e - a) & ~mask;
|
||||
c += (e - s) - a;
|
||||
|
||||
if (c && !region_tail(mm, this, c))
|
||||
return -ENOMEM;
|
||||
|
||||
this = region_tail(mm, this, a);
|
||||
if (!this)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -148,6 +224,7 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
|
|||
list_add_tail(&node->nl_entry, &mm->nodes);
|
||||
list_add_tail(&node->fl_entry, &mm->free);
|
||||
mm->heap_nodes++;
|
||||
mm->heap_size += length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -159,15 +236,8 @@ nouveau_mm_fini(struct nouveau_mm *mm)
|
|||
int nodes = 0;
|
||||
|
||||
list_for_each_entry(node, &mm->nodes, nl_entry) {
|
||||
if (nodes++ == mm->heap_nodes) {
|
||||
printk(KERN_ERR "nouveau_mm in use at destroy time!\n");
|
||||
list_for_each_entry(node, &mm->nodes, nl_entry) {
|
||||
printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n",
|
||||
node->type, node->offset, node->length);
|
||||
}
|
||||
WARN_ON(1);
|
||||
if (nodes++ == mm->heap_nodes)
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(heap);
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (handle->name == name)
|
||||
return handle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_mclass(handle->object) == oclass)
|
||||
return handle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
|
||||
if (nv_gpuobj(handle->object)->addr == vinst)
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
|
||||
if (nv_gpuobj(handle->object)->node &&
|
||||
nv_gpuobj(handle->object)->node->offset == cinst)
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,
|
||||
struct nouveau_object *object,
|
||||
struct nouveau_handle *handle)
|
||||
{
|
||||
int ret = -EEXIST;
|
||||
write_lock_irq(&namedb->lock);
|
||||
if (!nouveau_namedb_lookup(namedb, name)) {
|
||||
nouveau_object_ref(object, &handle->object);
|
||||
handle->namedb = namedb;
|
||||
list_add(&handle->node, &namedb->list);
|
||||
ret = 0;
|
||||
}
|
||||
write_unlock_irq(&namedb->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_namedb_remove(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_namedb *namedb = handle->namedb;
|
||||
struct nouveau_object *object = handle->object;
|
||||
write_lock_irq(&namedb->lock);
|
||||
list_del(&handle->node);
|
||||
write_unlock_irq(&namedb->lock);
|
||||
nouveau_object_ref(NULL, &object);
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup(namedb, name);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_class(namedb, oclass);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_vinst(namedb, vinst);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_cinst(namedb, cinst);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_namedb_put(struct nouveau_handle *handle)
|
||||
{
|
||||
if (handle)
|
||||
read_unlock(&handle->namedb->lock);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_namedb_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_oclass *sclass, u32 engcls,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_namedb *namedb;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_parent_create_(parent, engine, oclass, pclass |
|
||||
NV_NAMEDB_CLASS, sclass, engcls,
|
||||
length, pobject);
|
||||
namedb = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rwlock_init(&namedb->lock);
|
||||
INIT_LIST_HEAD(&namedb->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_namedb_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_namedb *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/parent.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/engine.h>
|
||||
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
|
||||
static DEFINE_SPINLOCK(_objlist_lock);
|
||||
#endif
|
||||
|
||||
int
|
||||
nouveau_object_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_object *object;
|
||||
|
||||
object = *pobject = kzalloc(size, GFP_KERNEL);
|
||||
if (!object)
|
||||
return -ENOMEM;
|
||||
|
||||
nouveau_object_ref(parent, &object->parent);
|
||||
nouveau_object_ref(engine, &object->engine);
|
||||
object->oclass = oclass;
|
||||
object->oclass->handle |= pclass;
|
||||
atomic_set(&object->refcount, 1);
|
||||
atomic_set(&object->usecount, 0);
|
||||
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
object->_magic = NOUVEAU_OBJECT_MAGIC;
|
||||
spin_lock(&_objlist_lock);
|
||||
list_add(&object->list, &_objlist);
|
||||
spin_unlock(&_objlist_lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_nouveau_object_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_object *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create(parent, engine, oclass, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_destroy(struct nouveau_object *object)
|
||||
{
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
spin_lock(&_objlist_lock);
|
||||
list_del(&object->list);
|
||||
spin_unlock(&_objlist_lock);
|
||||
#endif
|
||||
nouveau_object_ref(NULL, &object->engine);
|
||||
nouveau_object_ref(NULL, &object->parent);
|
||||
kfree(object);
|
||||
}
|
||||
|
||||
static void
|
||||
_nouveau_object_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_object_destroy(object);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_init(struct nouveau_object *object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_nouveau_object_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_object_init(object);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_nouveau_object_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_object_fini(object, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_ofuncs
|
||||
nouveau_object_ofuncs = {
|
||||
.ctor = _nouveau_object_ctor,
|
||||
.dtor = _nouveau_object_dtor,
|
||||
.init = _nouveau_object_init,
|
||||
.fini = _nouveau_object_fini,
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_object_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
|
||||
int ret;
|
||||
|
||||
*pobject = NULL;
|
||||
|
||||
ret = ofuncs->ctor(parent, engine, oclass, data, size, pobject);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENODEV) {
|
||||
nv_error(parent, "failed to create 0x%08x, %d\n",
|
||||
oclass->handle, ret);
|
||||
}
|
||||
|
||||
if (*pobject) {
|
||||
ofuncs->dtor(*pobject);
|
||||
*pobject = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(*pobject, "created\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_object_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nv_debug(object, "destroying\n");
|
||||
nv_ofuncs(object)->dtor(object);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
|
||||
{
|
||||
if (obj) {
|
||||
atomic_inc(&obj->refcount);
|
||||
nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
|
||||
}
|
||||
|
||||
if (*ref) {
|
||||
int dead = atomic_dec_and_test(&(*ref)->refcount);
|
||||
nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
|
||||
if (dead)
|
||||
nouveau_object_dtor(*ref);
|
||||
}
|
||||
|
||||
*ref = obj;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle,
|
||||
u16 _oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_object *parent = NULL;
|
||||
struct nouveau_object *engctx = NULL;
|
||||
struct nouveau_object *object = NULL;
|
||||
struct nouveau_object *engine;
|
||||
struct nouveau_oclass *oclass;
|
||||
struct nouveau_handle *handle;
|
||||
int ret;
|
||||
|
||||
/* lookup parent object and ensure it *is* a parent */
|
||||
parent = nouveau_handle_ref(client, _parent);
|
||||
if (!parent) {
|
||||
nv_error(client, "parent 0x%08x not found\n", _parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!nv_iclass(parent, NV_PARENT_CLASS)) {
|
||||
nv_error(parent, "cannot have children\n");
|
||||
ret = -EINVAL;
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* check that parent supports the requested subclass */
|
||||
ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
|
||||
if (ret) {
|
||||
nv_debug(parent, "illegal class 0x%04x\n", _oclass);
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* make sure engine init has been completed *before* any objects
|
||||
* it controls are created - the constructors may depend on
|
||||
* state calculated at init (ie. default context construction)
|
||||
*/
|
||||
if (engine) {
|
||||
ret = nouveau_object_inc(engine);
|
||||
if (ret)
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* if engine requires it, create a context object to insert
|
||||
* between the parent and its children (eg. PGRAPH context)
|
||||
*/
|
||||
if (engine && nv_engine(engine)->cclass) {
|
||||
ret = nouveau_object_ctor(parent, engine,
|
||||
nv_engine(engine)->cclass,
|
||||
data, size, &engctx);
|
||||
if (ret)
|
||||
goto fail_engctx;
|
||||
} else {
|
||||
nouveau_object_ref(parent, &engctx);
|
||||
}
|
||||
|
||||
/* finally, create new object and bind it to its handle */
|
||||
ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
|
||||
*pobject = object;
|
||||
if (ret)
|
||||
goto fail_ctor;
|
||||
|
||||
ret = nouveau_object_inc(object);
|
||||
if (ret)
|
||||
goto fail_init;
|
||||
|
||||
ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
|
||||
if (ret)
|
||||
goto fail_handle;
|
||||
|
||||
ret = nouveau_handle_init(handle);
|
||||
if (ret)
|
||||
nouveau_handle_destroy(handle);
|
||||
|
||||
fail_handle:
|
||||
nouveau_object_dec(object, false);
|
||||
fail_init:
|
||||
nouveau_object_ref(NULL, &object);
|
||||
fail_ctor:
|
||||
nouveau_object_ref(NULL, &engctx);
|
||||
fail_engctx:
|
||||
if (engine)
|
||||
nouveau_object_dec(engine, false);
|
||||
fail_class:
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
|
||||
{
|
||||
struct nouveau_object *parent = NULL;
|
||||
struct nouveau_object *namedb = NULL;
|
||||
struct nouveau_handle *handle = NULL;
|
||||
int ret = -EINVAL;
|
||||
|
||||
parent = nouveau_handle_ref(client, _parent);
|
||||
if (!parent)
|
||||
return -ENOENT;
|
||||
|
||||
namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
|
||||
if (namedb) {
|
||||
handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
|
||||
if (handle) {
|
||||
nouveau_namedb_put(handle);
|
||||
nouveau_handle_fini(handle, false);
|
||||
nouveau_handle_destroy(handle);
|
||||
}
|
||||
}
|
||||
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_inc(struct nouveau_object *object)
|
||||
{
|
||||
int ref = atomic_add_return(1, &object->usecount);
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
|
||||
if (ref != 1)
|
||||
return 0;
|
||||
|
||||
nv_trace(object, "initialising...\n");
|
||||
if (object->parent) {
|
||||
ret = nouveau_object_inc(object->parent);
|
||||
if (ret) {
|
||||
nv_error(object, "parent failed, %d\n", ret);
|
||||
goto fail_parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
ret = nouveau_object_inc(object->engine);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (ret) {
|
||||
nv_error(object, "engine failed, %d\n", ret);
|
||||
goto fail_engine;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nv_ofuncs(object)->init(object);
|
||||
if (ret) {
|
||||
nv_error(object, "init failed, %d\n", ret);
|
||||
goto fail_self;
|
||||
}
|
||||
|
||||
nv_debug(object, "initialised\n");
|
||||
return 0;
|
||||
|
||||
fail_self:
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
nouveau_object_dec(object->engine, false);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
}
|
||||
fail_engine:
|
||||
if (object->parent)
|
||||
nouveau_object_dec(object->parent, false);
|
||||
fail_parent:
|
||||
atomic_dec(&object->usecount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_object_decf(struct nouveau_object *object)
|
||||
{
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "stopping...\n");
|
||||
|
||||
ret = nv_ofuncs(object)->fini(object, false);
|
||||
if (ret)
|
||||
nv_warn(object, "failed fini, %d\n", ret);
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
nouveau_object_dec(object->engine, false);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
}
|
||||
|
||||
if (object->parent)
|
||||
nouveau_object_dec(object->parent, false);
|
||||
|
||||
nv_debug(object, "stopped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_object_decs(struct nouveau_object *object)
|
||||
{
|
||||
int ret, rret;
|
||||
|
||||
nv_trace(object, "suspending...\n");
|
||||
|
||||
ret = nv_ofuncs(object)->fini(object, true);
|
||||
if (ret) {
|
||||
nv_error(object, "failed suspend, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
ret = nouveau_object_dec(object->engine, true);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (ret) {
|
||||
nv_warn(object, "engine failed suspend, %d\n", ret);
|
||||
goto fail_engine;
|
||||
}
|
||||
}
|
||||
|
||||
if (object->parent) {
|
||||
ret = nouveau_object_dec(object->parent, true);
|
||||
if (ret) {
|
||||
nv_warn(object, "parent failed suspend, %d\n", ret);
|
||||
goto fail_parent;
|
||||
}
|
||||
}
|
||||
|
||||
nv_debug(object, "suspended\n");
|
||||
return 0;
|
||||
|
||||
fail_parent:
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
rret = nouveau_object_inc(object->engine);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (rret)
|
||||
nv_fatal(object, "engine failed to reinit, %d\n", rret);
|
||||
}
|
||||
|
||||
fail_engine:
|
||||
rret = nv_ofuncs(object)->init(object);
|
||||
if (rret)
|
||||
nv_fatal(object, "failed to reinit, %d\n", rret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_dec(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
int ref = atomic_add_return(-1, &object->usecount);
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
|
||||
|
||||
if (ref == 0) {
|
||||
if (suspend)
|
||||
ret = nouveau_object_decs(object);
|
||||
else
|
||||
ret = nouveau_object_decf(object);
|
||||
|
||||
if (ret) {
|
||||
atomic_inc(&object->usecount);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_debug(void)
|
||||
{
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
struct nouveau_object *object;
|
||||
if (!list_empty(&_objlist)) {
|
||||
nv_fatal(NULL, "*******************************************\n");
|
||||
nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
|
||||
nv_fatal(NULL, "*******************************************\n");
|
||||
list_for_each_entry(object, &_objlist, list) {
|
||||
nv_fatal(object, "%p/%p/%d/%d\n",
|
||||
object->parent, object->engine,
|
||||
atomic_read(&object->refcount),
|
||||
atomic_read(&object->usecount));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/option.h>
|
||||
#include <core/debug.h>
|
||||
|
||||
/* compares unterminated string 'str' with zero-terminated string 'cmp' */
|
||||
static inline int
|
||||
strncasecmpz(const char *str, const char *cmp, size_t len)
|
||||
{
|
||||
if (strlen(cmp) != len)
|
||||
return len;
|
||||
return strncasecmp(str, cmp, len);
|
||||
}
|
||||
|
||||
const char *
|
||||
nouveau_stropt(const char *optstr, const char *opt, int *arglen)
|
||||
{
|
||||
while (optstr && *optstr != '\0') {
|
||||
int len = strcspn(optstr, ",=");
|
||||
switch (optstr[len]) {
|
||||
case '=':
|
||||
if (!strncasecmpz(optstr, opt, len)) {
|
||||
optstr += len + 1;
|
||||
*arglen = strcspn(optstr, ",=");
|
||||
return *arglen ? optstr : NULL;
|
||||
}
|
||||
optstr++;
|
||||
break;
|
||||
case ',':
|
||||
optstr++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
optstr += len;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
nouveau_boolopt(const char *optstr, const char *opt, bool value)
|
||||
{
|
||||
int arglen;
|
||||
|
||||
optstr = nouveau_stropt(optstr, opt, &arglen);
|
||||
if (optstr) {
|
||||
if (!strncasecmpz(optstr, "0", arglen) ||
|
||||
!strncasecmpz(optstr, "no", arglen) ||
|
||||
!strncasecmpz(optstr, "off", arglen) ||
|
||||
!strncasecmpz(optstr, "false", arglen))
|
||||
value = false;
|
||||
else
|
||||
if (!strncasecmpz(optstr, "1", arglen) ||
|
||||
!strncasecmpz(optstr, "yes", arglen) ||
|
||||
!strncasecmpz(optstr, "on", arglen) ||
|
||||
!strncasecmpz(optstr, "true", arglen))
|
||||
value = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dbgopt(const char *optstr, const char *sub)
|
||||
{
|
||||
int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
|
||||
|
||||
while (optstr) {
|
||||
int len = strcspn(optstr, ",=");
|
||||
switch (optstr[len]) {
|
||||
case '=':
|
||||
if (strncasecmpz(optstr, sub, len))
|
||||
mode = 0;
|
||||
optstr++;
|
||||
break;
|
||||
default:
|
||||
if (mode) {
|
||||
if (!strncasecmpz(optstr, "fatal", len))
|
||||
level = NV_DBG_FATAL;
|
||||
else if (!strncasecmpz(optstr, "error", len))
|
||||
level = NV_DBG_ERROR;
|
||||
else if (!strncasecmpz(optstr, "warn", len))
|
||||
level = NV_DBG_WARN;
|
||||
else if (!strncasecmpz(optstr, "info", len))
|
||||
level = NV_DBG_INFO;
|
||||
else if (!strncasecmpz(optstr, "debug", len))
|
||||
level = NV_DBG_DEBUG;
|
||||
else if (!strncasecmpz(optstr, "trace", len))
|
||||
level = NV_DBG_TRACE;
|
||||
else if (!strncasecmpz(optstr, "paranoia", len))
|
||||
level = NV_DBG_PARANOIA;
|
||||
else if (!strncasecmpz(optstr, "spam", len))
|
||||
level = NV_DBG_SPAM;
|
||||
}
|
||||
|
||||
if (optstr[len] != '\0') {
|
||||
optstr++;
|
||||
mode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
optstr += len;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/parent.h>
|
||||
|
||||
int
|
||||
nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
|
||||
struct nouveau_object **pengine,
|
||||
struct nouveau_oclass **poclass)
|
||||
{
|
||||
struct nouveau_sclass *sclass;
|
||||
struct nouveau_engine *engine;
|
||||
struct nouveau_oclass *oclass;
|
||||
u64 mask;
|
||||
|
||||
sclass = nv_parent(parent)->sclass;
|
||||
while (sclass) {
|
||||
if ((sclass->oclass->handle & 0xffff) == handle) {
|
||||
*pengine = parent->engine;
|
||||
*poclass = sclass->oclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sclass = sclass->sclass;
|
||||
}
|
||||
|
||||
mask = nv_parent(parent)->engine;
|
||||
while (mask) {
|
||||
int i = ffsll(mask) - 1;
|
||||
|
||||
if ((engine = nouveau_engine(parent, i))) {
|
||||
oclass = engine->sclass;
|
||||
while (oclass->ofuncs) {
|
||||
if ((oclass->handle & 0xffff) == handle) {
|
||||
*pengine = nv_object(engine);
|
||||
*poclass = oclass;
|
||||
return 0;
|
||||
}
|
||||
oclass++;
|
||||
}
|
||||
}
|
||||
|
||||
mask &= ~(1ULL << i);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_parent_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_oclass *sclass, u64 engcls,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_parent *object;
|
||||
struct nouveau_sclass *nclass;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_PARENT_CLASS, size, pobject);
|
||||
object = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (sclass && sclass->ofuncs) {
|
||||
nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
|
||||
if (!nclass)
|
||||
return -ENOMEM;
|
||||
|
||||
nclass->sclass = object->sclass;
|
||||
object->sclass = nclass;
|
||||
nclass->engine = engine ? nv_engine(engine) : NULL;
|
||||
nclass->oclass = sclass;
|
||||
sclass++;
|
||||
}
|
||||
|
||||
object->engine = engcls;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_parent_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_parent *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_parent_create(parent, engine, oclass, 0, NULL, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_parent_destroy(struct nouveau_parent *parent)
|
||||
{
|
||||
struct nouveau_sclass *sclass;
|
||||
|
||||
while ((sclass = parent->sclass)) {
|
||||
parent->sclass = sclass->sclass;
|
||||
kfree(sclass);
|
||||
}
|
||||
|
||||
nouveau_object_destroy(&parent->base);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_nouveau_parent_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_parent_destroy(nv_parent(object));
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/client.h>
|
||||
#include <core/subdev.h>
|
||||
#include <core/printk.h>
|
||||
|
||||
void
|
||||
nv_printk_(struct nouveau_object *object, const char *pfx, int level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
|
||||
char mfmt[256];
|
||||
va_list args;
|
||||
|
||||
if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
|
||||
struct nouveau_object *device = object;
|
||||
struct nouveau_object *subdev = object;
|
||||
char obuf[64], *ofmt = "";
|
||||
|
||||
if (object->engine) {
|
||||
snprintf(obuf, sizeof(obuf), "[0x%08x][%p]",
|
||||
nv_hclass(object), object);
|
||||
ofmt = obuf;
|
||||
subdev = object->engine;
|
||||
device = object->engine;
|
||||
}
|
||||
|
||||
if (subdev->parent)
|
||||
device = subdev->parent;
|
||||
|
||||
if (level > nv_subdev(subdev)->debug)
|
||||
return;
|
||||
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
|
||||
name[level], nv_subdev(subdev)->name,
|
||||
nv_device(device)->name, ofmt, fmt);
|
||||
} else
|
||||
if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
|
||||
if (level > nv_client(object)->debug)
|
||||
return;
|
||||
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
|
||||
name[level], nv_client(object)->name, fmt);
|
||||
} else {
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintk(mfmt, args);
|
||||
va_end(args);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/math.h>
|
||||
|
||||
#include <subdev/bar.h>
|
||||
|
||||
static u32
|
||||
nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
|
||||
{
|
||||
u32 hash = 0;
|
||||
|
||||
while (handle) {
|
||||
hash ^= (handle & ((1 << ramht->bits) - 1));
|
||||
handle >>= ramht->bits;
|
||||
}
|
||||
|
||||
hash ^= chid << (ramht->bits - 4);
|
||||
hash = hash << 3;
|
||||
return hash;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
|
||||
u32 handle, u32 context)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(ramht);
|
||||
u32 co, ho;
|
||||
|
||||
co = ho = nouveau_ramht_hash(ramht, chid, handle);
|
||||
do {
|
||||
if (!nv_ro32(ramht, co + 4)) {
|
||||
nv_wo32(ramht, co + 0, handle);
|
||||
nv_wo32(ramht, co + 4, context);
|
||||
if (bar)
|
||||
bar->flush(bar);
|
||||
return co;
|
||||
}
|
||||
|
||||
co += 8;
|
||||
if (co >= nv_gpuobj(ramht)->size)
|
||||
co = 0;
|
||||
} while (co != ho);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(ramht);
|
||||
nv_wo32(ramht, cookie + 0, 0x00000000);
|
||||
nv_wo32(ramht, cookie + 4, 0x00000000);
|
||||
if (bar)
|
||||
bar->flush(bar);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nouveau_ramht_oclass = {
|
||||
.handle = 0x0000abcd,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = NULL,
|
||||
.dtor = _nouveau_gpuobj_dtor,
|
||||
.init = _nouveau_gpuobj_init,
|
||||
.fini = _nouveau_gpuobj_fini,
|
||||
.rd32 = _nouveau_gpuobj_rd32,
|
||||
.wr32 = _nouveau_gpuobj_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, struct nouveau_ramht **pramht)
|
||||
{
|
||||
struct nouveau_ramht *ramht;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_create(parent, parent->engine ?
|
||||
parent->engine : parent, /* <nv50 ramht */
|
||||
&nouveau_ramht_oclass, 0, pargpu, size,
|
||||
align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
|
||||
*pramht = ramht;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/subdev.h>
|
||||
#include <core/device.h>
|
||||
#include <core/option.h>
|
||||
|
||||
void
|
||||
nouveau_subdev_reset(struct nouveau_object *subdev)
|
||||
{
|
||||
nv_trace(subdev, "resetting...\n");
|
||||
nv_ofuncs(subdev)->fini(subdev, false);
|
||||
nv_debug(subdev, "reset\n");
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_init(struct nouveau_subdev *subdev)
|
||||
{
|
||||
int ret = nouveau_object_init(&subdev->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_subdev_reset(&subdev->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_subdev_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_subdev_init(nv_subdev(object));
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend)
|
||||
{
|
||||
if (subdev->unit) {
|
||||
nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
|
||||
nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
|
||||
}
|
||||
|
||||
return nouveau_object_fini(&subdev->base, suspend);
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_subdev_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_subdev_fini(nv_subdev(object), suspend);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_subdev_destroy(struct nouveau_subdev *subdev)
|
||||
{
|
||||
int subidx = nv_hclass(subdev) & 0xff;
|
||||
nv_device(subdev)->subdev[subidx] = NULL;
|
||||
nouveau_object_destroy(&subdev->base);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_subdev_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_subdev_destroy(nv_subdev(object));
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
const char *subname, const char *sysname,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_subdev *subdev;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_SUBDEV_CLASS, size, pobject);
|
||||
subdev = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&subdev->mutex);
|
||||
subdev->name = subname;
|
||||
|
||||
if (parent) {
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
int subidx = nv_hclass(subdev) & 0xff;
|
||||
|
||||
subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
|
||||
subdev->mmio = nv_subdev(device)->mmio;
|
||||
device->subdev[subidx] = *pobject;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <engine/bsp.h>
|
||||
|
||||
struct nv84_bsp_priv {
|
||||
struct nouveau_bsp base;
|
||||
};
|
||||
|
||||
struct nv84_bsp_chan {
|
||||
struct nouveau_bsp_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* BSP object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_bsp_sclass[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* BSP context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_bsp_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv84_bsp_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bsp_context_create(parent, engine, oclass, NULL,
|
||||
0, 0, 0, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nv84_bsp_context_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv84_bsp_chan *priv = (void *)object;
|
||||
nouveau_bsp_context_destroy(&priv->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_bsp_context_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv84_bsp_chan *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bsp_context_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_bsp_context_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv84_bsp_chan *priv = (void *)object;
|
||||
return nouveau_bsp_context_fini(&priv->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_bsp_cclass = {
|
||||
.handle = NV_ENGCTX(BSP, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_bsp_context_ctor,
|
||||
.dtor = nv84_bsp_context_dtor,
|
||||
.init = nv84_bsp_context_init,
|
||||
.fini = nv84_bsp_context_fini,
|
||||
.rd32 = _nouveau_bsp_context_rd32,
|
||||
.wr32 = _nouveau_bsp_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* BSP engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nv84_bsp_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv84_bsp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bsp_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x04008000;
|
||||
nv_subdev(priv)->intr = nv84_bsp_intr;
|
||||
nv_engine(priv)->cclass = &nv84_bsp_cclass;
|
||||
nv_engine(priv)->sclass = nv84_bsp_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nv84_bsp_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv84_bsp_priv *priv = (void *)object;
|
||||
nouveau_bsp_destroy(&priv->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_bsp_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv84_bsp_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bsp_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_bsp_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv84_bsp_priv *priv = (void *)object;
|
||||
return nouveau_bsp_fini(&priv->base, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv84_bsp_oclass = {
|
||||
.handle = NV_ENGINE(BSP, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_bsp_ctor,
|
||||
.dtor = nv84_bsp_dtor,
|
||||
.init = nv84_bsp_init,
|
||||
.fini = nv84_bsp_fini,
|
||||
},
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
u32 nva3_pcopy_data[] = {
|
||||
static u32 nva3_pcopy_data[] = {
|
||||
/* 0x0000: ctx_object */
|
||||
0x00000000,
|
||||
/* 0x0004: ctx_dma */
|
||||
|
@ -183,7 +183,7 @@ u32 nva3_pcopy_data[] = {
|
|||
0x00000800,
|
||||
};
|
||||
|
||||
u32 nva3_pcopy_code[] = {
|
||||
static u32 nva3_pcopy_code[] = {
|
||||
/* 0x0000: main */
|
||||
0x04fe04bd,
|
||||
0x3517f000,
|
|
@ -1,4 +1,4 @@
|
|||
u32 nvc0_pcopy_data[] = {
|
||||
static u32 nvc0_pcopy_data[] = {
|
||||
/* 0x0000: ctx_object */
|
||||
0x00000000,
|
||||
/* 0x0004: ctx_query_address_high */
|
||||
|
@ -171,7 +171,7 @@ u32 nvc0_pcopy_data[] = {
|
|||
0x00000800,
|
||||
};
|
||||
|
||||
u32 nvc0_pcopy_code[] = {
|
||||
static u32 nvc0_pcopy_code[] = {
|
||||
/* 0x0000: main */
|
||||
0x04fe04bd,
|
||||
0x3517f000,
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/vm.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
#include <engine/copy.h>
|
||||
|
||||
#include "fuc/nva3.fuc.h"
|
||||
|
||||
struct nva3_copy_priv {
|
||||
struct nouveau_copy base;
|
||||
};
|
||||
|
||||
struct nva3_copy_chan {
|
||||
struct nouveau_copy_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Copy object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nva3_copy_sclass[] = {
|
||||
{ 0x85b5, &nouveau_object_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nva3_copy_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nva3_copy_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nva3_copy_cclass = {
|
||||
.handle = NV_ENGCTX(COPY0, 0xa3),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nva3_copy_context_ctor,
|
||||
.dtor = _nouveau_copy_context_dtor,
|
||||
.init = _nouveau_copy_context_init,
|
||||
.fini = _nouveau_copy_context_fini,
|
||||
.rd32 = _nouveau_copy_context_rd32,
|
||||
.wr32 = _nouveau_copy_context_wr32,
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nva3_copy_isr_error_name[] = {
|
||||
{ 0x0001, "ILLEGAL_MTHD" },
|
||||
{ 0x0002, "INVALID_ENUM" },
|
||||
{ 0x0003, "INVALID_BITFIELD" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nva3_copy_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
|
||||
struct nouveau_engine *engine = nv_engine(subdev);
|
||||
struct nouveau_object *engctx;
|
||||
struct nva3_copy_priv *priv = (void *)subdev;
|
||||
u32 dispatch = nv_rd32(priv, 0x10401c);
|
||||
u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16);
|
||||
u64 inst = nv_rd32(priv, 0x104050) & 0x3fffffff;
|
||||
u32 ssta = nv_rd32(priv, 0x104040) & 0x0000ffff;
|
||||
u32 addr = nv_rd32(priv, 0x104040) >> 16;
|
||||
u32 mthd = (addr & 0x07ff) << 2;
|
||||
u32 subc = (addr & 0x3800) >> 11;
|
||||
u32 data = nv_rd32(priv, 0x104044);
|
||||
int chid;
|
||||
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(priv, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, subc, mthd, data);
|
||||
nv_wr32(priv, 0x104004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "unhandled intr 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x104004, stat);
|
||||
}
|
||||
|
||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
nva3_copy_tlb_flush(struct nouveau_engine *engine)
|
||||
{
|
||||
nv50_vm_flush_engine(&engine->base, 0x0d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
bool enable = (nv_device(parent)->chipset != 0xaf);
|
||||
struct nva3_copy_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_copy_create(parent, engine, oclass, enable, 0, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00802000;
|
||||
nv_subdev(priv)->intr = nva3_copy_intr;
|
||||
nv_engine(priv)->cclass = &nva3_copy_cclass;
|
||||
nv_engine(priv)->sclass = nva3_copy_sclass;
|
||||
nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nva3_copy_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nva3_copy_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_copy_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable all interrupts */
|
||||
nv_wr32(priv, 0x104014, 0xffffffff);
|
||||
|
||||
/* upload ucode */
|
||||
nv_wr32(priv, 0x1041c0, 0x01000000);
|
||||
for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
|
||||
nv_wr32(priv, 0x1041c4, nva3_pcopy_data[i]);
|
||||
|
||||
nv_wr32(priv, 0x104180, 0x01000000);
|
||||
for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
|
||||
if ((i & 0x3f) == 0)
|
||||
nv_wr32(priv, 0x104188, i >> 6);
|
||||
nv_wr32(priv, 0x104184, nva3_pcopy_code[i]);
|
||||
}
|
||||
|
||||
/* start it running */
|
||||
nv_wr32(priv, 0x10410c, 0x00000000);
|
||||
nv_wr32(priv, 0x104104, 0x00000000); /* ENTRY */
|
||||
nv_wr32(priv, 0x104100, 0x00000002); /* TRIGGER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nva3_copy_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nva3_copy_priv *priv = (void *)object;
|
||||
|
||||
nv_mask(priv, 0x104048, 0x00000003, 0x00000000);
|
||||
nv_wr32(priv, 0x104014, 0xffffffff);
|
||||
|
||||
return nouveau_copy_fini(&priv->base, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nva3_copy_oclass = {
|
||||
.handle = NV_ENGINE(COPY0, 0xa3),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nva3_copy_ctor,
|
||||
.dtor = _nouveau_copy_dtor,
|
||||
.init = nva3_copy_init,
|
||||
.fini = nva3_copy_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
#include <engine/copy.h>
|
||||
|
||||
#include "fuc/nvc0.fuc.h"
|
||||
|
||||
struct nvc0_copy_priv {
|
||||
struct nouveau_copy base;
|
||||
};
|
||||
|
||||
struct nvc0_copy_chan {
|
||||
struct nouveau_copy_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Copy object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_copy0_sclass[] = {
|
||||
{ 0x90b5, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_copy1_sclass[] = {
|
||||
{ 0x90b8, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nvc0_copy_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_copy_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
|
||||
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nvc0_copy_context_ofuncs = {
|
||||
.ctor = nvc0_copy_context_ctor,
|
||||
.dtor = _nouveau_copy_context_dtor,
|
||||
.init = _nouveau_copy_context_init,
|
||||
.fini = _nouveau_copy_context_fini,
|
||||
.rd32 = _nouveau_copy_context_rd32,
|
||||
.wr32 = _nouveau_copy_context_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_copy0_cclass = {
|
||||
.handle = NV_ENGCTX(COPY0, 0xc0),
|
||||
.ofuncs = &nvc0_copy_context_ofuncs,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_copy1_cclass = {
|
||||
.handle = NV_ENGCTX(COPY1, 0xc0),
|
||||
.ofuncs = &nvc0_copy_context_ofuncs,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nvc0_copy_isr_error_name[] = {
|
||||
{ 0x0001, "ILLEGAL_MTHD" },
|
||||
{ 0x0002, "INVALID_ENUM" },
|
||||
{ 0x0003, "INVALID_BITFIELD" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nvc0_copy_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
|
||||
struct nouveau_engine *engine = nv_engine(subdev);
|
||||
struct nouveau_object *engctx;
|
||||
int idx = nv_engidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
|
||||
struct nvc0_copy_priv *priv = (void *)subdev;
|
||||
u32 disp = nv_rd32(priv, 0x10401c + (idx * 0x1000));
|
||||
u32 intr = nv_rd32(priv, 0x104008 + (idx * 0x1000));
|
||||
u32 stat = intr & disp & ~(disp >> 16);
|
||||
u64 inst = nv_rd32(priv, 0x104050 + (idx * 0x1000)) & 0x0fffffff;
|
||||
u32 ssta = nv_rd32(priv, 0x104040 + (idx * 0x1000)) & 0x0000ffff;
|
||||
u32 addr = nv_rd32(priv, 0x104040 + (idx * 0x1000)) >> 16;
|
||||
u32 mthd = (addr & 0x07ff) << 2;
|
||||
u32 subc = (addr & 0x3800) >> 11;
|
||||
u32 data = nv_rd32(priv, 0x104044 + (idx * 0x1000));
|
||||
int chid;
|
||||
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(priv, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, subc, mthd, data);
|
||||
nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "unhandled intr 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x104004 + (idx * 0x1000), stat);
|
||||
}
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_copy_priv *priv;
|
||||
int ret;
|
||||
|
||||
if (nv_rd32(parent, 0x022500) & 0x00000100)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000040;
|
||||
nv_subdev(priv)->intr = nvc0_copy_intr;
|
||||
nv_engine(priv)->cclass = &nvc0_copy0_cclass;
|
||||
nv_engine(priv)->sclass = nvc0_copy0_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_copy_priv *priv;
|
||||
int ret;
|
||||
|
||||
if (nv_rd32(parent, 0x022500) & 0x00000200)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000080;
|
||||
nv_subdev(priv)->intr = nvc0_copy_intr;
|
||||
nv_engine(priv)->cclass = &nvc0_copy1_cclass;
|
||||
nv_engine(priv)->sclass = nvc0_copy1_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_copy_init(struct nouveau_object *object)
|
||||
{
|
||||
int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
|
||||
struct nvc0_copy_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_copy_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable all interrupts */
|
||||
nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
|
||||
|
||||
/* upload ucode */
|
||||
nv_wr32(priv, 0x1041c0 + (idx * 0x1000), 0x01000000);
|
||||
for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
|
||||
nv_wr32(priv, 0x1041c4 + (idx * 0x1000), nvc0_pcopy_data[i]);
|
||||
|
||||
nv_wr32(priv, 0x104180 + (idx * 0x1000), 0x01000000);
|
||||
for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
|
||||
if ((i & 0x3f) == 0)
|
||||
nv_wr32(priv, 0x104188 + (idx * 0x1000), i >> 6);
|
||||
nv_wr32(priv, 0x104184 + (idx * 0x1000), nvc0_pcopy_code[i]);
|
||||
}
|
||||
|
||||
/* start it running */
|
||||
nv_wr32(priv, 0x104084 + (idx * 0x1000), idx);
|
||||
nv_wr32(priv, 0x10410c + (idx * 0x1000), 0x00000000);
|
||||
nv_wr32(priv, 0x104104 + (idx * 0x1000), 0x00000000); /* ENTRY */
|
||||
nv_wr32(priv, 0x104100 + (idx * 0x1000), 0x00000002); /* TRIGGER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_copy_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
|
||||
struct nvc0_copy_priv *priv = (void *)object;
|
||||
|
||||
nv_mask(priv, 0x104048 + (idx * 0x1000), 0x00000003, 0x00000000);
|
||||
nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
|
||||
|
||||
return nouveau_copy_fini(&priv->base, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nvc0_copy0_oclass = {
|
||||
.handle = NV_ENGINE(COPY0, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_copy0_ctor,
|
||||
.dtor = _nouveau_copy_dtor,
|
||||
.init = nvc0_copy_init,
|
||||
.fini = nvc0_copy_fini,
|
||||
},
|
||||
};
|
||||
|
||||
struct nouveau_oclass
|
||||
nvc0_copy1_oclass = {
|
||||
.handle = NV_ENGINE(COPY1, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_copy1_ctor,
|
||||
.dtor = _nouveau_copy_dtor,
|
||||
.init = nvc0_copy_init,
|
||||
.fini = nvc0_copy_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <engine/copy.h>
|
||||
|
||||
struct nve0_copy_priv {
|
||||
struct nouveau_copy base;
|
||||
};
|
||||
|
||||
struct nve0_copy_chan {
|
||||
struct nouveau_copy_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Copy object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nve0_copy_sclass[] = {
|
||||
{ 0xa0b5, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nve0_copy_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_copy_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
|
||||
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nve0_copy_context_ofuncs = {
|
||||
.ctor = nve0_copy_context_ctor,
|
||||
.dtor = _nouveau_copy_context_dtor,
|
||||
.init = _nouveau_copy_context_init,
|
||||
.fini = _nouveau_copy_context_fini,
|
||||
.rd32 = _nouveau_copy_context_rd32,
|
||||
.wr32 = _nouveau_copy_context_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nve0_copy_cclass = {
|
||||
.handle = NV_ENGCTX(COPY0, 0xc0),
|
||||
.ofuncs = &nve0_copy_context_ofuncs,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCOPY engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_copy_priv *priv;
|
||||
int ret;
|
||||
|
||||
if (nv_rd32(parent, 0x022500) & 0x00000100)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000040;
|
||||
nv_engine(priv)->cclass = &nve0_copy_cclass;
|
||||
nv_engine(priv)->sclass = nve0_copy_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_copy_priv *priv;
|
||||
int ret;
|
||||
|
||||
if (nv_rd32(parent, 0x022500) & 0x00000200)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000080;
|
||||
nv_engine(priv)->cclass = &nve0_copy_cclass;
|
||||
nv_engine(priv)->sclass = nve0_copy_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nve0_copy0_oclass = {
|
||||
.handle = NV_ENGINE(COPY0, 0xe0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_copy0_ctor,
|
||||
.dtor = _nouveau_copy_dtor,
|
||||
.init = _nouveau_copy_init,
|
||||
.fini = _nouveau_copy_fini,
|
||||
},
|
||||
};
|
||||
|
||||
struct nouveau_oclass
|
||||
nve0_copy1_oclass = {
|
||||
.handle = NV_ENGINE(COPY1, 0xe0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_copy1_ctor,
|
||||
.dtor = _nouveau_copy_dtor,
|
||||
.init = _nouveau_copy_init,
|
||||
.fini = _nouveau_copy_fini,
|
||||
},
|
||||
};
|
|
@ -238,7 +238,7 @@ ih:
|
|||
cmpu b32 $r4 0x60+#dma_count
|
||||
bra nc #illegal_mthd
|
||||
shl b32 $r5 $r4 2
|
||||
add b32 $r5 (#ctx_dma - 0x60 * 4) & 0xffff
|
||||
add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
|
||||
bset $r3 0x1e
|
||||
st b32 D[$r5] $r3
|
||||
add b32 $r4 0x180 - 0x60
|
|
@ -1,4 +1,4 @@
|
|||
uint32_t nv98_pcrypt_data[] = {
|
||||
static uint32_t nv98_pcrypt_data[] = {
|
||||
/* 0x0000: ctx_dma */
|
||||
/* 0x0000: ctx_dma_query */
|
||||
0x00000000,
|
||||
|
@ -150,7 +150,7 @@ uint32_t nv98_pcrypt_data[] = {
|
|||
0x00000000,
|
||||
};
|
||||
|
||||
uint32_t nv98_pcrypt_code[] = {
|
||||
static uint32_t nv98_pcrypt_code[] = {
|
||||
0x17f004bd,
|
||||
0x0010fe35,
|
||||
0xf10004fe,
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
#include <engine/crypt.h>
|
||||
|
||||
struct nv84_crypt_priv {
|
||||
struct nouveau_crypt base;
|
||||
};
|
||||
|
||||
struct nv84_crypt_chan {
|
||||
struct nouveau_crypt_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Crypt object classes
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_crypt_object_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_gpuobj *obj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
|
||||
16, 16, 0, &obj);
|
||||
*pobject = nv_object(obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wo32(obj, 0x00, nv_mclass(obj));
|
||||
nv_wo32(obj, 0x04, 0x00000000);
|
||||
nv_wo32(obj, 0x08, 0x00000000);
|
||||
nv_wo32(obj, 0x0c, 0x00000000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv84_crypt_ofuncs = {
|
||||
.ctor = nv84_crypt_object_ctor,
|
||||
.dtor = _nouveau_gpuobj_dtor,
|
||||
.init = _nouveau_gpuobj_init,
|
||||
.fini = _nouveau_gpuobj_fini,
|
||||
.rd32 = _nouveau_gpuobj_rd32,
|
||||
.wr32 = _nouveau_gpuobj_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_crypt_sclass[] = {
|
||||
{ 0x74c1, &nv84_crypt_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCRYPT context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_crypt_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv84_crypt_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
|
||||
0, NVOBJ_FLAG_ZERO_ALLOC, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_crypt_cclass = {
|
||||
.handle = NV_ENGCTX(CRYPT, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_crypt_context_ctor,
|
||||
.dtor = _nouveau_crypt_context_dtor,
|
||||
.init = _nouveau_crypt_context_init,
|
||||
.fini = _nouveau_crypt_context_fini,
|
||||
.rd32 = _nouveau_crypt_context_rd32,
|
||||
.wr32 = _nouveau_crypt_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCRYPT engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_bitfield nv84_crypt_intr_mask[] = {
|
||||
{ 0x00000001, "INVALID_STATE" },
|
||||
{ 0x00000002, "ILLEGAL_MTHD" },
|
||||
{ 0x00000004, "ILLEGAL_CLASS" },
|
||||
{ 0x00000080, "QUERY" },
|
||||
{ 0x00000100, "FAULT" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nv84_crypt_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
|
||||
struct nouveau_engine *engine = nv_engine(subdev);
|
||||
struct nouveau_object *engctx;
|
||||
struct nv84_crypt_priv *priv = (void *)subdev;
|
||||
u32 stat = nv_rd32(priv, 0x102130);
|
||||
u32 mthd = nv_rd32(priv, 0x102190);
|
||||
u32 data = nv_rd32(priv, 0x102194);
|
||||
u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
|
||||
int chid;
|
||||
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "");
|
||||
nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
|
||||
printk(" ch %d [0x%010llx] mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x102130, stat);
|
||||
nv_wr32(priv, 0x10200c, 0x10);
|
||||
|
||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_crypt_tlb_flush(struct nouveau_engine *engine)
|
||||
{
|
||||
nv50_vm_flush_engine(&engine->base, 0x0a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv84_crypt_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_crypt_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00004000;
|
||||
nv_subdev(priv)->intr = nv84_crypt_intr;
|
||||
nv_engine(priv)->cclass = &nv84_crypt_cclass;
|
||||
nv_engine(priv)->sclass = nv84_crypt_sclass;
|
||||
nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_crypt_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv84_crypt_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_crypt_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x102130, 0xffffffff);
|
||||
nv_wr32(priv, 0x102140, 0xffffffbf);
|
||||
nv_wr32(priv, 0x10200c, 0x00000010);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv84_crypt_oclass = {
|
||||
.handle = NV_ENGINE(CRYPT, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_crypt_ctor,
|
||||
.dtor = _nouveau_crypt_dtor,
|
||||
.init = nv84_crypt_init,
|
||||
.fini = _nouveau_crypt_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
#include <engine/crypt.h>
|
||||
|
||||
#include "fuc/nv98.fuc.h"
|
||||
|
||||
struct nv98_crypt_priv {
|
||||
struct nouveau_crypt base;
|
||||
};
|
||||
|
||||
struct nv98_crypt_chan {
|
||||
struct nouveau_crypt_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Crypt object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv98_crypt_sclass[] = {
|
||||
{ 0x88b4, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCRYPT context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv98_crypt_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv98_crypt_chan *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
|
||||
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv98_crypt_cclass = {
|
||||
.handle = NV_ENGCTX(CRYPT, 0x98),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv98_crypt_context_ctor,
|
||||
.dtor = _nouveau_crypt_context_dtor,
|
||||
.init = _nouveau_crypt_context_init,
|
||||
.fini = _nouveau_crypt_context_fini,
|
||||
.rd32 = _nouveau_crypt_context_rd32,
|
||||
.wr32 = _nouveau_crypt_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PCRYPT engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nv98_crypt_isr_error_name[] = {
|
||||
{ 0x0000, "ILLEGAL_MTHD" },
|
||||
{ 0x0001, "INVALID_BITFIELD" },
|
||||
{ 0x0002, "INVALID_ENUM" },
|
||||
{ 0x0003, "QUERY" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nv98_crypt_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
|
||||
struct nouveau_engine *engine = nv_engine(subdev);
|
||||
struct nouveau_object *engctx;
|
||||
struct nv98_crypt_priv *priv = (void *)subdev;
|
||||
u32 disp = nv_rd32(priv, 0x08701c);
|
||||
u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
|
||||
u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
|
||||
u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
|
||||
u32 addr = nv_rd32(priv, 0x087040) >> 16;
|
||||
u32 mthd = (addr & 0x07ff) << 2;
|
||||
u32 subc = (addr & 0x3800) >> 11;
|
||||
u32 data = nv_rd32(priv, 0x087044);
|
||||
int chid;
|
||||
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(priv, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, subc, mthd, data);
|
||||
nv_wr32(priv, 0x087004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "unhandled intr 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x087004, stat);
|
||||
}
|
||||
|
||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
nv98_crypt_tlb_flush(struct nouveau_engine *engine)
|
||||
{
|
||||
nv50_vm_flush_engine(&engine->base, 0x0a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv98_crypt_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_crypt_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00004000;
|
||||
nv_subdev(priv)->intr = nv98_crypt_intr;
|
||||
nv_engine(priv)->cclass = &nv98_crypt_cclass;
|
||||
nv_engine(priv)->sclass = nv98_crypt_sclass;
|
||||
nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv98_crypt_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv98_crypt_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_crypt_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* wait for exit interrupt to signal */
|
||||
nv_wait(priv, 0x087008, 0x00000010, 0x00000010);
|
||||
nv_wr32(priv, 0x087004, 0x00000010);
|
||||
|
||||
/* upload microcode code and data segments */
|
||||
nv_wr32(priv, 0x087ff8, 0x00100000);
|
||||
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
|
||||
nv_wr32(priv, 0x087ff4, nv98_pcrypt_code[i]);
|
||||
|
||||
nv_wr32(priv, 0x087ff8, 0x00000000);
|
||||
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
|
||||
nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]);
|
||||
|
||||
/* start it running */
|
||||
nv_wr32(priv, 0x08710c, 0x00000000);
|
||||
nv_wr32(priv, 0x087104, 0x00000000); /* ENTRY */
|
||||
nv_wr32(priv, 0x087100, 0x00000002); /* TRIGGER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv98_crypt_oclass = {
|
||||
.handle = NV_ENGINE(CRYPT, 0x98),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv98_crypt_ctor,
|
||||
.dtor = _nouveau_crypt_dtor,
|
||||
.init = nv98_crypt_init,
|
||||
.fini = _nouveau_crypt_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
struct nv04_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_disp_sclass[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static void
|
||||
nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
|
||||
{
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_disp_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nv04_disp_priv *priv = (void *)subdev;
|
||||
u32 crtc0 = nv_rd32(priv, 0x600100);
|
||||
u32 crtc1 = nv_rd32(priv, 0x602100);
|
||||
|
||||
if (crtc0 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 0);
|
||||
nv_wr32(priv, 0x600100, 0x00000001);
|
||||
}
|
||||
|
||||
if (crtc1 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 1);
|
||||
nv_wr32(priv, 0x602100, 0x00000001);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_engine(priv)->sclass = nv04_disp_sclass;
|
||||
nv_subdev(priv)->intr = nv04_disp_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv04_disp_oclass = {
|
||||
.handle = NV_ENGINE(DISP, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_disp_ctor,
|
||||
.dtor = _nouveau_disp_dtor,
|
||||
.init = _nouveau_disp_init,
|
||||
.fini = _nouveau_disp_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
|
||||
struct nv50_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv50_disp_sclass[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static void
|
||||
nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
|
||||
{
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
struct nouveau_software_chan *chan, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
|
||||
if (chan->vblank.crtc != crtc)
|
||||
continue;
|
||||
|
||||
nv_wr32(priv, 0x001704, chan->vblank.channel);
|
||||
nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
|
||||
|
||||
if (nv_device(priv)->chipset == 0x50) {
|
||||
nv_wr32(priv, 0x001570, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x001574, chan->vblank.value);
|
||||
} else {
|
||||
if (nv_device(priv)->chipset >= 0xc0) {
|
||||
nv_wr32(priv, 0x06000c,
|
||||
upper_32_bits(chan->vblank.offset));
|
||||
}
|
||||
nv_wr32(priv, 0x060010, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
}
|
||||
|
||||
list_del(&chan->vblank.head);
|
||||
if (disp->vblank.put)
|
||||
disp->vblank.put(disp->vblank.data, crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_disp_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nv50_disp_priv *priv = (void *)subdev;
|
||||
u32 stat1 = nv_rd32(priv, 0x610024);
|
||||
|
||||
if (stat1 & 0x00000004) {
|
||||
nv50_disp_intr_vblank(priv, 0);
|
||||
nv_wr32(priv, 0x610024, 0x00000004);
|
||||
stat1 &= ~0x00000004;
|
||||
}
|
||||
|
||||
if (stat1 & 0x00000008) {
|
||||
nv50_disp_intr_vblank(priv, 1);
|
||||
nv_wr32(priv, 0x610024, 0x00000008);
|
||||
stat1 &= ~0x00000008;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_engine(priv)->sclass = nv50_disp_sclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv50_disp_oclass = {
|
||||
.handle = NV_ENGINE(DISP, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_disp_ctor,
|
||||
.dtor = _nouveau_disp_dtor,
|
||||
.init = _nouveau_disp_init,
|
||||
.fini = _nouveau_disp_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bar.h>
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
|
||||
struct nvd0_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvd0_disp_sclass[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static void
|
||||
nvd0_disp_intr_vblank(struct nvd0_disp_priv *priv, int crtc)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
struct nouveau_software_chan *chan, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
|
||||
if (chan->vblank.crtc != crtc)
|
||||
continue;
|
||||
|
||||
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
|
||||
bar->flush(bar);
|
||||
nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
|
||||
list_del(&chan->vblank.head);
|
||||
if (disp->vblank.put)
|
||||
disp->vblank.put(disp->vblank.data, crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
nvd0_disp_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nvd0_disp_priv *priv = (void *)subdev;
|
||||
u32 intr = nv_rd32(priv, 0x610088);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
u32 mask = 0x01000000 << i;
|
||||
if (mask & intr) {
|
||||
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
|
||||
if (stat & 0x00000001)
|
||||
nvd0_disp_intr_vblank(priv, i);
|
||||
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
|
||||
nv_rd32(priv, 0x6100c0 + (i * 0x800));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvd0_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_engine(priv)->sclass = nvd0_disp_sclass;
|
||||
nv_subdev(priv)->intr = nvd0_disp_intr;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nvd0_disp_oclass = {
|
||||
.handle = NV_ENGINE(DISP, 0xd0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvd0_disp_ctor,
|
||||
.dtor = _nouveau_disp_dtor,
|
||||
.init = _nouveau_disp_init,
|
||||
.fini = _nouveau_disp_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/subdev.h>
|
||||
#include <core/device.h>
|
||||
#include <subdev/vga.h>
|
||||
|
||||
u8
|
||||
nv_rdport(void *obj, int head, u16 port)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(obj);
|
||||
|
||||
if (device->card_type >= NV_50)
|
||||
return nv_rd08(obj, 0x601000 + port);
|
||||
|
||||
if (port == 0x03c0 || port == 0x03c1 || /* AR */
|
||||
port == 0x03c2 || port == 0x03da || /* INP0 */
|
||||
port == 0x03d4 || port == 0x03d5) /* CR */
|
||||
return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
|
||||
|
||||
if (port == 0x03c2 || port == 0x03cc || /* MISC */
|
||||
port == 0x03c4 || port == 0x03c5 || /* SR */
|
||||
port == 0x03ce || port == 0x03cf) { /* GR */
|
||||
if (device->card_type < NV_40)
|
||||
head = 0; /* CR44 selects head */
|
||||
return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
|
||||
}
|
||||
|
||||
nv_error(obj, "unknown vga port 0x%04x\n", port);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrport(void *obj, int head, u16 port, u8 data)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(obj);
|
||||
|
||||
if (device->card_type >= NV_50)
|
||||
nv_wr08(obj, 0x601000 + port, data);
|
||||
else
|
||||
if (port == 0x03c0 || port == 0x03c1 || /* AR */
|
||||
port == 0x03c2 || port == 0x03da || /* INP0 */
|
||||
port == 0x03d4 || port == 0x03d5) /* CR */
|
||||
nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
|
||||
else
|
||||
if (port == 0x03c2 || port == 0x03cc || /* MISC */
|
||||
port == 0x03c4 || port == 0x03c5 || /* SR */
|
||||
port == 0x03ce || port == 0x03cf) { /* GR */
|
||||
if (device->card_type < NV_40)
|
||||
head = 0; /* CR44 selects head */
|
||||
nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
|
||||
} else
|
||||
nv_error(obj, "unknown vga port 0x%04x\n", port);
|
||||
}
|
||||
|
||||
u8
|
||||
nv_rdvgas(void *obj, int head, u8 index)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03c4, index);
|
||||
return nv_rdport(obj, head, 0x03c5);
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrvgas(void *obj, int head, u8 index, u8 value)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03c4, index);
|
||||
nv_wrport(obj, head, 0x03c5, value);
|
||||
}
|
||||
|
||||
u8
|
||||
nv_rdvgag(void *obj, int head, u8 index)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03ce, index);
|
||||
return nv_rdport(obj, head, 0x03cf);
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrvgag(void *obj, int head, u8 index, u8 value)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03ce, index);
|
||||
nv_wrport(obj, head, 0x03cf, value);
|
||||
}
|
||||
|
||||
u8
|
||||
nv_rdvgac(void *obj, int head, u8 index)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03d4, index);
|
||||
return nv_rdport(obj, head, 0x03d5);
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrvgac(void *obj, int head, u8 index, u8 value)
|
||||
{
|
||||
nv_wrport(obj, head, 0x03d4, index);
|
||||
nv_wrport(obj, head, 0x03d5, value);
|
||||
}
|
||||
|
||||
u8
|
||||
nv_rdvgai(void *obj, int head, u16 port, u8 index)
|
||||
{
|
||||
if (port == 0x03c4) return nv_rdvgas(obj, head, index);
|
||||
if (port == 0x03ce) return nv_rdvgag(obj, head, index);
|
||||
if (port == 0x03d4) return nv_rdvgac(obj, head, index);
|
||||
nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
|
||||
{
|
||||
if (port == 0x03c4) nv_wrvgas(obj, head, index, value);
|
||||
else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
|
||||
else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
|
||||
else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
|
||||
}
|
||||
|
||||
bool
|
||||
nv_lockvgac(void *obj, bool lock)
|
||||
{
|
||||
bool locked = !nv_rdvgac(obj, 0, 0x1f);
|
||||
u8 data = lock ? 0x99 : 0x57;
|
||||
nv_wrvgac(obj, 0, 0x1f, data);
|
||||
if (nv_device(obj)->chipset == 0x11) {
|
||||
if (!(nv_rd32(obj, 0x001084) & 0x10000000))
|
||||
nv_wrvgac(obj, 1, 0x1f, data);
|
||||
}
|
||||
return locked;
|
||||
}
|
||||
|
||||
/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
|
||||
* it affects only the 8 bit vga io regs, which we access using mmio at
|
||||
* 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
|
||||
* in general, the set value of cr44 does not matter: reg access works as
|
||||
* expected and values can be set for the appropriate head by using a 0x2000
|
||||
* offset as required
|
||||
* however:
|
||||
* a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
|
||||
* cr44 must be set to 0 or 3 for accessing values on the correct head
|
||||
* through the common 0xc03c* addresses
|
||||
* b) in tied mode (4) head B is programmed to the values set on head A, and
|
||||
* access using the head B addresses can have strange results, ergo we leave
|
||||
* tied mode in init once we know to what cr44 should be restored on exit
|
||||
*
|
||||
* the owner parameter is slightly abused:
|
||||
* 0 and 1 are treated as head values and so the set value is (owner * 3)
|
||||
* other values are treated as literal values to set
|
||||
*/
|
||||
u8
|
||||
nv_rdvgaowner(void *obj)
|
||||
{
|
||||
if (nv_device(obj)->card_type < NV_50) {
|
||||
if (nv_device(obj)->chipset == 0x11) {
|
||||
u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
|
||||
if (tied == 0) {
|
||||
u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
|
||||
u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
|
||||
u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
|
||||
u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
|
||||
if (slA && !tvA) return 0x00;
|
||||
if (slB && !tvB) return 0x03;
|
||||
if (slA) return 0x00;
|
||||
if (slB) return 0x03;
|
||||
return 0x00;
|
||||
}
|
||||
return 0x04;
|
||||
}
|
||||
|
||||
return nv_rdvgac(obj, 0, 0x44);
|
||||
}
|
||||
|
||||
nv_error(obj, "rdvgaowner after nv4x\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void
|
||||
nv_wrvgaowner(void *obj, u8 select)
|
||||
{
|
||||
if (nv_device(obj)->card_type < NV_50) {
|
||||
u8 owner = (select == 1) ? 3 : select;
|
||||
if (nv_device(obj)->chipset == 0x11) {
|
||||
/* workaround hw lockup bug */
|
||||
nv_rdvgac(obj, 0, 0x1f);
|
||||
nv_rdvgac(obj, 1, 0x1f);
|
||||
}
|
||||
|
||||
nv_wrvgac(obj, 0, 0x44, owner);
|
||||
|
||||
if (nv_device(obj)->chipset == 0x11) {
|
||||
nv_wrvgac(obj, 0, 0x2e, owner);
|
||||
nv_wrvgac(obj, 0, 0x2e, owner);
|
||||
}
|
||||
} else
|
||||
nv_error(obj, "wrvgaowner after nv4x\n");
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <engine/dmaobj.h>
|
||||
|
||||
int
|
||||
nouveau_dmaobj_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass,
|
||||
void *data, u32 size, int len, void **pobject)
|
||||
{
|
||||
struct nv_dma_class *args = data;
|
||||
struct nouveau_dmaobj *object;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, 0, len, pobject);
|
||||
object = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (args->flags & NV_DMA_TARGET_MASK) {
|
||||
case NV_DMA_TARGET_VM:
|
||||
object->target = NV_MEM_TARGET_VM;
|
||||
break;
|
||||
case NV_DMA_TARGET_VRAM:
|
||||
object->target = NV_MEM_TARGET_VRAM;
|
||||
break;
|
||||
case NV_DMA_TARGET_PCI:
|
||||
object->target = NV_MEM_TARGET_PCI;
|
||||
break;
|
||||
case NV_DMA_TARGET_PCI_US:
|
||||
case NV_DMA_TARGET_AGP:
|
||||
object->target = NV_MEM_TARGET_PCI_NOSNOOP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (args->flags & NV_DMA_ACCESS_MASK) {
|
||||
case NV_DMA_ACCESS_VM:
|
||||
object->access = NV_MEM_ACCESS_VM;
|
||||
break;
|
||||
case NV_DMA_ACCESS_RD:
|
||||
object->access = NV_MEM_ACCESS_RO;
|
||||
break;
|
||||
case NV_DMA_ACCESS_WR:
|
||||
object->access = NV_MEM_ACCESS_WO;
|
||||
break;
|
||||
case NV_DMA_ACCESS_RDWR:
|
||||
object->access = NV_MEM_ACCESS_RW;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
object->start = args->start;
|
||||
object->limit = args->limit;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/vm/nv04.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
|
||||
struct nv04_dmaeng_priv {
|
||||
struct nouveau_dmaeng base;
|
||||
};
|
||||
|
||||
struct nv04_dmaobj_priv {
|
||||
struct nouveau_dmaobj base;
|
||||
};
|
||||
|
||||
static int
|
||||
nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
|
||||
struct nouveau_object *parent,
|
||||
struct nouveau_dmaobj *dmaobj,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaeng);
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
u32 flags0 = nv_mclass(dmaobj);
|
||||
u32 flags2 = 0x00000000;
|
||||
u64 offset = dmaobj->start & 0xfffff000;
|
||||
u64 adjust = dmaobj->start & 0x00000fff;
|
||||
u32 length = dmaobj->limit - dmaobj->start;
|
||||
int ret;
|
||||
|
||||
if (dmaobj->target == NV_MEM_TARGET_VM) {
|
||||
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) {
|
||||
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
|
||||
if (!dmaobj->start)
|
||||
return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
|
||||
offset = nv_ro32(pgt, 8 + (offset >> 10));
|
||||
offset &= 0xfffff000;
|
||||
}
|
||||
|
||||
dmaobj->target = NV_MEM_TARGET_PCI;
|
||||
dmaobj->access = NV_MEM_ACCESS_RW;
|
||||
}
|
||||
|
||||
switch (dmaobj->target) {
|
||||
case NV_MEM_TARGET_VRAM:
|
||||
flags0 |= 0x00003000;
|
||||
break;
|
||||
case NV_MEM_TARGET_PCI:
|
||||
flags0 |= 0x00023000;
|
||||
break;
|
||||
case NV_MEM_TARGET_PCI_NOSNOOP:
|
||||
flags0 |= 0x00033000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dmaobj->access) {
|
||||
case NV_MEM_ACCESS_RO:
|
||||
flags0 |= 0x00004000;
|
||||
break;
|
||||
case NV_MEM_ACCESS_WO:
|
||||
flags0 |= 0x00008000;
|
||||
case NV_MEM_ACCESS_RW:
|
||||
flags2 |= 0x00000002;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
|
||||
*pgpuobj = gpuobj;
|
||||
if (ret == 0) {
|
||||
nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20));
|
||||
nv_wo32(*pgpuobj, 0x04, length);
|
||||
nv_wo32(*pgpuobj, 0x08, flags2 | offset);
|
||||
nv_wo32(*pgpuobj, 0x0c, flags2 | offset);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_dmaeng *dmaeng = (void *)engine;
|
||||
struct nv04_dmaobj_priv *dmaobj;
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaobj_create(parent, engine, oclass,
|
||||
data, size, &dmaobj);
|
||||
*pobject = nv_object(dmaobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (nv_mclass(parent)) {
|
||||
case NV_DEVICE_CLASS:
|
||||
break;
|
||||
case NV03_CHANNEL_DMA_CLASS:
|
||||
case NV10_CHANNEL_DMA_CLASS:
|
||||
case NV17_CHANNEL_DMA_CLASS:
|
||||
case NV40_CHANNEL_DMA_CLASS:
|
||||
ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
|
||||
nouveau_object_ref(NULL, pobject);
|
||||
*pobject = nv_object(gpuobj);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv04_dmaobj_ofuncs = {
|
||||
.ctor = nv04_dmaobj_ctor,
|
||||
.dtor = _nouveau_dmaobj_dtor,
|
||||
.init = _nouveau_dmaobj_init,
|
||||
.fini = _nouveau_dmaobj_fini,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_dmaobj_sclass[] = {
|
||||
{ 0x0002, &nv04_dmaobj_ofuncs },
|
||||
{ 0x0003, &nv04_dmaobj_ofuncs },
|
||||
{ 0x003d, &nv04_dmaobj_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_dmaeng_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.base.sclass = nv04_dmaobj_sclass;
|
||||
priv->base.bind = nv04_dmaobj_bind;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv04_dmaeng_oclass = {
|
||||
.handle = NV_ENGINE(DMAOBJ, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_dmaeng_ctor,
|
||||
.dtor = _nouveau_dmaeng_dtor,
|
||||
.init = _nouveau_dmaeng_init,
|
||||
.fini = _nouveau_dmaeng_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <engine/dmaobj.h>
|
||||
|
||||
struct nv50_dmaeng_priv {
|
||||
struct nouveau_dmaeng base;
|
||||
};
|
||||
|
||||
struct nv50_dmaobj_priv {
|
||||
struct nouveau_dmaobj base;
|
||||
};
|
||||
|
||||
static int
|
||||
nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
|
||||
struct nouveau_object *parent,
|
||||
struct nouveau_dmaobj *dmaobj,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
u32 flags = nv_mclass(dmaobj);
|
||||
int ret;
|
||||
|
||||
switch (dmaobj->target) {
|
||||
case NV_MEM_TARGET_VM:
|
||||
flags |= 0x00000000;
|
||||
flags |= 0x60000000; /* COMPRESSION_USEVM */
|
||||
flags |= 0x1fc00000; /* STORAGE_TYPE_USEVM */
|
||||
break;
|
||||
case NV_MEM_TARGET_VRAM:
|
||||
flags |= 0x00010000;
|
||||
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
|
||||
break;
|
||||
case NV_MEM_TARGET_PCI:
|
||||
flags |= 0x00020000;
|
||||
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
|
||||
break;
|
||||
case NV_MEM_TARGET_PCI_NOSNOOP:
|
||||
flags |= 0x00030000;
|
||||
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dmaobj->access) {
|
||||
case NV_MEM_ACCESS_VM:
|
||||
break;
|
||||
case NV_MEM_ACCESS_RO:
|
||||
flags |= 0x00040000;
|
||||
break;
|
||||
case NV_MEM_ACCESS_WO:
|
||||
case NV_MEM_ACCESS_RW:
|
||||
flags |= 0x00080000;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
|
||||
if (ret == 0) {
|
||||
nv_wo32(*pgpuobj, 0x00, flags);
|
||||
nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
|
||||
nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
|
||||
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
|
||||
upper_32_bits(dmaobj->start));
|
||||
nv_wo32(*pgpuobj, 0x10, 0x00000000);
|
||||
nv_wo32(*pgpuobj, 0x14, 0x00000000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_dmaeng *dmaeng = (void *)engine;
|
||||
struct nv50_dmaobj_priv *dmaobj;
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaobj_create(parent, engine, oclass,
|
||||
data, size, &dmaobj);
|
||||
*pobject = nv_object(dmaobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (nv_mclass(parent)) {
|
||||
case NV_DEVICE_CLASS:
|
||||
break;
|
||||
case NV50_CHANNEL_DMA_CLASS:
|
||||
case NV84_CHANNEL_DMA_CLASS:
|
||||
case NV50_CHANNEL_IND_CLASS:
|
||||
case NV84_CHANNEL_IND_CLASS:
|
||||
ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
|
||||
nouveau_object_ref(NULL, pobject);
|
||||
*pobject = nv_object(gpuobj);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv50_dmaobj_ofuncs = {
|
||||
.ctor = nv50_dmaobj_ctor,
|
||||
.dtor = _nouveau_dmaobj_dtor,
|
||||
.init = _nouveau_dmaobj_init,
|
||||
.fini = _nouveau_dmaobj_fini,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv50_dmaobj_sclass[] = {
|
||||
{ 0x0002, &nv50_dmaobj_ofuncs },
|
||||
{ 0x0003, &nv50_dmaobj_ofuncs },
|
||||
{ 0x003d, &nv50_dmaobj_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_dmaeng_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.base.sclass = nv50_dmaobj_sclass;
|
||||
priv->base.bind = nv50_dmaobj_bind;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv50_dmaeng_oclass = {
|
||||
.handle = NV_ENGINE(DMAOBJ, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_dmaeng_ctor,
|
||||
.dtor = _nouveau_dmaeng_dtor,
|
||||
.init = _nouveau_dmaeng_init,
|
||||
.fini = _nouveau_dmaeng_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <engine/dmaobj.h>
|
||||
|
||||
struct nvc0_dmaeng_priv {
|
||||
struct nouveau_dmaeng base;
|
||||
};
|
||||
|
||||
struct nvc0_dmaobj_priv {
|
||||
struct nouveau_dmaobj base;
|
||||
};
|
||||
|
||||
static int
|
||||
nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_dmaobj_priv *dmaobj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaobj_create(parent, engine, oclass, data, size, &dmaobj);
|
||||
*pobject = nv_object(dmaobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dmaobj->base.target != NV_MEM_TARGET_VM || dmaobj->base.start)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nvc0_dmaobj_ofuncs = {
|
||||
.ctor = nvc0_dmaobj_ctor,
|
||||
.dtor = _nouveau_dmaobj_dtor,
|
||||
.init = _nouveau_dmaobj_init,
|
||||
.fini = _nouveau_dmaobj_fini,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_dmaobj_sclass[] = {
|
||||
{ 0x0002, &nvc0_dmaobj_ofuncs },
|
||||
{ 0x0003, &nvc0_dmaobj_ofuncs },
|
||||
{ 0x003d, &nvc0_dmaobj_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_dmaeng_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.base.sclass = nvc0_dmaobj_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nvc0_dmaeng_oclass = {
|
||||
.handle = NV_ENGINE(DMAOBJ, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_dmaeng_ctor,
|
||||
.dtor = _nouveau_dmaeng_dtor,
|
||||
.init = _nouveau_dmaeng_init,
|
||||
.fini = _nouveau_dmaeng_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/handle.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
int
|
||||
nouveau_fifo_channel_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass,
|
||||
int bar, u32 addr, u32 size, u32 pushbuf,
|
||||
u32 engmask, int len, void **ptr)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(engine);
|
||||
struct nouveau_fifo *priv = (void *)engine;
|
||||
struct nouveau_fifo_chan *chan;
|
||||
struct nouveau_dmaeng *dmaeng;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* create base object class */
|
||||
ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
|
||||
engmask, len, ptr);
|
||||
chan = *ptr;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* validate dma object representing push buffer */
|
||||
chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
|
||||
if (!chan->pushdma)
|
||||
return -ENOENT;
|
||||
|
||||
dmaeng = (void *)chan->pushdma->base.engine;
|
||||
switch (chan->pushdma->base.oclass->handle) {
|
||||
case 0x0002:
|
||||
case 0x003d:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dmaeng->bind) {
|
||||
ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* find a free fifo channel */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
|
||||
if (!priv->channel[chan->chid]) {
|
||||
priv->channel[chan->chid] = nv_object(chan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (chan->chid == priv->max) {
|
||||
nv_error(priv, "no free channels\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* map fifo control registers */
|
||||
chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
|
||||
(chan->chid * size), size);
|
||||
if (!chan->user)
|
||||
return -EFAULT;
|
||||
|
||||
chan->size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
|
||||
{
|
||||
struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
|
||||
unsigned long flags;
|
||||
|
||||
iounmap(chan->user);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->channel[chan->chid] = NULL;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
nouveau_gpuobj_ref(NULL, &chan->pushgpu);
|
||||
nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
|
||||
nouveau_namedb_destroy(&chan->base);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_fifo_channel_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_fifo_chan *chan = (void *)object;
|
||||
nouveau_fifo_channel_destroy(chan);
|
||||
}
|
||||
|
||||
u32
|
||||
_nouveau_fifo_channel_rd32(struct nouveau_object *object, u32 addr)
|
||||
{
|
||||
struct nouveau_fifo_chan *chan = (void *)object;
|
||||
return ioread32_native(chan->user + addr);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_fifo_channel_wr32(struct nouveau_object *object, u32 addr, u32 data)
|
||||
{
|
||||
struct nouveau_fifo_chan *chan = (void *)object;
|
||||
iowrite32_native(data, chan->user + addr);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object)
|
||||
{
|
||||
int engidx = nv_hclass(priv) & 0xff;
|
||||
|
||||
while (object && object->parent) {
|
||||
if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
|
||||
(nv_hclass(object->parent) & 0xff) == engidx)
|
||||
return nouveau_fifo_chan(object)->chid;
|
||||
object = object->parent;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_fifo_destroy(struct nouveau_fifo *priv)
|
||||
{
|
||||
kfree(priv->channel);
|
||||
nouveau_engine_destroy(&priv->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_fifo_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass,
|
||||
int min, int max, int length, void **pobject)
|
||||
{
|
||||
struct nouveau_fifo *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
|
||||
"fifo", length, pobject);
|
||||
priv = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->min = min;
|
||||
priv->max = max;
|
||||
priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
|
||||
if (!priv->channel)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->chid = nouveau_fifo_chid;
|
||||
spin_lock_init(&priv->lock);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/ramht.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/instmem/nv04.h>
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv04.h"
|
||||
|
||||
static struct ramfc_desc
|
||||
nv04_ramfc[] = {
|
||||
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
|
||||
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
|
||||
{ 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
|
||||
{ 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
|
||||
{ 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
|
||||
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
|
||||
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
|
||||
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
int
|
||||
nv04_fifo_object_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object, u32 handle)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)parent;
|
||||
u32 context, chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
if (nv_iclass(object, NV_GPUOBJ_CLASS))
|
||||
context = nv_gpuobj(object)->addr >> 4;
|
||||
else
|
||||
context = 0x00000004; /* just non-zero */
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_DMAOBJ:
|
||||
case NVDEV_ENGINE_SW:
|
||||
context |= 0x00000000;
|
||||
break;
|
||||
case NVDEV_ENGINE_GR:
|
||||
context |= 0x00010000;
|
||||
break;
|
||||
case NVDEV_ENGINE_MPEG:
|
||||
context |= 0x00020000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
context |= 0x80000000; /* valid */
|
||||
context |= chid << 24;
|
||||
|
||||
mutex_lock(&nv_subdev(priv)->mutex);
|
||||
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
|
||||
mutex_unlock(&nv_subdev(priv)->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)parent->engine;
|
||||
mutex_lock(&nv_subdev(priv)->mutex);
|
||||
nouveau_ramht_remove(priv->ramht, cookie);
|
||||
mutex_unlock(&nv_subdev(priv)->mutex);
|
||||
}
|
||||
|
||||
int
|
||||
nv04_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
nv_engctx(object)->addr = nouveau_fifo_chan(parent)->chid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)engine;
|
||||
struct nv04_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
|
||||
0x10000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
|
||||
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
|
||||
chan->ramfc = chan->base.chid * 32;
|
||||
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x10,
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
|
||||
#ifdef __BIG_ENDIAN
|
||||
NV_PFIFO_CACHE1_BIG_ENDIAN |
|
||||
#endif
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_chan_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)object;
|
||||
struct ramfc_desc *c = priv->ramfc_desc;
|
||||
|
||||
do {
|
||||
nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
|
||||
} while ((++c)->bits);
|
||||
|
||||
nouveau_fifo_channel_destroy(&chan->base);
|
||||
}
|
||||
|
||||
int
|
||||
nv04_fifo_chan_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)object;
|
||||
u32 mask = 1 << chan->base.chid;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_channel_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)object;
|
||||
struct nouveau_gpuobj *fctx = priv->ramfc;
|
||||
struct ramfc_desc *c;
|
||||
unsigned long flags;
|
||||
u32 data = chan->ramfc;
|
||||
u32 chid;
|
||||
|
||||
/* prevent fifo context switches */
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
|
||||
|
||||
/* if this channel is active, replace it with a null context */
|
||||
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
|
||||
if (chid == chan->base.chid) {
|
||||
nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
|
||||
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
|
||||
|
||||
c = priv->ramfc_desc;
|
||||
do {
|
||||
u32 rm = ((1ULL << c->bits) - 1) << c->regs;
|
||||
u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
|
||||
u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs;
|
||||
u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
|
||||
nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
|
||||
} while ((++c)->bits);
|
||||
|
||||
c = priv->ramfc_desc;
|
||||
do {
|
||||
nv_wr32(priv, c->regp, 0x00000000);
|
||||
} while ((++c)->bits);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
}
|
||||
|
||||
/* restore normal operation, after disabling dma mode */
|
||||
nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
|
||||
return nouveau_fifo_channel_fini(&chan->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv04_fifo_ofuncs = {
|
||||
.ctor = nv04_fifo_chan_ctor,
|
||||
.dtor = nv04_fifo_chan_dtor,
|
||||
.init = nv04_fifo_chan_init,
|
||||
.fini = nv04_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_fifo_sclass[] = {
|
||||
{ NV03_CHANNEL_DMA_CLASS, &nv04_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
int
|
||||
nv04_fifo_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_fifo_base *base;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
|
||||
0x1000, NVOBJ_FLAG_HEAP, &base);
|
||||
*pobject = nv_object(base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_fifo_context_ctor,
|
||||
.dtor = _nouveau_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
|
||||
__acquires(priv->base.lock)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)pfifo;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
*pflags = flags;
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
|
||||
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
|
||||
|
||||
/* in some cases the puller may be left in an inconsistent state
|
||||
* if you try to stop it while it's busy translating handles.
|
||||
* sometimes you get a CACHE_ERROR, sometimes it just fails
|
||||
* silently; sending incorrect instance offsets to PGRAPH after
|
||||
* it's started up again.
|
||||
*
|
||||
* to avoid this, we invalidate the most recently calculated
|
||||
* instance.
|
||||
*/
|
||||
if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
|
||||
NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
|
||||
nv_warn(priv, "timeout idling puller\n");
|
||||
|
||||
if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
|
||||
NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
|
||||
__releases(priv->base.lock)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)pfifo;
|
||||
unsigned long flags = *pflags;
|
||||
|
||||
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
|
||||
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nv_dma_state_err(u32 state)
|
||||
{
|
||||
static const char * const desc[] = {
|
||||
"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
|
||||
"INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
|
||||
};
|
||||
return desc[(state >> 29) & 0x7];
|
||||
}
|
||||
|
||||
static bool
|
||||
nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
|
||||
{
|
||||
struct nv04_fifo_chan *chan = NULL;
|
||||
struct nouveau_handle *bind;
|
||||
const int subc = (addr >> 13) & 0x7;
|
||||
const int mthd = addr & 0x1ffc;
|
||||
bool handled = false;
|
||||
unsigned long flags;
|
||||
u32 engine;
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
if (likely(chid >= priv->base.min && chid <= priv->base.max))
|
||||
chan = (void *)priv->base.channel[chid];
|
||||
if (unlikely(!chan))
|
||||
goto out;
|
||||
|
||||
switch (mthd) {
|
||||
case 0x0000:
|
||||
bind = nouveau_namedb_get(nv_namedb(chan), data);
|
||||
if (unlikely(!bind))
|
||||
break;
|
||||
|
||||
if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
|
||||
engine = 0x0000000f << (subc * 4);
|
||||
chan->subc[subc] = data;
|
||||
handled = true;
|
||||
|
||||
nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
|
||||
}
|
||||
|
||||
nouveau_namedb_put(bind);
|
||||
break;
|
||||
default:
|
||||
engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
|
||||
if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
|
||||
break;
|
||||
|
||||
bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
|
||||
if (likely(bind)) {
|
||||
if (!nv_call(bind->object, mthd, data))
|
||||
handled = true;
|
||||
nouveau_namedb_put(bind);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return handled;
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(subdev);
|
||||
struct nv04_fifo_priv *priv = (void *)subdev;
|
||||
uint32_t status, reassign;
|
||||
int cnt = 0;
|
||||
|
||||
reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
|
||||
while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
|
||||
uint32_t chid, get;
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
|
||||
|
||||
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
|
||||
get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
|
||||
|
||||
if (status & NV_PFIFO_INTR_CACHE_ERROR) {
|
||||
uint32_t mthd, data;
|
||||
int ptr;
|
||||
|
||||
/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
|
||||
* wrapping on my G80 chips, but CACHE1 isn't big
|
||||
* enough for this much data.. Tests show that it
|
||||
* wraps around to the start at GET=0x800.. No clue
|
||||
* as to why..
|
||||
*/
|
||||
ptr = (get & 0x7ff) >> 2;
|
||||
|
||||
if (device->card_type < NV_40) {
|
||||
mthd = nv_rd32(priv,
|
||||
NV04_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv,
|
||||
NV04_PFIFO_CACHE1_DATA(ptr));
|
||||
} else {
|
||||
mthd = nv_rd32(priv,
|
||||
NV40_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv,
|
||||
NV40_PFIFO_CACHE1_DATA(ptr));
|
||||
}
|
||||
|
||||
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
|
||||
nv_info(priv, "CACHE_ERROR - Ch %d/%d "
|
||||
"Mthd 0x%04x Data 0x%08x\n",
|
||||
chid, (mthd >> 13) & 7, mthd & 0x1ffc,
|
||||
data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0,
|
||||
NV_PFIFO_INTR_CACHE_ERROR);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
|
||||
nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
|
||||
status &= ~NV_PFIFO_INTR_CACHE_ERROR;
|
||||
}
|
||||
|
||||
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
|
||||
u32 dma_get = nv_rd32(priv, 0x003244);
|
||||
u32 dma_put = nv_rd32(priv, 0x003240);
|
||||
u32 push = nv_rd32(priv, 0x003220);
|
||||
u32 state = nv_rd32(priv, 0x003228);
|
||||
|
||||
if (device->card_type == NV_50) {
|
||||
u32 ho_get = nv_rd32(priv, 0x003328);
|
||||
u32 ho_put = nv_rd32(priv, 0x003320);
|
||||
u32 ib_get = nv_rd32(priv, 0x003334);
|
||||
u32 ib_put = nv_rd32(priv, 0x003330);
|
||||
|
||||
nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
|
||||
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
|
||||
"State 0x%08x (err: %s) Push 0x%08x\n",
|
||||
chid, ho_get, dma_get, ho_put,
|
||||
dma_put, ib_get, ib_put, state,
|
||||
nv_dma_state_err(state),
|
||||
push);
|
||||
|
||||
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
|
||||
nv_wr32(priv, 0x003364, 0x00000000);
|
||||
if (dma_get != dma_put || ho_get != ho_put) {
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
nv_wr32(priv, 0x003328, ho_put);
|
||||
} else
|
||||
if (ib_get != ib_put) {
|
||||
nv_wr32(priv, 0x003334, ib_put);
|
||||
}
|
||||
} else {
|
||||
nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
|
||||
"Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
|
||||
chid, dma_get, dma_put, state,
|
||||
nv_dma_state_err(state), push);
|
||||
|
||||
if (dma_get != dma_put)
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x003228, 0x00000000);
|
||||
nv_wr32(priv, 0x003220, 0x00000001);
|
||||
nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
|
||||
status &= ~NV_PFIFO_INTR_DMA_PUSHER;
|
||||
}
|
||||
|
||||
if (status & NV_PFIFO_INTR_SEMAPHORE) {
|
||||
uint32_t sem;
|
||||
|
||||
status &= ~NV_PFIFO_INTR_SEMAPHORE;
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0,
|
||||
NV_PFIFO_INTR_SEMAPHORE);
|
||||
|
||||
sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
|
||||
nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
}
|
||||
|
||||
if (device->card_type == NV_50) {
|
||||
if (status & 0x00000010) {
|
||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
||||
status &= ~0x00000010;
|
||||
nv_wr32(priv, 0x002100, 0x00000010);
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
nv_info(priv, "unknown intr 0x%08x, ch %d\n",
|
||||
status, chid);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, status);
|
||||
status = 0;
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
|
||||
}
|
||||
|
||||
if (status) {
|
||||
nv_info(priv, "still angry after %d spins, halt\n", cnt);
|
||||
nv_wr32(priv, 0x002140, 0);
|
||||
nv_wr32(priv, 0x000140, 0);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x000100, 0x00000100);
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_instmem_priv *imem = nv04_instmem(parent);
|
||||
struct nv04_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_ramht_ref(imem->ramht, &priv->ramht);
|
||||
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
|
||||
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv04_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv04_fifo_sclass;
|
||||
priv->base.pause = nv04_fifo_pause;
|
||||
priv->base.start = nv04_fifo_start;
|
||||
priv->ramfc_desc = nv04_ramfc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object;
|
||||
nouveau_gpuobj_ref(NULL, &priv->ramfc);
|
||||
nouveau_gpuobj_ref(NULL, &priv->ramro);
|
||||
nouveau_ramht_ref(NULL, &priv->ramht);
|
||||
nouveau_fifo_destroy(&priv->base);
|
||||
}
|
||||
|
||||
int
|
||||
nv04_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
|
||||
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
|
||||
((priv->ramht->bits - 9) << 16) |
|
||||
(priv->ramht->base.addr >> 8));
|
||||
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
|
||||
nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv04_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_fifo_ctor,
|
||||
.dtor = nv04_fifo_dtor,
|
||||
.init = nv04_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,178 @@
|
|||
#ifndef __NV04_FIFO_H__
|
||||
#define __NV04_FIFO_H__
|
||||
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#define NV04_PFIFO_DELAY_0 0x00002040
|
||||
#define NV04_PFIFO_DMA_TIMESLICE 0x00002044
|
||||
#define NV04_PFIFO_NEXT_CHANNEL 0x00002050
|
||||
#define NV03_PFIFO_INTR_0 0x00002100
|
||||
#define NV03_PFIFO_INTR_EN_0 0x00002140
|
||||
# define NV_PFIFO_INTR_CACHE_ERROR (1<<0)
|
||||
# define NV_PFIFO_INTR_RUNOUT (1<<4)
|
||||
# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8)
|
||||
# define NV_PFIFO_INTR_DMA_PUSHER (1<<12)
|
||||
# define NV_PFIFO_INTR_DMA_PT (1<<16)
|
||||
# define NV_PFIFO_INTR_SEMAPHORE (1<<20)
|
||||
# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24)
|
||||
#define NV03_PFIFO_RAMHT 0x00002210
|
||||
#define NV03_PFIFO_RAMFC 0x00002214
|
||||
#define NV03_PFIFO_RAMRO 0x00002218
|
||||
#define NV40_PFIFO_RAMFC 0x00002220
|
||||
#define NV03_PFIFO_CACHES 0x00002500
|
||||
#define NV04_PFIFO_MODE 0x00002504
|
||||
#define NV04_PFIFO_DMA 0x00002508
|
||||
#define NV04_PFIFO_SIZE 0x0000250c
|
||||
#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
|
||||
#define NV50_PFIFO_CTX_TABLE__SIZE 128
|
||||
#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
|
||||
#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
|
||||
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
|
||||
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
|
||||
#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
|
||||
#define NV03_PFIFO_CACHE0_PULL0 0x00003040
|
||||
#define NV04_PFIFO_CACHE0_PULL0 0x00003050
|
||||
#define NV04_PFIFO_CACHE0_PULL1 0x00003054
|
||||
#define NV03_PFIFO_CACHE1_PUSH0 0x00003200
|
||||
#define NV03_PFIFO_CACHE1_PUSH1 0x00003204
|
||||
#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8)
|
||||
#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16)
|
||||
#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f
|
||||
#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f
|
||||
#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f
|
||||
#define NV03_PFIFO_CACHE1_PUT 0x00003210
|
||||
#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220
|
||||
#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000
|
||||
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000
|
||||
# define NV_PFIFO_CACHE1_ENDIAN 0x80000000
|
||||
# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF
|
||||
# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000
|
||||
#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228
|
||||
#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c
|
||||
#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230
|
||||
#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240
|
||||
#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244
|
||||
#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248
|
||||
#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
|
||||
#define NV03_PFIFO_CACHE1_PULL0 0x00003240
|
||||
#define NV04_PFIFO_CACHE1_PULL0 0x00003250
|
||||
# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
|
||||
# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
|
||||
#define NV03_PFIFO_CACHE1_PULL1 0x00003250
|
||||
#define NV04_PFIFO_CACHE1_PULL1 0x00003254
|
||||
#define NV04_PFIFO_CACHE1_HASH 0x00003258
|
||||
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260
|
||||
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264
|
||||
#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268
|
||||
#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
|
||||
#define NV03_PFIFO_CACHE1_GET 0x00003270
|
||||
#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
|
||||
#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
|
||||
#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
|
||||
#define NV40_PFIFO_UNK32E4 0x000032E4
|
||||
#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
|
||||
#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8))
|
||||
#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8))
|
||||
#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8))
|
||||
|
||||
struct ramfc_desc {
|
||||
unsigned bits:6;
|
||||
unsigned ctxs:5;
|
||||
unsigned ctxp:8;
|
||||
unsigned regs:5;
|
||||
unsigned regp;
|
||||
};
|
||||
|
||||
struct nv04_fifo_priv {
|
||||
struct nouveau_fifo base;
|
||||
struct ramfc_desc *ramfc_desc;
|
||||
struct nouveau_ramht *ramht;
|
||||
struct nouveau_gpuobj *ramro;
|
||||
struct nouveau_gpuobj *ramfc;
|
||||
};
|
||||
|
||||
struct nv04_fifo_base {
|
||||
struct nouveau_fifo_base base;
|
||||
};
|
||||
|
||||
struct nv04_fifo_chan {
|
||||
struct nouveau_fifo_chan base;
|
||||
u32 subc[8];
|
||||
u32 ramfc;
|
||||
};
|
||||
|
||||
int nv04_fifo_object_attach(struct nouveau_object *,
|
||||
struct nouveau_object *, u32);
|
||||
void nv04_fifo_object_detach(struct nouveau_object *, int);
|
||||
|
||||
void nv04_fifo_chan_dtor(struct nouveau_object *);
|
||||
int nv04_fifo_chan_init(struct nouveau_object *);
|
||||
int nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
|
||||
|
||||
int nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, void *, u32,
|
||||
struct nouveau_object **);
|
||||
|
||||
void nv04_fifo_dtor(struct nouveau_object *);
|
||||
int nv04_fifo_init(struct nouveau_object *);
|
||||
void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
|
||||
void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/instmem/nv04.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv04.h"
|
||||
|
||||
static struct ramfc_desc
|
||||
nv10_ramfc[] = {
|
||||
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
|
||||
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
|
||||
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
|
||||
{ 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
|
||||
{ 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
|
||||
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
|
||||
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
|
||||
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
|
||||
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv10_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)engine;
|
||||
struct nv04_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
|
||||
0x10000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
|
||||
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
|
||||
chan->ramfc = chan->base.chid * 32;
|
||||
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
|
||||
#ifdef __BIG_ENDIAN
|
||||
NV_PFIFO_CACHE1_BIG_ENDIAN |
|
||||
#endif
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv10_fifo_ofuncs = {
|
||||
.ctor = nv10_fifo_chan_ctor,
|
||||
.dtor = nv04_fifo_chan_dtor,
|
||||
.init = nv04_fifo_chan_init,
|
||||
.fini = nv04_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv10_fifo_sclass[] = {
|
||||
{ NV10_CHANNEL_DMA_CLASS, &nv10_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv10_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x10),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_fifo_context_ctor,
|
||||
.dtor = _nouveau_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_instmem_priv *imem = nv04_instmem(parent);
|
||||
struct nv04_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_ramht_ref(imem->ramht, &priv->ramht);
|
||||
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
|
||||
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv10_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv10_fifo_sclass;
|
||||
priv->base.pause = nv04_fifo_pause;
|
||||
priv->base.start = nv04_fifo_start;
|
||||
priv->ramfc_desc = nv10_ramfc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv10_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x10),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv10_fifo_ctor,
|
||||
.dtor = nv04_fifo_dtor,
|
||||
.init = nv04_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/instmem/nv04.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv04.h"
|
||||
|
||||
static struct ramfc_desc
|
||||
nv17_ramfc[] = {
|
||||
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
|
||||
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
|
||||
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
|
||||
{ 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
|
||||
{ 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
|
||||
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
|
||||
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
|
||||
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
|
||||
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
|
||||
{ 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
|
||||
{ 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
|
||||
{ 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
|
||||
{ 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
|
||||
{ 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv17_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)engine;
|
||||
struct nv04_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
|
||||
0x10000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG), /* NV31- */
|
||||
&chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
|
||||
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
|
||||
chan->ramfc = chan->base.chid * 64;
|
||||
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
|
||||
#ifdef __BIG_ENDIAN
|
||||
NV_PFIFO_CACHE1_BIG_ENDIAN |
|
||||
#endif
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv17_fifo_ofuncs = {
|
||||
.ctor = nv17_fifo_chan_ctor,
|
||||
.dtor = nv04_fifo_chan_dtor,
|
||||
.init = nv04_fifo_chan_init,
|
||||
.fini = nv04_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv17_fifo_sclass[] = {
|
||||
{ NV17_CHANNEL_DMA_CLASS, &nv17_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv17_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x17),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_fifo_context_ctor,
|
||||
.dtor = _nouveau_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_instmem_priv *imem = nv04_instmem(parent);
|
||||
struct nv04_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_ramht_ref(imem->ramht, &priv->ramht);
|
||||
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
|
||||
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv17_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv17_fifo_sclass;
|
||||
priv->base.pause = nv04_fifo_pause;
|
||||
priv->base.start = nv04_fifo_start;
|
||||
priv->ramfc_desc = nv17_ramfc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv17_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
|
||||
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
|
||||
((priv->ramht->bits - 9) << 16) |
|
||||
(priv->ramht->base.addr >> 8));
|
||||
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
|
||||
nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv17_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x17),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv17_fifo_ctor,
|
||||
.dtor = nv04_fifo_dtor,
|
||||
.init = nv17_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/instmem/nv04.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv04.h"
|
||||
|
||||
static struct ramfc_desc
|
||||
nv40_ramfc[] = {
|
||||
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
|
||||
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
|
||||
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
|
||||
{ 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
|
||||
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
|
||||
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
|
||||
{ 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
|
||||
{ 2, 28, 0x18, 28, 0x002058 },
|
||||
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
|
||||
{ 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
|
||||
{ 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
|
||||
{ 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
|
||||
{ 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
|
||||
{ 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
|
||||
{ 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
|
||||
{ 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
|
||||
{ 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
|
||||
{ 32, 0, 0x40, 0, 0x0032e4 },
|
||||
{ 32, 0, 0x44, 0, 0x0032e8 },
|
||||
{ 32, 0, 0x4c, 0, 0x002088 },
|
||||
{ 32, 0, 0x50, 0, 0x003300 },
|
||||
{ 32, 0, 0x54, 0, 0x00330c },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv40_fifo_object_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object, u32 handle)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)parent;
|
||||
u32 context, chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
if (nv_iclass(object, NV_GPUOBJ_CLASS))
|
||||
context = nv_gpuobj(object)->addr >> 4;
|
||||
else
|
||||
context = 0x00000004; /* just non-zero */
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_DMAOBJ:
|
||||
case NVDEV_ENGINE_SW:
|
||||
context |= 0x00000000;
|
||||
break;
|
||||
case NVDEV_ENGINE_GR:
|
||||
context |= 0x00100000;
|
||||
break;
|
||||
case NVDEV_ENGINE_MPEG:
|
||||
context |= 0x00200000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
context |= chid << 23;
|
||||
|
||||
mutex_lock(&nv_subdev(priv)->mutex);
|
||||
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
|
||||
mutex_unlock(&nv_subdev(priv)->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *engctx)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)parent;
|
||||
unsigned long flags;
|
||||
u32 reg, ctx;
|
||||
|
||||
switch (nv_engidx(engctx->engine)) {
|
||||
case NVDEV_ENGINE_SW:
|
||||
return 0;
|
||||
case NVDEV_ENGINE_GR:
|
||||
reg = 0x32e0;
|
||||
ctx = 0x38;
|
||||
break;
|
||||
case NVDEV_ENGINE_MPEG:
|
||||
reg = 0x330c;
|
||||
ctx = 0x54;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
|
||||
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
|
||||
|
||||
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
|
||||
nv_wr32(priv, reg, nv_engctx(engctx)->addr);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
|
||||
|
||||
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
struct nouveau_object *engctx)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv04_fifo_chan *chan = (void *)parent;
|
||||
unsigned long flags;
|
||||
u32 reg, ctx;
|
||||
|
||||
switch (nv_engidx(engctx->engine)) {
|
||||
case NVDEV_ENGINE_SW:
|
||||
return 0;
|
||||
case NVDEV_ENGINE_GR:
|
||||
reg = 0x32e0;
|
||||
ctx = 0x38;
|
||||
break;
|
||||
case NVDEV_ENGINE_MPEG:
|
||||
reg = 0x330c;
|
||||
ctx = 0x54;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
|
||||
|
||||
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
|
||||
nv_wr32(priv, reg, 0x00000000);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
|
||||
|
||||
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)engine;
|
||||
struct nv04_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
|
||||
0x1000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nv40_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nv40_fifo_context_detach;
|
||||
nv_parent(chan)->object_attach = nv40_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
|
||||
chan->ramfc = chan->base.chid * 128;
|
||||
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
|
||||
#ifdef __BIG_ENDIAN
|
||||
NV_PFIFO_CACHE1_BIG_ENDIAN |
|
||||
#endif
|
||||
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
|
||||
nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv40_fifo_ofuncs = {
|
||||
.ctor = nv40_fifo_chan_ctor,
|
||||
.dtor = nv04_fifo_chan_dtor,
|
||||
.init = nv04_fifo_chan_init,
|
||||
.fini = nv04_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv40_fifo_sclass[] = {
|
||||
{ NV40_CHANNEL_DMA_CLASS, &nv40_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv40_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x40),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_fifo_context_ctor,
|
||||
.dtor = _nouveau_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_instmem_priv *imem = nv04_instmem(parent);
|
||||
struct nv04_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_ramht_ref(imem->ramht, &priv->ramht);
|
||||
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
|
||||
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv40_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv40_fifo_sclass;
|
||||
priv->base.pause = nv04_fifo_pause;
|
||||
priv->base.start = nv04_fifo_start;
|
||||
priv->ramfc_desc = nv40_ramfc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_fifo_priv *priv = (void *)object;
|
||||
struct nouveau_fb *pfb = nouveau_fb(object);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x002040, 0x000000ff);
|
||||
nv_wr32(priv, 0x002044, 0x2101ffff);
|
||||
nv_wr32(priv, 0x002058, 0x00000001);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
|
||||
((priv->ramht->bits - 9) << 16) |
|
||||
(priv->ramht->base.addr >> 8));
|
||||
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
|
||||
|
||||
switch (nv_device(priv)->chipset) {
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
case 0x4b:
|
||||
nv_wr32(priv, 0x002230, 0x00000001);
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x45:
|
||||
case 0x48:
|
||||
nv_wr32(priv, 0x002220, 0x00030002);
|
||||
break;
|
||||
default:
|
||||
nv_wr32(priv, 0x002230, 0x00000000);
|
||||
nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 +
|
||||
priv->ramfc->addr) >> 16) |
|
||||
0x00030000);
|
||||
break;
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv40_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x40),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv40_fifo_ctor,
|
||||
.dtor = nv04_fifo_dtor,
|
||||
.init = nv40_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/bar.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv50.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nouveau_gpuobj *cur;
|
||||
int i, p;
|
||||
|
||||
cur = priv->playlist[priv->cur_playlist];
|
||||
priv->cur_playlist = !priv->cur_playlist;
|
||||
|
||||
for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
|
||||
if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
|
||||
nv_wo32(cur, p++ * 4, i);
|
||||
}
|
||||
|
||||
bar->flush(bar);
|
||||
|
||||
nv_wr32(priv, 0x0032f4, cur->addr >> 12);
|
||||
nv_wr32(priv, 0x0032ec, p);
|
||||
nv_wr32(priv, 0x002500, 0x00000101);
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent->parent;
|
||||
struct nouveau_gpuobj *ectx = (void *)object;
|
||||
u64 limit = ectx->addr + ectx->size - 1;
|
||||
u64 start = ectx->addr;
|
||||
u32 addr;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : addr = 0x0000; break;
|
||||
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
|
||||
nv_wo32(base->eng, addr + 0x00, 0x00190000);
|
||||
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
|
||||
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
|
||||
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
|
||||
upper_32_bits(start));
|
||||
nv_wo32(base->eng, addr + 0x10, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x14, 0x00000000);
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv50_fifo_base *base = (void *)parent->parent;
|
||||
struct nv50_fifo_chan *chan = (void *)parent;
|
||||
u32 addr, me;
|
||||
int ret = 0;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : addr = 0x0000; break;
|
||||
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_wo32(base->eng, addr + 0x00, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x04, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x08, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x10, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x14, 0x00000000);
|
||||
bar->flush(bar);
|
||||
|
||||
/* HW bug workaround:
|
||||
*
|
||||
* PFIFO will hang forever if the connected engines don't report
|
||||
* that they've processed the context switch request.
|
||||
*
|
||||
* In order for the kickoff to work, we need to ensure all the
|
||||
* connected engines are in a state where they can answer.
|
||||
*
|
||||
* Newer chipsets don't seem to suffer from this issue, and well,
|
||||
* there's also a "ignore these engines" bitmask reg we can use
|
||||
* if we hit the issue there..
|
||||
*/
|
||||
me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
|
||||
|
||||
/* do the kickoff... */
|
||||
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
|
||||
if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
|
||||
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
|
||||
if (suspend)
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x00b860, me);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_object_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object, u32 handle)
|
||||
{
|
||||
struct nv50_fifo_chan *chan = (void *)parent;
|
||||
u32 context;
|
||||
|
||||
if (nv_iclass(object, NV_GPUOBJ_CLASS))
|
||||
context = nv_gpuobj(object)->node->offset >> 4;
|
||||
else
|
||||
context = 0x00000004; /* just non-zero */
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_DMAOBJ:
|
||||
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
|
||||
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
|
||||
case NVDEV_ENGINE_MPEG : context |= 0x00200000; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
|
||||
}
|
||||
|
||||
void
|
||||
nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
|
||||
{
|
||||
struct nv50_fifo_chan *chan = (void *)parent;
|
||||
nouveau_ramht_remove(chan->ramht, cookie);
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent;
|
||||
struct nv50_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
|
||||
0x2000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nv50_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nv50_fifo_context_detach;
|
||||
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
|
||||
|
||||
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x3c, 0x003f6078);
|
||||
nv_wo32(base->ramfc, 0x44, 0x01003fff);
|
||||
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
|
||||
nv_wo32(base->ramfc, 0x4c, 0xffffffff);
|
||||
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
|
||||
nv_wo32(base->ramfc, 0x78, 0x00000000);
|
||||
nv_wo32(base->ramfc, 0x7c, 0x30000001);
|
||||
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
|
||||
(4 << 24) /* SEARCH_FULL */ |
|
||||
(chan->ramht->base.node->offset >> 4));
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_channel_ind_class *args = data;
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent;
|
||||
struct nv50_fifo_chan *chan;
|
||||
u64 ioffset, ilength;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
|
||||
0x2000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nv50_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nv50_fifo_context_detach;
|
||||
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
|
||||
|
||||
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ioffset = args->ioffset;
|
||||
ilength = log2i(args->ilength / 8);
|
||||
|
||||
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
|
||||
nv_wo32(base->ramfc, 0x44, 0x01003fff);
|
||||
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
|
||||
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
|
||||
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
|
||||
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
|
||||
nv_wo32(base->ramfc, 0x78, 0x00000000);
|
||||
nv_wo32(base->ramfc, 0x7c, 0x30000001);
|
||||
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
|
||||
(4 << 24) /* SEARCH_FULL */ |
|
||||
(chan->ramht->base.node->offset >> 4));
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv50_fifo_chan_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_chan *chan = (void *)object;
|
||||
nouveau_ramht_ref(NULL, &chan->ramht);
|
||||
nouveau_fifo_channel_destroy(&chan->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fifo_chan_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv50_fifo_base *base = (void *)object->parent;
|
||||
struct nv50_fifo_chan *chan = (void *)object;
|
||||
struct nouveau_gpuobj *ramfc = base->ramfc;
|
||||
u32 chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_channel_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
|
||||
nv50_fifo_playlist_update(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv50_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv50_fifo_chan *chan = (void *)object;
|
||||
u32 chid = chan->base.chid;
|
||||
|
||||
/* remove channel from playlist, fifo will unload context */
|
||||
nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
|
||||
nv50_fifo_playlist_update(priv);
|
||||
nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
|
||||
|
||||
return nouveau_fifo_channel_fini(&chan->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv50_fifo_ofuncs_dma = {
|
||||
.ctor = nv50_fifo_chan_ctor_dma,
|
||||
.dtor = nv50_fifo_chan_dtor,
|
||||
.init = nv50_fifo_chan_init,
|
||||
.fini = nv50_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv50_fifo_ofuncs_ind = {
|
||||
.ctor = nv50_fifo_chan_ctor_ind,
|
||||
.dtor = nv50_fifo_chan_dtor,
|
||||
.init = nv50_fifo_chan_init,
|
||||
.fini = nv50_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv50_fifo_sclass[] = {
|
||||
{ NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma },
|
||||
{ NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv50_fifo_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_fifo_base *base;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
|
||||
0x1000, NVOBJ_FLAG_HEAP, &base);
|
||||
*pobject = nv_object(base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0x1000,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1200, 0,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, 0,
|
||||
&base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv50_fifo_context_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_base *base = (void *)object;
|
||||
nouveau_vm_ref(NULL, &base->vm, base->pgd);
|
||||
nouveau_gpuobj_ref(NULL, &base->pgd);
|
||||
nouveau_gpuobj_ref(NULL, &base->eng);
|
||||
nouveau_gpuobj_ref(NULL, &base->ramfc);
|
||||
nouveau_gpuobj_ref(NULL, &base->cache);
|
||||
nouveau_fifo_context_destroy(&base->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv50_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_fifo_context_ctor,
|
||||
.dtor = nv50_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
|
||||
&priv->playlist[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
|
||||
&priv->playlist[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv50_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv50_fifo_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv50_fifo_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_priv *priv = (void *)object;
|
||||
|
||||
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
|
||||
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
|
||||
|
||||
nouveau_fifo_destroy(&priv->base);
|
||||
}
|
||||
|
||||
int
|
||||
nv50_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
|
||||
nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
|
||||
nv_wr32(priv, 0x00250c, 0x6f3cfc34);
|
||||
nv_wr32(priv, 0x002044, 0x01003fff);
|
||||
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xffffffff);
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
|
||||
nv50_fifo_playlist_update(priv);
|
||||
|
||||
nv_wr32(priv, 0x003200, 0x00000001);
|
||||
nv_wr32(priv, 0x003250, 0x00000001);
|
||||
nv_wr32(priv, 0x002500, 0x00000001);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv50_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_fifo_ctor,
|
||||
.dtor = nv50_fifo_dtor,
|
||||
.init = nv50_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef __NV50_FIFO_H__
|
||||
#define __NV50_FIFO_H__
|
||||
|
||||
struct nv50_fifo_priv {
|
||||
struct nouveau_fifo base;
|
||||
struct nouveau_gpuobj *playlist[2];
|
||||
int cur_playlist;
|
||||
};
|
||||
|
||||
struct nv50_fifo_base {
|
||||
struct nouveau_fifo_base base;
|
||||
struct nouveau_gpuobj *ramfc;
|
||||
struct nouveau_gpuobj *cache;
|
||||
struct nouveau_gpuobj *eng;
|
||||
struct nouveau_gpuobj *pgd;
|
||||
struct nouveau_vm *vm;
|
||||
};
|
||||
|
||||
struct nv50_fifo_chan {
|
||||
struct nouveau_fifo_chan base;
|
||||
u32 subc[8];
|
||||
struct nouveau_ramht *ramht;
|
||||
};
|
||||
|
||||
void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
|
||||
|
||||
void nv50_fifo_object_detach(struct nouveau_object *, int);
|
||||
void nv50_fifo_chan_dtor(struct nouveau_object *);
|
||||
int nv50_fifo_chan_fini(struct nouveau_object *, bool);
|
||||
|
||||
void nv50_fifo_context_dtor(struct nouveau_object *);
|
||||
|
||||
void nv50_fifo_dtor(struct nouveau_object *);
|
||||
int nv50_fifo_init(struct nouveau_object *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/client.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/bar.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv50.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent->parent;
|
||||
struct nouveau_gpuobj *ectx = (void *)object;
|
||||
u64 limit = ectx->addr + ectx->size - 1;
|
||||
u64 start = ectx->addr;
|
||||
u32 addr;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : addr = 0x0020; break;
|
||||
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
|
||||
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
|
||||
case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
|
||||
nv_wo32(base->eng, addr + 0x00, 0x00190000);
|
||||
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
|
||||
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
|
||||
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
|
||||
upper_32_bits(start));
|
||||
nv_wo32(base->eng, addr + 0x10, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x14, 0x00000000);
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nv50_fifo_base *base = (void *)parent->parent;
|
||||
struct nv50_fifo_chan *chan = (void *)parent;
|
||||
u32 addr, save, engn;
|
||||
bool done;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
|
||||
case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
|
||||
case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
|
||||
case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_wo32(base->eng, addr + 0x00, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x04, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x08, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x10, 0x00000000);
|
||||
nv_wo32(base->eng, addr + 0x14, 0x00000000);
|
||||
bar->flush(bar);
|
||||
|
||||
save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
|
||||
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
|
||||
done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
|
||||
nv_wr32(priv, 0x002520, save);
|
||||
if (!done) {
|
||||
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_object_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object, u32 handle)
|
||||
{
|
||||
struct nv50_fifo_chan *chan = (void *)parent;
|
||||
u32 context;
|
||||
|
||||
if (nv_iclass(object, NV_GPUOBJ_CLASS))
|
||||
context = nv_gpuobj(object)->node->offset >> 4;
|
||||
else
|
||||
context = 0x00000004; /* just non-zero */
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_DMAOBJ:
|
||||
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
|
||||
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
|
||||
case NVDEV_ENGINE_MPEG :
|
||||
case NVDEV_ENGINE_PPP : context |= 0x00200000; break;
|
||||
case NVDEV_ENGINE_ME :
|
||||
case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
|
||||
case NVDEV_ENGINE_VP : context |= 0x00400000; break;
|
||||
case NVDEV_ENGINE_CRYPT :
|
||||
case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break;
|
||||
case NVDEV_ENGINE_BSP : context |= 0x00600000; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent;
|
||||
struct nv50_fifo_chan *chan;
|
||||
struct nv03_channel_dma_class *args = data;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
|
||||
0x2000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG) |
|
||||
(1 << NVDEV_ENGINE_ME) |
|
||||
(1 << NVDEV_ENGINE_VP) |
|
||||
(1 << NVDEV_ENGINE_CRYPT) |
|
||||
(1 << NVDEV_ENGINE_BSP) |
|
||||
(1 << NVDEV_ENGINE_PPP) |
|
||||
(1 << NVDEV_ENGINE_COPY0) |
|
||||
(1 << NVDEV_ENGINE_UNK1C1), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nv84_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nv84_fifo_context_detach;
|
||||
nv_parent(chan)->object_attach = nv84_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
|
||||
|
||||
nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset));
|
||||
nv_wo32(base->ramfc, 0x3c, 0x003f6078);
|
||||
nv_wo32(base->ramfc, 0x44, 0x01003fff);
|
||||
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
|
||||
nv_wo32(base->ramfc, 0x4c, 0xffffffff);
|
||||
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
|
||||
nv_wo32(base->ramfc, 0x78, 0x00000000);
|
||||
nv_wo32(base->ramfc, 0x7c, 0x30000001);
|
||||
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
|
||||
(4 << 24) /* SEARCH_FULL */ |
|
||||
(chan->ramht->base.node->offset >> 4));
|
||||
nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
|
||||
nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nv50_fifo_base *base = (void *)parent;
|
||||
struct nv50_fifo_chan *chan;
|
||||
struct nv50_channel_ind_class *args = data;
|
||||
u64 ioffset, ilength;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
|
||||
0x2000, args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_DMAOBJ) |
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_MPEG) |
|
||||
(1 << NVDEV_ENGINE_ME) |
|
||||
(1 << NVDEV_ENGINE_VP) |
|
||||
(1 << NVDEV_ENGINE_CRYPT) |
|
||||
(1 << NVDEV_ENGINE_BSP) |
|
||||
(1 << NVDEV_ENGINE_PPP) |
|
||||
(1 << NVDEV_ENGINE_COPY0) |
|
||||
(1 << NVDEV_ENGINE_UNK1C1), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nv84_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nv84_fifo_context_detach;
|
||||
nv_parent(chan)->object_attach = nv84_fifo_object_attach;
|
||||
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
|
||||
|
||||
ioffset = args->ioffset;
|
||||
ilength = log2i(args->ilength / 8);
|
||||
|
||||
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
|
||||
nv_wo32(base->ramfc, 0x44, 0x01003fff);
|
||||
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
|
||||
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
|
||||
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
|
||||
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
|
||||
nv_wo32(base->ramfc, 0x78, 0x00000000);
|
||||
nv_wo32(base->ramfc, 0x7c, 0x30000001);
|
||||
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
|
||||
(4 << 24) /* SEARCH_FULL */ |
|
||||
(chan->ramht->base.node->offset >> 4));
|
||||
nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
|
||||
nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_chan_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_fifo_priv *priv = (void *)object->engine;
|
||||
struct nv50_fifo_base *base = (void *)object->parent;
|
||||
struct nv50_fifo_chan *chan = (void *)object;
|
||||
struct nouveau_gpuobj *ramfc = base->ramfc;
|
||||
u32 chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_channel_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
|
||||
nv50_fifo_playlist_update(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv84_fifo_ofuncs_dma = {
|
||||
.ctor = nv84_fifo_chan_ctor_dma,
|
||||
.dtor = nv50_fifo_chan_dtor,
|
||||
.init = nv84_fifo_chan_init,
|
||||
.fini = nv50_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nv84_fifo_ofuncs_ind = {
|
||||
.ctor = nv84_fifo_chan_ctor_ind,
|
||||
.dtor = nv50_fifo_chan_dtor,
|
||||
.init = nv84_fifo_chan_init,
|
||||
.fini = nv50_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_fifo_sclass[] = {
|
||||
{ NV84_CHANNEL_DMA_CLASS, &nv84_fifo_ofuncs_dma },
|
||||
{ NV84_CHANNEL_IND_CLASS, &nv84_fifo_ofuncs_ind },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - basically just the instmem reserved for the channel
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_fifo_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_fifo_base *base;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
|
||||
0x1000, NVOBJ_FLAG_HEAP, &base);
|
||||
*pobject = nv_object(base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0,
|
||||
0, &base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1000, 0x400,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0100, 0x100,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv84_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_fifo_context_ctor,
|
||||
.dtor = nv50_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
|
||||
&priv->playlist[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
|
||||
&priv->playlist[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv84_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nv84_fifo_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv84_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0x84),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv84_fifo_ctor,
|
||||
.dtor = nv50_fifo_dtor,
|
||||
.init = nv50_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,647 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/vm.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
struct nvc0_fifo_priv {
|
||||
struct nouveau_fifo base;
|
||||
struct nouveau_gpuobj *playlist[2];
|
||||
int cur_playlist;
|
||||
struct {
|
||||
struct nouveau_gpuobj *mem;
|
||||
struct nouveau_vma bar;
|
||||
} user;
|
||||
int spoon_nr;
|
||||
};
|
||||
|
||||
struct nvc0_fifo_base {
|
||||
struct nouveau_fifo_base base;
|
||||
struct nouveau_gpuobj *pgd;
|
||||
struct nouveau_vm *vm;
|
||||
};
|
||||
|
||||
struct nvc0_fifo_chan {
|
||||
struct nouveau_fifo_chan base;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nouveau_gpuobj *cur;
|
||||
int i, p;
|
||||
|
||||
cur = priv->playlist[priv->cur_playlist];
|
||||
priv->cur_playlist = !priv->cur_playlist;
|
||||
|
||||
for (i = 0, p = 0; i < 128; i++) {
|
||||
if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1))
|
||||
continue;
|
||||
nv_wo32(cur, p + 0, i);
|
||||
nv_wo32(cur, p + 4, 0x00000004);
|
||||
p += 8;
|
||||
}
|
||||
bar->flush(bar);
|
||||
|
||||
nv_wr32(priv, 0x002270, cur->addr >> 12);
|
||||
nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
|
||||
if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
|
||||
nv_error(priv, "playlist update failed\n");
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nvc0_fifo_base *base = (void *)parent->parent;
|
||||
struct nouveau_engctx *ectx = (void *)object;
|
||||
u32 addr;
|
||||
int ret;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : addr = 0x0210; break;
|
||||
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
|
||||
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ectx->vma.node) {
|
||||
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
|
||||
NV_MEM_ACCESS_RW, &ectx->vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
|
||||
}
|
||||
|
||||
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
|
||||
nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nvc0_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nvc0_fifo_base *base = (void *)parent->parent;
|
||||
struct nvc0_fifo_chan *chan = (void *)parent;
|
||||
u32 addr;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR : addr = 0x0210; break;
|
||||
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
|
||||
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_wo32(base, addr + 0x00, 0x00000000);
|
||||
nv_wo32(base, addr + 0x04, 0x00000000);
|
||||
bar->flush(bar);
|
||||
|
||||
nv_wr32(priv, 0x002634, chan->base.chid);
|
||||
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
|
||||
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nvc0_fifo_priv *priv = (void *)engine;
|
||||
struct nvc0_fifo_base *base = (void *)parent;
|
||||
struct nvc0_fifo_chan *chan;
|
||||
struct nv50_channel_ind_class *args = data;
|
||||
u64 usermem, ioffset, ilength;
|
||||
int ret, i;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
|
||||
priv->user.bar.offset, 0x1000,
|
||||
args->pushbuf,
|
||||
(1 << NVDEV_ENGINE_SW) |
|
||||
(1 << NVDEV_ENGINE_GR) |
|
||||
(1 << NVDEV_ENGINE_COPY0) |
|
||||
(1 << NVDEV_ENGINE_COPY1), &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
|
||||
|
||||
usermem = chan->base.chid * 0x1000;
|
||||
ioffset = args->ioffset;
|
||||
ilength = log2i(args->ilength / 8);
|
||||
|
||||
for (i = 0; i < 0x1000; i += 4)
|
||||
nv_wo32(priv->user.mem, usermem + i, 0x00000000);
|
||||
|
||||
nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
|
||||
nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
|
||||
nv_wo32(base, 0x10, 0x0000face);
|
||||
nv_wo32(base, 0x30, 0xfffff902);
|
||||
nv_wo32(base, 0x48, lower_32_bits(ioffset));
|
||||
nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
|
||||
nv_wo32(base, 0x54, 0x00000002);
|
||||
nv_wo32(base, 0x84, 0x20400000);
|
||||
nv_wo32(base, 0x94, 0x30000001);
|
||||
nv_wo32(base, 0x9c, 0x00000100);
|
||||
nv_wo32(base, 0xa4, 0x1f1f1f1f);
|
||||
nv_wo32(base, 0xa8, 0x1f1f1f1f);
|
||||
nv_wo32(base, 0xac, 0x0000001f);
|
||||
nv_wo32(base, 0xb8, 0xf8000000);
|
||||
nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
|
||||
nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_chan_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
|
||||
struct nvc0_fifo_priv *priv = (void *)object->engine;
|
||||
struct nvc0_fifo_chan *chan = (void *)object;
|
||||
u32 chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_channel_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
|
||||
nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
|
||||
nvc0_fifo_playlist_update(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = (void *)object->engine;
|
||||
struct nvc0_fifo_chan *chan = (void *)object;
|
||||
u32 chid = chan->base.chid;
|
||||
|
||||
nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
|
||||
nvc0_fifo_playlist_update(priv);
|
||||
nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
|
||||
|
||||
return nouveau_fifo_channel_fini(&chan->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nvc0_fifo_ofuncs = {
|
||||
.ctor = nvc0_fifo_chan_ctor,
|
||||
.dtor = _nouveau_fifo_channel_dtor,
|
||||
.init = nvc0_fifo_chan_init,
|
||||
.fini = nvc0_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_fifo_sclass[] = {
|
||||
{ NVC0_CHANNEL_IND_CLASS, &nvc0_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - instmem heap and vm setup
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nvc0_fifo_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_fifo_base *base;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
|
||||
0x1000, NVOBJ_FLAG_ZERO_ALLOC |
|
||||
NVOBJ_FLAG_HEAP, &base);
|
||||
*pobject = nv_object(base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
|
||||
nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
|
||||
nv_wo32(base, 0x0208, 0xffffffff);
|
||||
nv_wo32(base, 0x020c, 0x000000ff);
|
||||
|
||||
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_context_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nvc0_fifo_base *base = (void *)object;
|
||||
nouveau_vm_ref(NULL, &base->vm, base->pgd);
|
||||
nouveau_gpuobj_ref(NULL, &base->pgd);
|
||||
nouveau_fifo_context_destroy(&base->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nvc0_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_fifo_context_ctor,
|
||||
.dtor = nvc0_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nvc0_fifo_fault_unit[] = {
|
||||
{ 0x00, "PGRAPH" },
|
||||
{ 0x03, "PEEPHOLE" },
|
||||
{ 0x04, "BAR1" },
|
||||
{ 0x05, "BAR3" },
|
||||
{ 0x07, "PFIFO" },
|
||||
{ 0x10, "PBSP" },
|
||||
{ 0x11, "PPPP" },
|
||||
{ 0x13, "PCOUNTER" },
|
||||
{ 0x14, "PVP" },
|
||||
{ 0x15, "PCOPY0" },
|
||||
{ 0x16, "PCOPY1" },
|
||||
{ 0x17, "PDAEMON" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nvc0_fifo_fault_reason[] = {
|
||||
{ 0x00, "PT_NOT_PRESENT" },
|
||||
{ 0x01, "PT_TOO_SHORT" },
|
||||
{ 0x02, "PAGE_NOT_PRESENT" },
|
||||
{ 0x03, "VM_LIMIT_EXCEEDED" },
|
||||
{ 0x04, "NO_CHANNEL" },
|
||||
{ 0x05, "PAGE_SYSTEM_ONLY" },
|
||||
{ 0x06, "PAGE_READ_ONLY" },
|
||||
{ 0x0a, "COMPRESSED_SYSRAM" },
|
||||
{ 0x0c, "INVALID_STORAGE_TYPE" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
|
||||
{ 0x01, "PCOPY0" },
|
||||
{ 0x02, "PCOPY1" },
|
||||
{ 0x04, "DISPATCH" },
|
||||
{ 0x05, "CTXCTL" },
|
||||
{ 0x06, "PFIFO" },
|
||||
{ 0x07, "BAR_READ" },
|
||||
{ 0x08, "BAR_WRITE" },
|
||||
{ 0x0b, "PVP" },
|
||||
{ 0x0c, "PPPP" },
|
||||
{ 0x0d, "PBSP" },
|
||||
{ 0x11, "PCOUNTER" },
|
||||
{ 0x12, "PDAEMON" },
|
||||
{ 0x14, "CCACHE" },
|
||||
{ 0x15, "CCACHE_POST" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
|
||||
{ 0x01, "TEX" },
|
||||
{ 0x0c, "ESETUP" },
|
||||
{ 0x0e, "CTXCTL" },
|
||||
{ 0x0f, "PROP" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = {
|
||||
/* { 0x00008000, "" } seen with null ib push */
|
||||
{ 0x00200000, "ILLEGAL_MTHD" },
|
||||
{ 0x00800000, "EMPTY_SUBC" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
|
||||
{
|
||||
u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
|
||||
u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
|
||||
u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
|
||||
u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
|
||||
u32 client = (stat & 0x00001f00) >> 8;
|
||||
|
||||
switch (unit) {
|
||||
case 3: /* PEEPHOLE */
|
||||
nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
|
||||
break;
|
||||
case 4: /* BAR1 */
|
||||
nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
|
||||
break;
|
||||
case 5: /* BAR3 */
|
||||
nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
|
||||
"write" : "read", (u64)vahi << 32 | valo);
|
||||
nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
|
||||
printk("] from ");
|
||||
nouveau_enum_print(nvc0_fifo_fault_unit, unit);
|
||||
if (stat & 0x00000040) {
|
||||
printk("/");
|
||||
nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
|
||||
} else {
|
||||
printk("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
|
||||
}
|
||||
printk(" on channel 0x%010llx\n", (u64)inst << 12);
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
|
||||
{
|
||||
struct nvc0_fifo_chan *chan = NULL;
|
||||
struct nouveau_handle *bind;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
if (likely(chid >= priv->base.min && chid <= priv->base.max))
|
||||
chan = (void *)priv->base.channel[chid];
|
||||
if (unlikely(!chan))
|
||||
goto out;
|
||||
|
||||
bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
|
||||
if (likely(bind)) {
|
||||
if (!mthd || !nv_call(bind->object, mthd, data))
|
||||
ret = 0;
|
||||
nouveau_namedb_put(bind);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
|
||||
{
|
||||
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
|
||||
u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
|
||||
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
|
||||
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
|
||||
u32 subc = (addr & 0x00070000) >> 16;
|
||||
u32 mthd = (addr & 0x00003ffc);
|
||||
u32 show = stat;
|
||||
|
||||
if (stat & 0x00200000) {
|
||||
if (mthd == 0x0054) {
|
||||
if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
|
||||
show &= ~0x00200000;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat & 0x00800000) {
|
||||
if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
|
||||
show &= ~0x00800000;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "SUBFIFO%d:", unit);
|
||||
nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
|
||||
printk("\n");
|
||||
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
unit, chid, subc, mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
|
||||
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = (void *)subdev;
|
||||
u32 mask = nv_rd32(priv, 0x002140);
|
||||
u32 stat = nv_rd32(priv, 0x002100) & mask;
|
||||
|
||||
if (stat & 0x00000100) {
|
||||
nv_info(priv, "unknown status 0x00000100\n");
|
||||
nv_wr32(priv, 0x002100, 0x00000100);
|
||||
stat &= ~0x00000100;
|
||||
}
|
||||
|
||||
if (stat & 0x10000000) {
|
||||
u32 units = nv_rd32(priv, 0x00259c);
|
||||
u32 u = units;
|
||||
|
||||
while (u) {
|
||||
int i = ffs(u) - 1;
|
||||
nvc0_fifo_isr_vm_fault(priv, i);
|
||||
u &= ~(1 << i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x00259c, units);
|
||||
stat &= ~0x10000000;
|
||||
}
|
||||
|
||||
if (stat & 0x20000000) {
|
||||
u32 units = nv_rd32(priv, 0x0025a0);
|
||||
u32 u = units;
|
||||
|
||||
while (u) {
|
||||
int i = ffs(u) - 1;
|
||||
nvc0_fifo_isr_subfifo_intr(priv, i);
|
||||
u &= ~(1 << i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0025a0, units);
|
||||
stat &= ~0x20000000;
|
||||
}
|
||||
|
||||
if (stat & 0x40000000) {
|
||||
nv_warn(priv, "unknown status 0x40000000\n");
|
||||
nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
|
||||
stat &= ~0x40000000;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x002100, stat);
|
||||
nv_wr32(priv, 0x002140, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
|
||||
&priv->playlist[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
|
||||
&priv->playlist[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 128 * 0x1000, 0x1000, 0,
|
||||
&priv->user.mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
|
||||
&priv->user.bar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nvc0_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nvc0_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nvc0_fifo_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = (void *)object;
|
||||
|
||||
nouveau_gpuobj_unmap(&priv->user.bar);
|
||||
nouveau_gpuobj_ref(NULL, &priv->user.mem);
|
||||
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
|
||||
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
|
||||
|
||||
nouveau_fifo_destroy(&priv->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x000204, 0xffffffff);
|
||||
nv_wr32(priv, 0x002204, 0xffffffff);
|
||||
|
||||
priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
|
||||
nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
|
||||
|
||||
/* assign engines to subfifos */
|
||||
if (priv->spoon_nr >= 3) {
|
||||
nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
|
||||
nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
|
||||
nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
|
||||
nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
|
||||
nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
|
||||
nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
|
||||
}
|
||||
|
||||
/* PSUBFIFO[n] */
|
||||
for (i = 0; i < priv->spoon_nr; i++) {
|
||||
nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
|
||||
nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
|
||||
nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
|
||||
}
|
||||
|
||||
nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
|
||||
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
|
||||
|
||||
nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xbfffffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nvc0_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_fifo_ctor,
|
||||
.dtor = nvc0_fifo_dtor,
|
||||
.init = nvc0_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/vm.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#define _(a,b) { (a), ((1 << (a)) | (b)) }
|
||||
static const struct {
|
||||
int subdev;
|
||||
u32 mask;
|
||||
} fifo_engine[] = {
|
||||
_(NVDEV_ENGINE_GR , (1 << NVDEV_ENGINE_SW)),
|
||||
_(NVDEV_ENGINE_VP , 0),
|
||||
_(NVDEV_ENGINE_PPP , 0),
|
||||
_(NVDEV_ENGINE_BSP , 0),
|
||||
_(NVDEV_ENGINE_COPY0 , 0),
|
||||
_(NVDEV_ENGINE_COPY1 , 0),
|
||||
_(NVDEV_ENGINE_VENC , 0),
|
||||
};
|
||||
#undef _
|
||||
#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
|
||||
|
||||
struct nve0_fifo_engn {
|
||||
struct nouveau_gpuobj *playlist[2];
|
||||
int cur_playlist;
|
||||
};
|
||||
|
||||
struct nve0_fifo_priv {
|
||||
struct nouveau_fifo base;
|
||||
struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
|
||||
struct {
|
||||
struct nouveau_gpuobj *mem;
|
||||
struct nouveau_vma bar;
|
||||
} user;
|
||||
int spoon_nr;
|
||||
};
|
||||
|
||||
struct nve0_fifo_base {
|
||||
struct nouveau_fifo_base base;
|
||||
struct nouveau_gpuobj *pgd;
|
||||
struct nouveau_vm *vm;
|
||||
};
|
||||
|
||||
struct nve0_fifo_chan {
|
||||
struct nouveau_fifo_chan base;
|
||||
u32 engine;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO channel objects
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nve0_fifo_engn *engn = &priv->engine[engine];
|
||||
struct nouveau_gpuobj *cur;
|
||||
u32 match = (engine << 16) | 0x00000001;
|
||||
int i, p;
|
||||
|
||||
cur = engn->playlist[engn->cur_playlist];
|
||||
if (unlikely(cur == NULL)) {
|
||||
int ret = nouveau_gpuobj_new(nv_object(priv)->parent, NULL,
|
||||
0x8000, 0x1000, 0, &cur);
|
||||
if (ret) {
|
||||
nv_error(priv, "playlist alloc failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
engn->playlist[engn->cur_playlist] = cur;
|
||||
}
|
||||
|
||||
engn->cur_playlist = !engn->cur_playlist;
|
||||
|
||||
for (i = 0, p = 0; i < priv->base.max; i++) {
|
||||
u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001;
|
||||
if (ctrl != match)
|
||||
continue;
|
||||
nv_wo32(cur, p + 0, i);
|
||||
nv_wo32(cur, p + 4, 0x00000000);
|
||||
p += 8;
|
||||
}
|
||||
bar->flush(bar);
|
||||
|
||||
nv_wr32(priv, 0x002270, cur->addr >> 12);
|
||||
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
|
||||
if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
|
||||
nv_error(priv, "playlist %d update timeout\n", engine);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_context_attach(struct nouveau_object *parent,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nve0_fifo_base *base = (void *)parent->parent;
|
||||
struct nouveau_engctx *ectx = (void *)object;
|
||||
u32 addr;
|
||||
int ret;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR :
|
||||
case NVDEV_ENGINE_COPY0:
|
||||
case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ectx->vma.node) {
|
||||
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
|
||||
NV_MEM_ACCESS_RW, &ectx->vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
|
||||
}
|
||||
|
||||
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
|
||||
nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nve0_fifo_priv *priv = (void *)parent->engine;
|
||||
struct nve0_fifo_base *base = (void *)parent->parent;
|
||||
struct nve0_fifo_chan *chan = (void *)parent;
|
||||
u32 addr;
|
||||
|
||||
switch (nv_engidx(object->engine)) {
|
||||
case NVDEV_ENGINE_SW : return 0;
|
||||
case NVDEV_ENGINE_GR :
|
||||
case NVDEV_ENGINE_COPY0:
|
||||
case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_wo32(base, addr + 0x00, 0x00000000);
|
||||
nv_wo32(base, addr + 0x04, 0x00000000);
|
||||
bar->flush(bar);
|
||||
|
||||
nv_wr32(priv, 0x002634, chan->base.chid);
|
||||
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
|
||||
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nve0_fifo_priv *priv = (void *)engine;
|
||||
struct nve0_fifo_base *base = (void *)parent;
|
||||
struct nve0_fifo_chan *chan;
|
||||
struct nve0_channel_ind_class *args = data;
|
||||
u64 usermem, ioffset, ilength;
|
||||
int ret, i;
|
||||
|
||||
if (size < sizeof(*args))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < FIFO_ENGINE_NR; i++) {
|
||||
if (args->engine & (1 << i)) {
|
||||
if (nouveau_engine(parent, fifo_engine[i].subdev)) {
|
||||
args->engine = (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == FIFO_ENGINE_NR)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
|
||||
priv->user.bar.offset, 0x200,
|
||||
args->pushbuf,
|
||||
fifo_engine[i].mask, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_parent(chan)->context_attach = nve0_fifo_context_attach;
|
||||
nv_parent(chan)->context_detach = nve0_fifo_context_detach;
|
||||
chan->engine = i;
|
||||
|
||||
usermem = chan->base.chid * 0x200;
|
||||
ioffset = args->ioffset;
|
||||
ilength = log2i(args->ilength / 8);
|
||||
|
||||
for (i = 0; i < 0x200; i += 4)
|
||||
nv_wo32(priv->user.mem, usermem + i, 0x00000000);
|
||||
|
||||
nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
|
||||
nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
|
||||
nv_wo32(base, 0x10, 0x0000face);
|
||||
nv_wo32(base, 0x30, 0xfffff902);
|
||||
nv_wo32(base, 0x48, lower_32_bits(ioffset));
|
||||
nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
|
||||
nv_wo32(base, 0x84, 0x20400000);
|
||||
nv_wo32(base, 0x94, 0x30000001);
|
||||
nv_wo32(base, 0x9c, 0x00000100);
|
||||
nv_wo32(base, 0xac, 0x0000001f);
|
||||
nv_wo32(base, 0xe8, chan->base.chid);
|
||||
nv_wo32(base, 0xb8, 0xf8000000);
|
||||
nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
|
||||
nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
|
||||
bar->flush(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_chan_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
|
||||
struct nve0_fifo_priv *priv = (void *)object->engine;
|
||||
struct nve0_fifo_chan *chan = (void *)object;
|
||||
u32 chid = chan->base.chid;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_channel_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
|
||||
nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
|
||||
nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
|
||||
nve0_fifo_playlist_update(priv, chan->engine);
|
||||
nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = (void *)object->engine;
|
||||
struct nve0_fifo_chan *chan = (void *)object;
|
||||
u32 chid = chan->base.chid;
|
||||
|
||||
nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
|
||||
nve0_fifo_playlist_update(priv, chan->engine);
|
||||
nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
|
||||
|
||||
return nouveau_fifo_channel_fini(&chan->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
nve0_fifo_ofuncs = {
|
||||
.ctor = nve0_fifo_chan_ctor,
|
||||
.dtor = _nouveau_fifo_channel_dtor,
|
||||
.init = nve0_fifo_chan_init,
|
||||
.fini = nve0_fifo_chan_fini,
|
||||
.rd32 = _nouveau_fifo_channel_rd32,
|
||||
.wr32 = _nouveau_fifo_channel_wr32,
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nve0_fifo_sclass[] = {
|
||||
{ NVE0_CHANNEL_IND_CLASS, &nve0_fifo_ofuncs },
|
||||
{}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* FIFO context - instmem heap and vm setup
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nve0_fifo_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_fifo_base *base;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
|
||||
0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
|
||||
*pobject = nv_object(base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
|
||||
nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
|
||||
nv_wo32(base, 0x0208, 0xffffffff);
|
||||
nv_wo32(base, 0x020c, 0x000000ff);
|
||||
|
||||
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_context_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_fifo_base *base = (void *)object;
|
||||
nouveau_vm_ref(NULL, &base->vm, base->pgd);
|
||||
nouveau_gpuobj_ref(NULL, &base->pgd);
|
||||
nouveau_fifo_context_destroy(&base->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nve0_fifo_cclass = {
|
||||
.handle = NV_ENGCTX(FIFO, 0xe0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_fifo_context_ctor,
|
||||
.dtor = nve0_fifo_context_dtor,
|
||||
.init = _nouveau_fifo_context_init,
|
||||
.fini = _nouveau_fifo_context_fini,
|
||||
.rd32 = _nouveau_fifo_context_rd32,
|
||||
.wr32 = _nouveau_fifo_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nve0_fifo_fault_unit[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nve0_fifo_fault_reason[] = {
|
||||
{ 0x00, "PT_NOT_PRESENT" },
|
||||
{ 0x01, "PT_TOO_SHORT" },
|
||||
{ 0x02, "PAGE_NOT_PRESENT" },
|
||||
{ 0x03, "VM_LIMIT_EXCEEDED" },
|
||||
{ 0x04, "NO_CHANNEL" },
|
||||
{ 0x05, "PAGE_SYSTEM_ONLY" },
|
||||
{ 0x06, "PAGE_READ_ONLY" },
|
||||
{ 0x0a, "COMPRESSED_SYSRAM" },
|
||||
{ 0x0c, "INVALID_STORAGE_TYPE" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nve0_fifo_fault_hubclient[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct nouveau_bitfield nve0_fifo_subfifo_intr[] = {
|
||||
{ 0x00200000, "ILLEGAL_MTHD" },
|
||||
{ 0x00800000, "EMPTY_SUBC" },
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
|
||||
{
|
||||
u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
|
||||
u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
|
||||
u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
|
||||
u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
|
||||
u32 client = (stat & 0x00001f00) >> 8;
|
||||
|
||||
nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
|
||||
"write" : "read", (u64)vahi << 32 | valo);
|
||||
nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
|
||||
printk("] from ");
|
||||
nouveau_enum_print(nve0_fifo_fault_unit, unit);
|
||||
if (stat & 0x00000040) {
|
||||
printk("/");
|
||||
nouveau_enum_print(nve0_fifo_fault_hubclient, client);
|
||||
} else {
|
||||
printk("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
nouveau_enum_print(nve0_fifo_fault_gpcclient, client);
|
||||
}
|
||||
printk(" on channel 0x%010llx\n", (u64)inst << 12);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
|
||||
{
|
||||
struct nve0_fifo_chan *chan = NULL;
|
||||
struct nouveau_handle *bind;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&priv->base.lock, flags);
|
||||
if (likely(chid >= priv->base.min && chid <= priv->base.max))
|
||||
chan = (void *)priv->base.channel[chid];
|
||||
if (unlikely(!chan))
|
||||
goto out;
|
||||
|
||||
bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
|
||||
if (likely(bind)) {
|
||||
if (!mthd || !nv_call(bind->object, mthd, data))
|
||||
ret = 0;
|
||||
nouveau_namedb_put(bind);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->base.lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
|
||||
{
|
||||
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
|
||||
u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
|
||||
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
|
||||
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
|
||||
u32 subc = (addr & 0x00070000) >> 16;
|
||||
u32 mthd = (addr & 0x00003ffc);
|
||||
u32 show = stat;
|
||||
|
||||
if (stat & 0x00200000) {
|
||||
if (mthd == 0x0054) {
|
||||
if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
|
||||
show &= ~0x00200000;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat & 0x00800000) {
|
||||
if (!nve0_fifo_swmthd(priv, chid, mthd, data))
|
||||
show &= ~0x00800000;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "SUBFIFO%d:", unit);
|
||||
nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
|
||||
printk("\n");
|
||||
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
unit, chid, subc, mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
|
||||
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = (void *)subdev;
|
||||
u32 mask = nv_rd32(priv, 0x002140);
|
||||
u32 stat = nv_rd32(priv, 0x002100) & mask;
|
||||
|
||||
if (stat & 0x00000100) {
|
||||
nv_warn(priv, "unknown status 0x00000100\n");
|
||||
nv_wr32(priv, 0x002100, 0x00000100);
|
||||
stat &= ~0x00000100;
|
||||
}
|
||||
|
||||
if (stat & 0x10000000) {
|
||||
u32 units = nv_rd32(priv, 0x00259c);
|
||||
u32 u = units;
|
||||
|
||||
while (u) {
|
||||
int i = ffs(u) - 1;
|
||||
nve0_fifo_isr_vm_fault(priv, i);
|
||||
u &= ~(1 << i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x00259c, units);
|
||||
stat &= ~0x10000000;
|
||||
}
|
||||
|
||||
if (stat & 0x20000000) {
|
||||
u32 units = nv_rd32(priv, 0x0025a0);
|
||||
u32 u = units;
|
||||
|
||||
while (u) {
|
||||
int i = ffs(u) - 1;
|
||||
nve0_fifo_isr_subfifo_intr(priv, i);
|
||||
u &= ~(1 << i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0025a0, units);
|
||||
stat &= ~0x20000000;
|
||||
}
|
||||
|
||||
if (stat & 0x40000000) {
|
||||
nv_warn(priv, "unknown status 0x40000000\n");
|
||||
nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
|
||||
stat &= ~0x40000000;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x002100, stat);
|
||||
nv_wr32(priv, 0x002140, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_fifo_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 4096 * 0x200, 0x1000,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
|
||||
&priv->user.bar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nve0_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nve0_fifo_cclass;
|
||||
nv_engine(priv)->sclass = nve0_fifo_sclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = (void *)object;
|
||||
int i;
|
||||
|
||||
nouveau_gpuobj_unmap(&priv->user.bar);
|
||||
nouveau_gpuobj_ref(NULL, &priv->user.mem);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->engine); i++) {
|
||||
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
|
||||
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
|
||||
}
|
||||
|
||||
nouveau_fifo_destroy(&priv->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = (void *)object;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_fifo_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* enable all available PSUBFIFOs */
|
||||
nv_wr32(priv, 0x000204, 0xffffffff);
|
||||
priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
|
||||
nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
|
||||
|
||||
/* PSUBFIFO[n] */
|
||||
for (i = 0; i < priv->spoon_nr; i++) {
|
||||
nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
|
||||
nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
|
||||
nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
|
||||
|
||||
nv_wr32(priv, 0x002a00, 0xffffffff);
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xbfffffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nve0_fifo_oclass = {
|
||||
.handle = NV_ENGINE(FIFO, 0xe0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_fifo_ctor,
|
||||
.dtor = nve0_fifo_dtor,
|
||||
.init = nve0_fifo_init,
|
||||
.fini = _nouveau_fifo_fini,
|
||||
},
|
||||
};
|
|
@ -2,7 +2,7 @@
|
|||
#define __NOUVEAU_GRCTX_H__
|
||||
|
||||
struct nouveau_grctx {
|
||||
struct drm_device *dev;
|
||||
struct nouveau_device *device;
|
||||
|
||||
enum {
|
||||
NOUVEAU_GRCTX_PROG,
|
||||
|
@ -10,18 +10,18 @@ struct nouveau_grctx {
|
|||
} mode;
|
||||
void *data;
|
||||
|
||||
uint32_t ctxprog_max;
|
||||
uint32_t ctxprog_len;
|
||||
uint32_t ctxprog_reg;
|
||||
int ctxprog_label[32];
|
||||
uint32_t ctxvals_pos;
|
||||
uint32_t ctxvals_base;
|
||||
u32 ctxprog_max;
|
||||
u32 ctxprog_len;
|
||||
u32 ctxprog_reg;
|
||||
int ctxprog_label[32];
|
||||
u32 ctxvals_pos;
|
||||
u32 ctxvals_base;
|
||||
};
|
||||
|
||||
static inline void
|
||||
cp_out(struct nouveau_grctx *ctx, uint32_t inst)
|
||||
cp_out(struct nouveau_grctx *ctx, u32 inst)
|
||||
{
|
||||
uint32_t *ctxprog = ctx->data;
|
||||
u32 *ctxprog = ctx->data;
|
||||
|
||||
if (ctx->mode != NOUVEAU_GRCTX_PROG)
|
||||
return;
|
||||
|
@ -31,13 +31,13 @@ cp_out(struct nouveau_grctx *ctx, uint32_t inst)
|
|||
}
|
||||
|
||||
static inline void
|
||||
cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
|
||||
cp_lsr(struct nouveau_grctx *ctx, u32 val)
|
||||
{
|
||||
cp_out(ctx, CP_LOAD_SR | val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
|
||||
cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
|
||||
{
|
||||
ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
|
||||
|
||||
|
@ -55,7 +55,7 @@ cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
|
|||
static inline void
|
||||
cp_name(struct nouveau_grctx *ctx, int name)
|
||||
{
|
||||
uint32_t *ctxprog = ctx->data;
|
||||
u32 *ctxprog = ctx->data;
|
||||
int i;
|
||||
|
||||
if (ctx->mode != NOUVEAU_GRCTX_PROG)
|
||||
|
@ -115,7 +115,7 @@ cp_pos(struct nouveau_grctx *ctx, int offset)
|
|||
}
|
||||
|
||||
static inline void
|
||||
gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
|
||||
gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
|
||||
{
|
||||
if (ctx->mode != NOUVEAU_GRCTX_VALS)
|
||||
return;
|
|
@ -22,6 +22,8 @@
|
|||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
/* NVIDIA context programs handle a number of other conditions which are
|
||||
* not implemented in our versions. It's not clear why NVIDIA context
|
||||
* programs have this code, nor whether it's strictly necessary for
|
||||
|
@ -109,20 +111,18 @@
|
|||
#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */
|
||||
#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */
|
||||
|
||||
#include "drmP.h"
|
||||
#include "nouveau_drv.h"
|
||||
#include "nouveau_grctx.h"
|
||||
#include "nv40.h"
|
||||
#include "ctx.h"
|
||||
|
||||
/* TODO:
|
||||
* - get vs count from 0x1540
|
||||
*/
|
||||
|
||||
static int
|
||||
nv40_graph_vs_count(struct drm_device *dev)
|
||||
nv40_graph_vs_count(struct nouveau_device *device)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
case 0x4b:
|
||||
|
@ -160,7 +160,7 @@ enum cp_label {
|
|||
static void
|
||||
nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
|
||||
struct nouveau_device *device = ctx->device;
|
||||
int i;
|
||||
|
||||
cp_ctx(ctx, 0x4000a4, 1);
|
||||
|
@ -187,7 +187,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
|||
cp_ctx(ctx, 0x400724, 1);
|
||||
gr_def(ctx, 0x400724, 0x02008821);
|
||||
cp_ctx(ctx, 0x400770, 3);
|
||||
if (dev_priv->chipset == 0x40) {
|
||||
if (device->chipset == 0x40) {
|
||||
cp_ctx(ctx, 0x400814, 4);
|
||||
cp_ctx(ctx, 0x400828, 5);
|
||||
cp_ctx(ctx, 0x400840, 5);
|
||||
|
@ -208,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x4009dc, 0x80000000);
|
||||
} else {
|
||||
cp_ctx(ctx, 0x400840, 20);
|
||||
if (nv44_graph_class(ctx->dev)) {
|
||||
if (nv44_graph_class(ctx->device)) {
|
||||
for (i = 0; i < 8; i++)
|
||||
gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
|
||||
}
|
||||
|
@ -217,21 +217,21 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x400888, 0x00000040);
|
||||
cp_ctx(ctx, 0x400894, 11);
|
||||
gr_def(ctx, 0x400894, 0x00000040);
|
||||
if (!nv44_graph_class(ctx->dev)) {
|
||||
if (!nv44_graph_class(ctx->device)) {
|
||||
for (i = 0; i < 8; i++)
|
||||
gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
|
||||
}
|
||||
cp_ctx(ctx, 0x4008e0, 2);
|
||||
cp_ctx(ctx, 0x4008f8, 2);
|
||||
if (dev_priv->chipset == 0x4c ||
|
||||
(dev_priv->chipset & 0xf0) == 0x60)
|
||||
if (device->chipset == 0x4c ||
|
||||
(device->chipset & 0xf0) == 0x60)
|
||||
cp_ctx(ctx, 0x4009f8, 1);
|
||||
}
|
||||
cp_ctx(ctx, 0x400a00, 73);
|
||||
gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
|
||||
cp_ctx(ctx, 0x401000, 4);
|
||||
cp_ctx(ctx, 0x405004, 1);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
case 0x4b:
|
||||
|
@ -240,7 +240,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
|||
break;
|
||||
default:
|
||||
cp_ctx(ctx, 0x403440, 1);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x40:
|
||||
gr_def(ctx, 0x403440, 0x00000010);
|
||||
break;
|
||||
|
@ -266,19 +266,19 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
|
|||
static void
|
||||
nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
|
||||
struct nouveau_device *device = ctx->device;
|
||||
int i;
|
||||
|
||||
if (dev_priv->chipset == 0x40) {
|
||||
if (device->chipset == 0x40) {
|
||||
cp_ctx(ctx, 0x401880, 51);
|
||||
gr_def(ctx, 0x401940, 0x00000100);
|
||||
} else
|
||||
if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
|
||||
dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
|
||||
if (device->chipset == 0x46 || device->chipset == 0x47 ||
|
||||
device->chipset == 0x49 || device->chipset == 0x4b) {
|
||||
cp_ctx(ctx, 0x401880, 32);
|
||||
for (i = 0; i < 16; i++)
|
||||
gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
|
||||
if (dev_priv->chipset == 0x46)
|
||||
if (device->chipset == 0x46)
|
||||
cp_ctx(ctx, 0x401900, 16);
|
||||
cp_ctx(ctx, 0x401940, 3);
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x401978, 0xffff0000);
|
||||
gr_def(ctx, 0x40197c, 0x00000001);
|
||||
gr_def(ctx, 0x401990, 0x46400000);
|
||||
if (dev_priv->chipset == 0x40) {
|
||||
if (device->chipset == 0x40) {
|
||||
cp_ctx(ctx, 0x4019a0, 2);
|
||||
cp_ctx(ctx, 0x4019ac, 5);
|
||||
} else {
|
||||
|
@ -297,7 +297,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
cp_ctx(ctx, 0x4019b4, 3);
|
||||
}
|
||||
gr_def(ctx, 0x4019bc, 0xffff0000);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
|
@ -316,7 +316,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
for (i = 0; i < 16; i++)
|
||||
gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
|
||||
gr_def(ctx, 0x401a8c, 0x4b7fffff);
|
||||
if (dev_priv->chipset == 0x40) {
|
||||
if (device->chipset == 0x40) {
|
||||
cp_ctx(ctx, 0x401ab8, 3);
|
||||
} else {
|
||||
cp_ctx(ctx, 0x401ab8, 1);
|
||||
|
@ -327,10 +327,10 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x401ad4, 0x70605040);
|
||||
gr_def(ctx, 0x401ad8, 0xb8a89888);
|
||||
gr_def(ctx, 0x401adc, 0xf8e8d8c8);
|
||||
cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
|
||||
cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
|
||||
gr_def(ctx, 0x401b10, 0x40100000);
|
||||
cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
|
||||
gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
|
||||
cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
|
||||
gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
|
||||
0x00000004 : 0x00000000);
|
||||
cp_ctx(ctx, 0x401b30, 25);
|
||||
gr_def(ctx, 0x401b34, 0x0000ffff);
|
||||
|
@ -341,8 +341,8 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x401b84, 0xffffffff);
|
||||
gr_def(ctx, 0x401b88, 0x00ff7000);
|
||||
gr_def(ctx, 0x401b8c, 0x0000ffff);
|
||||
if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
|
||||
dev_priv->chipset != 0x4e)
|
||||
if (device->chipset != 0x44 && device->chipset != 0x4a &&
|
||||
device->chipset != 0x4e)
|
||||
cp_ctx(ctx, 0x401b94, 1);
|
||||
cp_ctx(ctx, 0x401b98, 8);
|
||||
gr_def(ctx, 0x401b9c, 0x00ff0000);
|
||||
|
@ -371,12 +371,12 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
|
|||
static void
|
||||
nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
|
||||
struct nouveau_device *device = ctx->device;
|
||||
int i;
|
||||
|
||||
cp_ctx(ctx, 0x402000, 1);
|
||||
cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
|
||||
switch (dev_priv->chipset) {
|
||||
cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
|
||||
switch (device->chipset) {
|
||||
case 0x40:
|
||||
gr_def(ctx, 0x402404, 0x00000001);
|
||||
break;
|
||||
|
@ -393,9 +393,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
default:
|
||||
gr_def(ctx, 0x402404, 0x00000021);
|
||||
}
|
||||
if (dev_priv->chipset != 0x40)
|
||||
if (device->chipset != 0x40)
|
||||
gr_def(ctx, 0x402408, 0x030c30c3);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x44:
|
||||
case 0x46:
|
||||
case 0x4a:
|
||||
|
@ -408,10 +408,10 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
|
||||
cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
|
||||
gr_def(ctx, 0x402488, 0x3e020200);
|
||||
gr_def(ctx, 0x40248c, 0x00ffffff);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x40:
|
||||
gr_def(ctx, 0x402490, 0x60103f00);
|
||||
break;
|
||||
|
@ -428,16 +428,16 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x402490, 0x0c103f00);
|
||||
break;
|
||||
}
|
||||
gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
|
||||
gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
|
||||
0x00020000 : 0x00040000);
|
||||
cp_ctx(ctx, 0x402500, 31);
|
||||
gr_def(ctx, 0x402530, 0x00008100);
|
||||
if (dev_priv->chipset == 0x40)
|
||||
if (device->chipset == 0x40)
|
||||
cp_ctx(ctx, 0x40257c, 6);
|
||||
cp_ctx(ctx, 0x402594, 16);
|
||||
cp_ctx(ctx, 0x402800, 17);
|
||||
gr_def(ctx, 0x402800, 0x00000001);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
case 0x4b:
|
||||
|
@ -445,7 +445,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x402864, 0x00001001);
|
||||
cp_ctx(ctx, 0x402870, 3);
|
||||
gr_def(ctx, 0x402878, 0x00000003);
|
||||
if (dev_priv->chipset != 0x47) { /* belong at end!! */
|
||||
if (device->chipset != 0x47) { /* belong at end!! */
|
||||
cp_ctx(ctx, 0x402900, 1);
|
||||
cp_ctx(ctx, 0x402940, 1);
|
||||
cp_ctx(ctx, 0x402980, 1);
|
||||
|
@ -470,9 +470,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
}
|
||||
|
||||
cp_ctx(ctx, 0x402c00, 4);
|
||||
gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
|
||||
gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
|
||||
0x80800001 : 0x00888001);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
case 0x4b:
|
||||
|
@ -485,30 +485,30 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
break;
|
||||
default:
|
||||
cp_ctx(ctx, 0x402c10, 4);
|
||||
if (dev_priv->chipset == 0x40)
|
||||
if (device->chipset == 0x40)
|
||||
cp_ctx(ctx, 0x402c20, 36);
|
||||
else
|
||||
if (dev_priv->chipset <= 0x42)
|
||||
if (device->chipset <= 0x42)
|
||||
cp_ctx(ctx, 0x402c20, 24);
|
||||
else
|
||||
if (dev_priv->chipset <= 0x4a)
|
||||
if (device->chipset <= 0x4a)
|
||||
cp_ctx(ctx, 0x402c20, 16);
|
||||
else
|
||||
cp_ctx(ctx, 0x402c20, 8);
|
||||
cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
|
||||
cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
|
||||
gr_def(ctx, 0x402cd4, 0x00000005);
|
||||
if (dev_priv->chipset != 0x40)
|
||||
if (device->chipset != 0x40)
|
||||
gr_def(ctx, 0x402ce0, 0x0000ffff);
|
||||
break;
|
||||
}
|
||||
|
||||
cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
|
||||
cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
|
||||
cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
|
||||
for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
|
||||
cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
|
||||
cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
|
||||
cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
|
||||
for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
|
||||
gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
|
||||
|
||||
if (dev_priv->chipset != 0x40) {
|
||||
if (device->chipset != 0x40) {
|
||||
cp_ctx(ctx, 0x403600, 1);
|
||||
gr_def(ctx, 0x403600, 0x00000001);
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
|
||||
cp_ctx(ctx, 0x403c18, 1);
|
||||
gr_def(ctx, 0x403c18, 0x00000001);
|
||||
switch (dev_priv->chipset) {
|
||||
switch (device->chipset) {
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
|
@ -527,7 +527,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
gr_def(ctx, 0x405c24, 0x000e3000);
|
||||
break;
|
||||
}
|
||||
if (dev_priv->chipset != 0x4e)
|
||||
if (device->chipset != 0x4e)
|
||||
cp_ctx(ctx, 0x405800, 11);
|
||||
cp_ctx(ctx, 0x407000, 1);
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
|
|||
static void
|
||||
nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
|
||||
{
|
||||
int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
|
||||
int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
|
||||
|
||||
cp_out (ctx, 0x300000);
|
||||
cp_lsr (ctx, len - 4);
|
||||
|
@ -550,32 +550,31 @@ nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
|
|||
static void
|
||||
nv40_graph_construct_shader(struct nouveau_grctx *ctx)
|
||||
{
|
||||
struct drm_device *dev = ctx->dev;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_device *device = ctx->device;
|
||||
struct nouveau_gpuobj *obj = ctx->data;
|
||||
int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
|
||||
int offset, i;
|
||||
|
||||
vs_nr = nv40_graph_vs_count(ctx->dev);
|
||||
vs_nr = nv40_graph_vs_count(ctx->device);
|
||||
vs_nr_b0 = 363;
|
||||
vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
|
||||
if (dev_priv->chipset == 0x40) {
|
||||
vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
|
||||
if (device->chipset == 0x40) {
|
||||
b0_offset = 0x2200/4; /* 33a0 */
|
||||
b1_offset = 0x55a0/4; /* 1500 */
|
||||
vs_len = 0x6aa0/4;
|
||||
} else
|
||||
if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
|
||||
if (device->chipset == 0x41 || device->chipset == 0x42) {
|
||||
b0_offset = 0x2200/4; /* 2200 */
|
||||
b1_offset = 0x4400/4; /* 0b00 */
|
||||
vs_len = 0x4f00/4;
|
||||
} else {
|
||||
b0_offset = 0x1d40/4; /* 2200 */
|
||||
b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
|
||||
vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
|
||||
vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
|
||||
}
|
||||
|
||||
cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
|
||||
cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
|
||||
cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
|
||||
|
||||
offset = ctx->ctxvals_pos;
|
||||
ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
|
||||
|
@ -661,21 +660,21 @@ nv40_grctx_generate(struct nouveau_grctx *ctx)
|
|||
}
|
||||
|
||||
void
|
||||
nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
|
||||
nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
|
||||
{
|
||||
nv40_grctx_generate(&(struct nouveau_grctx) {
|
||||
.dev = dev,
|
||||
.device = device,
|
||||
.mode = NOUVEAU_GRCTX_VALS,
|
||||
.data = mem,
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
nv40_grctx_init(struct drm_device *dev, u32 *size)
|
||||
nv40_grctx_init(struct nouveau_device *device, u32 *size)
|
||||
{
|
||||
u32 ctxprog[256], i;
|
||||
struct nouveau_grctx ctx = {
|
||||
.dev = dev,
|
||||
.device = device,
|
||||
.mode = NOUVEAU_GRCTX_PROG,
|
||||
.data = ctxprog,
|
||||
.ctxprog_max = ARRAY_SIZE(ctxprog)
|
||||
|
@ -683,8 +682,8 @@ nv40_grctx_init(struct drm_device *dev, u32 *size)
|
|||
|
||||
nv40_grctx_generate(&ctx);
|
||||
|
||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
||||
nv_wr32(device, 0x400324, 0);
|
||||
for (i = 0; i < ctx.ctxprog_len; i++)
|
||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
|
||||
nv_wr32(device, 0x400328, ctxprog[i]);
|
||||
*size = ctx.ctxvals_pos * 4;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
/* To build:
|
||||
* m4 nvc0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grgpc.fuc.h
|
||||
* m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
|
||||
.section #nvc0_grgpc_data
|
||||
include(`nvc0_graph.fuc')
|
||||
include(`nvc0.fuc')
|
||||
gpc_id: .b32 0
|
||||
gpc_mmio_list_head: .b32 0
|
||||
gpc_mmio_list_tail: .b32 0
|
||||
|
@ -209,11 +209,11 @@ nvd9_tpc_mmio_tail:
|
|||
.section #nvc0_grgpc_code
|
||||
bra #init
|
||||
define(`include_code')
|
||||
include(`nvc0_graph.fuc')
|
||||
include(`nvc0.fuc')
|
||||
|
||||
// reports an exception to the host
|
||||
//
|
||||
// In: $r15 error code (see nvc0_graph.fuc)
|
||||
// In: $r15 error code (see nvc0.fuc)
|
||||
//
|
||||
error:
|
||||
push $r14
|
|
@ -1,4 +1,19 @@
|
|||
uint32_t nvc0_grgpc_data[] = {
|
||||
/* 0x0000: gpc_id */
|
||||
0x00000000,
|
||||
/* 0x0004: gpc_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0008: gpc_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x000c: tpc_count */
|
||||
0x00000000,
|
||||
/* 0x0010: tpc_mask */
|
||||
0x00000000,
|
||||
/* 0x0014: tpc_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0018: tpc_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x001c: cmd_queue */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
@ -17,13 +32,7 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0064: chipsets */
|
||||
0x000000c0,
|
||||
0x012800c8,
|
||||
0x01e40194,
|
||||
|
@ -49,6 +58,7 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
0x0194012c,
|
||||
0x025401f8,
|
||||
0x00000000,
|
||||
/* 0x00c8: nvc0_gpc_mmio_head */
|
||||
0x00000380,
|
||||
0x14000400,
|
||||
0x20000450,
|
||||
|
@ -73,7 +83,10 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
0x00000c8c,
|
||||
0x08001000,
|
||||
0x00001014,
|
||||
/* 0x0128: nvc0_gpc_mmio_tail */
|
||||
0x00000c6c,
|
||||
/* 0x012c: nvc1_gpc_mmio_tail */
|
||||
/* 0x012c: nvd9_gpc_mmio_head */
|
||||
0x00000380,
|
||||
0x04000400,
|
||||
0x0800040c,
|
||||
|
@ -100,6 +113,8 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
0x00000c8c,
|
||||
0x08001000,
|
||||
0x00001014,
|
||||
/* 0x0194: nvd9_gpc_mmio_tail */
|
||||
/* 0x0194: nvc0_tpc_mmio_head */
|
||||
0x00000018,
|
||||
0x0000003c,
|
||||
0x00000048,
|
||||
|
@ -120,11 +135,16 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
0x4c000644,
|
||||
0x00000698,
|
||||
0x04000750,
|
||||
/* 0x01e4: nvc0_tpc_mmio_tail */
|
||||
0x00000758,
|
||||
0x000002c4,
|
||||
0x000006e0,
|
||||
/* 0x01f0: nvcf_tpc_mmio_tail */
|
||||
0x000004bc,
|
||||
/* 0x01f4: nvc3_tpc_mmio_tail */
|
||||
0x00000544,
|
||||
/* 0x01f8: nvc1_tpc_mmio_tail */
|
||||
/* 0x01f8: nvd9_tpc_mmio_head */
|
||||
0x00000018,
|
||||
0x0000003c,
|
||||
0x00000048,
|
||||
|
@ -152,12 +172,14 @@ uint32_t nvc0_grgpc_data[] = {
|
|||
|
||||
uint32_t nvc0_grgpc_code[] = {
|
||||
0x03060ef5,
|
||||
/* 0x0004: queue_put */
|
||||
0x9800d898,
|
||||
0x86f001d9,
|
||||
0x0489b808,
|
||||
0xf00c1bf4,
|
||||
0x21f502f7,
|
||||
0x00f802ec,
|
||||
/* 0x001c: queue_put_next */
|
||||
0xb60798c4,
|
||||
0x8dbb0384,
|
||||
0x0880b600,
|
||||
|
@ -165,6 +187,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x90b6018f,
|
||||
0x0f94f001,
|
||||
0xf801d980,
|
||||
/* 0x0039: queue_get */
|
||||
0x0131f400,
|
||||
0x9800d898,
|
||||
0x89b801d9,
|
||||
|
@ -176,37 +199,46 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x80b6019f,
|
||||
0x0f84f001,
|
||||
0xf400d880,
|
||||
/* 0x0066: queue_get_done */
|
||||
0x00f80132,
|
||||
/* 0x0068: nv_rd32 */
|
||||
0x0728b7f1,
|
||||
0xb906b4b6,
|
||||
0xc9f002ec,
|
||||
0x00bcd01f,
|
||||
/* 0x0078: nv_rd32_wait */
|
||||
0xc800bccf,
|
||||
0x1bf41fcc,
|
||||
0x06a7f0fa,
|
||||
0x010321f5,
|
||||
0xf840bfcf,
|
||||
/* 0x008d: nv_wr32 */
|
||||
0x28b7f100,
|
||||
0x06b4b607,
|
||||
0xb980bfd0,
|
||||
0xc9f002ec,
|
||||
0x1ec9f01f,
|
||||
/* 0x00a3: nv_wr32_wait */
|
||||
0xcf00bcd0,
|
||||
0xccc800bc,
|
||||
0xfa1bf41f,
|
||||
/* 0x00ae: watchdog_reset */
|
||||
0x87f100f8,
|
||||
0x84b60430,
|
||||
0x1ff9f006,
|
||||
0xf8008fd0,
|
||||
/* 0x00bd: watchdog_clear */
|
||||
0x3087f100,
|
||||
0x0684b604,
|
||||
0xf80080d0,
|
||||
/* 0x00c9: wait_donez */
|
||||
0x3c87f100,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d000,
|
||||
0x081887f1,
|
||||
0xd00684b6,
|
||||
/* 0x00e2: wait_done_wait_donez */
|
||||
0x87f1008a,
|
||||
0x84b60400,
|
||||
0x0088cf06,
|
||||
|
@ -215,6 +247,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00099,
|
||||
/* 0x0103: wait_doneo */
|
||||
0xf100f800,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
|
@ -222,6 +255,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x87f10089,
|
||||
0x84b60818,
|
||||
0x008ad006,
|
||||
/* 0x011c: wait_done_wait_doneo */
|
||||
0x040087f1,
|
||||
0xcf0684b6,
|
||||
0x8aff0088,
|
||||
|
@ -230,6 +264,8 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xbd0684b6,
|
||||
0x0099f094,
|
||||
0xf80089d0,
|
||||
/* 0x013d: mmctx_size */
|
||||
/* 0x013f: nv_mmctx_size_loop */
|
||||
0x9894bd00,
|
||||
0x85b600e8,
|
||||
0x0180b61a,
|
||||
|
@ -238,6 +274,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x04efb804,
|
||||
0xb9eb1bf4,
|
||||
0x00f8029f,
|
||||
/* 0x015c: mmctx_xfer */
|
||||
0x083c87f1,
|
||||
0xbd0684b6,
|
||||
0x0199f094,
|
||||
|
@ -247,9 +284,11 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xf405bbfd,
|
||||
0x8bd0090b,
|
||||
0x0099f000,
|
||||
/* 0x0180: mmctx_base_disabled */
|
||||
0xf405eefd,
|
||||
0x8ed00c0b,
|
||||
0xc08fd080,
|
||||
/* 0x018f: mmctx_multi_disabled */
|
||||
0xb70199f0,
|
||||
0xc8010080,
|
||||
0xb4b600ab,
|
||||
|
@ -257,6 +296,8 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xb601aec8,
|
||||
0xbefd11e4,
|
||||
0x008bd005,
|
||||
/* 0x01a8: mmctx_exec_loop */
|
||||
/* 0x01a8: mmctx_wait_free */
|
||||
0xf0008ecf,
|
||||
0x0bf41fe4,
|
||||
0x00ce98fa,
|
||||
|
@ -265,34 +306,42 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x04cdb804,
|
||||
0xc8e81bf4,
|
||||
0x1bf402ab,
|
||||
/* 0x01c9: mmctx_fini_wait */
|
||||
0x008bcf18,
|
||||
0xb01fb4f0,
|
||||
0x1bf410b4,
|
||||
0x02a7f0f7,
|
||||
0xf4c921f4,
|
||||
/* 0x01de: mmctx_stop */
|
||||
0xabc81b0e,
|
||||
0x10b4b600,
|
||||
0xf00cb9f0,
|
||||
0x8bd012b9,
|
||||
/* 0x01ed: mmctx_stop_wait */
|
||||
0x008bcf00,
|
||||
0xf412bbc8,
|
||||
/* 0x01f6: mmctx_done */
|
||||
0x87f1fa1b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00199,
|
||||
/* 0x0207: strand_wait */
|
||||
0xf900f800,
|
||||
0x02a7f0a0,
|
||||
0xfcc921f4,
|
||||
/* 0x0213: strand_pre */
|
||||
0xf100f8a0,
|
||||
0xf04afc87,
|
||||
0x97f00283,
|
||||
0x0089d00c,
|
||||
0x020721f5,
|
||||
/* 0x0226: strand_post */
|
||||
0x87f100f8,
|
||||
0x83f04afc,
|
||||
0x0d97f002,
|
||||
0xf50089d0,
|
||||
0xf8020721,
|
||||
/* 0x0239: strand_set */
|
||||
0xfca7f100,
|
||||
0x02a3f04f,
|
||||
0x0500aba2,
|
||||
|
@ -303,6 +352,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xf000aed0,
|
||||
0xbcd00ac7,
|
||||
0x0721f500,
|
||||
/* 0x0263: strand_ctx_init */
|
||||
0xf100f802,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
|
@ -325,6 +375,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x0684b608,
|
||||
0xb70089cf,
|
||||
0x95220080,
|
||||
/* 0x02ba: ctx_init_strand_loop */
|
||||
0x8ed008fe,
|
||||
0x408ed000,
|
||||
0xb6808acf,
|
||||
|
@ -338,12 +389,14 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x00f80089,
|
||||
/* 0x02ec: error */
|
||||
0xe7f1e0f9,
|
||||
0xe3f09814,
|
||||
0x8d21f440,
|
||||
0x041ce0b7,
|
||||
0xf401f7f0,
|
||||
0xe0fc8d21,
|
||||
/* 0x0306: init */
|
||||
0x04bd00f8,
|
||||
0xf10004fe,
|
||||
0xf0120017,
|
||||
|
@ -366,11 +419,13 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x27f10002,
|
||||
0x24b60800,
|
||||
0x0022cf06,
|
||||
/* 0x035f: init_find_chipset */
|
||||
0xb65817f0,
|
||||
0x13980c10,
|
||||
0x0432b800,
|
||||
0xb00b0bf4,
|
||||
0x1bf40034,
|
||||
/* 0x0373: init_context */
|
||||
0xf100f8f1,
|
||||
0xb6080027,
|
||||
0x22cf0624,
|
||||
|
@ -407,6 +462,7 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x0010b740,
|
||||
0xf024bd08,
|
||||
0x12d01f29,
|
||||
/* 0x0401: main */
|
||||
0x0031f400,
|
||||
0xf00028f4,
|
||||
0x21f41cd7,
|
||||
|
@ -419,9 +475,11 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xfe051efd,
|
||||
0x21f50018,
|
||||
0x0ef404c3,
|
||||
/* 0x0431: main_not_ctx_xfer */
|
||||
0x10ef94d3,
|
||||
0xf501f5f0,
|
||||
0xf402ec21,
|
||||
/* 0x043e: ih */
|
||||
0x80f9c60e,
|
||||
0xf90188fe,
|
||||
0xf990f980,
|
||||
|
@ -436,30 +494,36 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0xb0b70421,
|
||||
0xe7f00400,
|
||||
0x00bed001,
|
||||
/* 0x0474: ih_no_fifo */
|
||||
0xfc400ad0,
|
||||
0xfce0fcf0,
|
||||
0xfcb0fcd0,
|
||||
0xfc90fca0,
|
||||
0x0088fe80,
|
||||
0x32f480fc,
|
||||
/* 0x048f: hub_barrier_done */
|
||||
0xf001f800,
|
||||
0x0e9801f7,
|
||||
0x04febb00,
|
||||
0x9418e7f1,
|
||||
0xf440e3f0,
|
||||
0x00f88d21,
|
||||
/* 0x04a4: ctx_redswitch */
|
||||
0x0614e7f1,
|
||||
0xf006e4b6,
|
||||
0xefd020f7,
|
||||
0x08f7f000,
|
||||
/* 0x04b4: ctx_redswitch_delay */
|
||||
0xf401f2b6,
|
||||
0xf7f1fd1b,
|
||||
0xefd00a20,
|
||||
/* 0x04c3: ctx_xfer */
|
||||
0xf100f800,
|
||||
0xb60a0417,
|
||||
0x1fd00614,
|
||||
0x0711f400,
|
||||
0x04a421f5,
|
||||
/* 0x04d4: ctx_xfer_not_load */
|
||||
0x4afc17f1,
|
||||
0xf00213f0,
|
||||
0x12d00c27,
|
||||
|
@ -489,11 +553,13 @@ uint32_t nvc0_grgpc_code[] = {
|
|||
0x5c21f508,
|
||||
0x0721f501,
|
||||
0x0601f402,
|
||||
/* 0x054b: ctx_xfer_post */
|
||||
0xf11412f4,
|
||||
0xf04afc17,
|
||||
0x27f00213,
|
||||
0x0012d00d,
|
||||
0x020721f5,
|
||||
/* 0x055c: ctx_xfer_done */
|
||||
0x048f21f5,
|
||||
0x000000f8,
|
||||
0x00000000,
|
|
@ -0,0 +1,451 @@
|
|||
/* fuc microcode for nve0 PGRAPH/GPC
|
||||
*
|
||||
* Copyright 2011 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
/* To build:
|
||||
* m4 nve0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grgpc.fuc.h
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
* - bracket certain functions with scratch writes, useful for debugging
|
||||
* - watchdog timer around ctx operations
|
||||
*/
|
||||
|
||||
.section #nve0_grgpc_data
|
||||
include(`nve0.fuc')
|
||||
gpc_id: .b32 0
|
||||
gpc_mmio_list_head: .b32 0
|
||||
gpc_mmio_list_tail: .b32 0
|
||||
|
||||
tpc_count: .b32 0
|
||||
tpc_mask: .b32 0
|
||||
tpc_mmio_list_head: .b32 0
|
||||
tpc_mmio_list_tail: .b32 0
|
||||
|
||||
cmd_queue: queue_init
|
||||
|
||||
// chipset descriptions
|
||||
chipsets:
|
||||
.b8 0xe4 0 0 0
|
||||
.b16 #nve4_gpc_mmio_head
|
||||
.b16 #nve4_gpc_mmio_tail
|
||||
.b16 #nve4_tpc_mmio_head
|
||||
.b16 #nve4_tpc_mmio_tail
|
||||
.b8 0xe7 0 0 0
|
||||
.b16 #nve4_gpc_mmio_head
|
||||
.b16 #nve4_gpc_mmio_tail
|
||||
.b16 #nve4_tpc_mmio_head
|
||||
.b16 #nve4_tpc_mmio_tail
|
||||
.b8 0 0 0 0
|
||||
|
||||
// GPC mmio lists
|
||||
nve4_gpc_mmio_head:
|
||||
mmctx_data(0x000380, 1)
|
||||
mmctx_data(0x000400, 2)
|
||||
mmctx_data(0x00040c, 3)
|
||||
mmctx_data(0x000450, 9)
|
||||
mmctx_data(0x000600, 1)
|
||||
mmctx_data(0x000684, 1)
|
||||
mmctx_data(0x000700, 5)
|
||||
mmctx_data(0x000800, 1)
|
||||
mmctx_data(0x000808, 3)
|
||||
mmctx_data(0x000828, 1)
|
||||
mmctx_data(0x000830, 1)
|
||||
mmctx_data(0x0008d8, 1)
|
||||
mmctx_data(0x0008e0, 1)
|
||||
mmctx_data(0x0008e8, 6)
|
||||
mmctx_data(0x00091c, 1)
|
||||
mmctx_data(0x000924, 3)
|
||||
mmctx_data(0x000b00, 1)
|
||||
mmctx_data(0x000b08, 6)
|
||||
mmctx_data(0x000bb8, 1)
|
||||
mmctx_data(0x000c08, 1)
|
||||
mmctx_data(0x000c10, 8)
|
||||
mmctx_data(0x000c40, 1)
|
||||
mmctx_data(0x000c6c, 1)
|
||||
mmctx_data(0x000c80, 1)
|
||||
mmctx_data(0x000c8c, 1)
|
||||
mmctx_data(0x001000, 3)
|
||||
mmctx_data(0x001014, 1)
|
||||
mmctx_data(0x003024, 1)
|
||||
mmctx_data(0x0030c0, 2)
|
||||
mmctx_data(0x0030e4, 1)
|
||||
mmctx_data(0x003100, 6)
|
||||
mmctx_data(0x0031d0, 1)
|
||||
mmctx_data(0x0031e0, 2)
|
||||
nve4_gpc_mmio_tail:
|
||||
|
||||
// TPC mmio lists
|
||||
nve4_tpc_mmio_head:
|
||||
mmctx_data(0x000048, 1)
|
||||
mmctx_data(0x000064, 1)
|
||||
mmctx_data(0x000088, 1)
|
||||
mmctx_data(0x000200, 6)
|
||||
mmctx_data(0x00021c, 2)
|
||||
mmctx_data(0x000230, 1)
|
||||
mmctx_data(0x0002c4, 1)
|
||||
mmctx_data(0x000400, 3)
|
||||
mmctx_data(0x000420, 3)
|
||||
mmctx_data(0x0004e8, 1)
|
||||
mmctx_data(0x0004f4, 1)
|
||||
mmctx_data(0x000604, 4)
|
||||
mmctx_data(0x000644, 22)
|
||||
mmctx_data(0x0006ac, 2)
|
||||
mmctx_data(0x0006c8, 1)
|
||||
mmctx_data(0x000730, 8)
|
||||
mmctx_data(0x000758, 1)
|
||||
mmctx_data(0x000778, 1)
|
||||
nve4_tpc_mmio_tail:
|
||||
|
||||
.section #nve0_grgpc_code
|
||||
bra #init
|
||||
define(`include_code')
|
||||
include(`nve0.fuc')
|
||||
|
||||
// reports an exception to the host
|
||||
//
|
||||
// In: $r15 error code (see nve0.fuc)
|
||||
//
|
||||
error:
|
||||
push $r14
|
||||
mov $r14 -0x67ec // 0x9814
|
||||
sethi $r14 0x400000
|
||||
call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code
|
||||
add b32 $r14 0x41c
|
||||
mov $r15 1
|
||||
call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET
|
||||
pop $r14
|
||||
ret
|
||||
|
||||
// GPC fuc initialisation, executed by triggering ucode start, will
|
||||
// fall through to main loop after completion.
|
||||
//
|
||||
// Input:
|
||||
// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
|
||||
// CC_SCRATCH[1]: context base
|
||||
//
|
||||
// Output:
|
||||
// CC_SCRATCH[0]:
|
||||
// 31:31: set to signal completion
|
||||
// CC_SCRATCH[1]:
|
||||
// 31:0: GPC context size
|
||||
//
|
||||
init:
|
||||
clear b32 $r0
|
||||
mov $sp $r0
|
||||
|
||||
// enable fifo access
|
||||
mov $r1 0x1200
|
||||
mov $r2 2
|
||||
iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
|
||||
|
||||
// setup i0 handler, and route all interrupts to it
|
||||
mov $r1 #ih
|
||||
mov $iv0 $r1
|
||||
mov $r1 0x400
|
||||
iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
|
||||
|
||||
// enable fifo interrupt
|
||||
mov $r2 4
|
||||
iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
|
||||
|
||||
// enable interrupts
|
||||
bset $flags ie0
|
||||
|
||||
// figure out which GPC we are, and how many TPCs we have
|
||||
mov $r1 0x608
|
||||
shl b32 $r1 6
|
||||
iord $r2 I[$r1 + 0x000] // UNITS
|
||||
mov $r3 1
|
||||
and $r2 0x1f
|
||||
shl b32 $r3 $r2
|
||||
sub b32 $r3 1
|
||||
st b32 D[$r0 + #tpc_count] $r2
|
||||
st b32 D[$r0 + #tpc_mask] $r3
|
||||
add b32 $r1 0x400
|
||||
iord $r2 I[$r1 + 0x000] // MYINDEX
|
||||
st b32 D[$r0 + #gpc_id] $r2
|
||||
|
||||
// find context data for this chipset
|
||||
mov $r2 0x800
|
||||
shl b32 $r2 6
|
||||
iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
|
||||
mov $r1 #chipsets - 12
|
||||
init_find_chipset:
|
||||
add b32 $r1 12
|
||||
ld b32 $r3 D[$r1 + 0x00]
|
||||
cmpu b32 $r3 $r2
|
||||
bra e #init_context
|
||||
cmpu b32 $r3 0
|
||||
bra ne #init_find_chipset
|
||||
// unknown chipset
|
||||
ret
|
||||
|
||||
// initialise context base, and size tracking
|
||||
init_context:
|
||||
mov $r2 0x800
|
||||
shl b32 $r2 6
|
||||
iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base
|
||||
clear b32 $r3 // track GPC context size here
|
||||
|
||||
// set mmctx base addresses now so we don't have to do it later,
|
||||
// they don't currently ever change
|
||||
mov $r4 0x700
|
||||
shl b32 $r4 6
|
||||
shr b32 $r5 $r2 8
|
||||
iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE
|
||||
iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE
|
||||
|
||||
// calculate GPC mmio context size, store the chipset-specific
|
||||
// mmio list pointers somewhere we can get at them later without
|
||||
// re-parsing the chipset list
|
||||
clear b32 $r14
|
||||
clear b32 $r15
|
||||
ld b16 $r14 D[$r1 + 4]
|
||||
ld b16 $r15 D[$r1 + 6]
|
||||
st b16 D[$r0 + #gpc_mmio_list_head] $r14
|
||||
st b16 D[$r0 + #gpc_mmio_list_tail] $r15
|
||||
call #mmctx_size
|
||||
add b32 $r2 $r15
|
||||
add b32 $r3 $r15
|
||||
|
||||
// calculate per-TPC mmio context size, store the list pointers
|
||||
ld b16 $r14 D[$r1 + 8]
|
||||
ld b16 $r15 D[$r1 + 10]
|
||||
st b16 D[$r0 + #tpc_mmio_list_head] $r14
|
||||
st b16 D[$r0 + #tpc_mmio_list_tail] $r15
|
||||
call #mmctx_size
|
||||
ld b32 $r14 D[$r0 + #tpc_count]
|
||||
mulu $r14 $r15
|
||||
add b32 $r2 $r14
|
||||
add b32 $r3 $r14
|
||||
|
||||
// round up base/size to 256 byte boundary (for strand SWBASE)
|
||||
add b32 $r4 0x1300
|
||||
shr b32 $r3 2
|
||||
iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!?
|
||||
shr b32 $r2 8
|
||||
shr b32 $r3 6
|
||||
add b32 $r2 1
|
||||
add b32 $r3 1
|
||||
shl b32 $r2 8
|
||||
shl b32 $r3 8
|
||||
|
||||
// calculate size of strand context data
|
||||
mov b32 $r15 $r2
|
||||
call #strand_ctx_init
|
||||
add b32 $r3 $r15
|
||||
|
||||
// save context size, and tell HUB we're done
|
||||
mov $r1 0x800
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size
|
||||
add b32 $r1 0x800
|
||||
clear b32 $r2
|
||||
bset $r2 31
|
||||
iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
|
||||
|
||||
// Main program loop, very simple, sleeps until woken up by the interrupt
|
||||
// handler, pulls a command from the queue and executes its handler
|
||||
//
|
||||
main:
|
||||
bset $flags $p0
|
||||
sleep $p0
|
||||
mov $r13 #cmd_queue
|
||||
call #queue_get
|
||||
bra $p1 #main
|
||||
|
||||
// 0x0000-0x0003 are all context transfers
|
||||
cmpu b32 $r14 0x04
|
||||
bra nc #main_not_ctx_xfer
|
||||
// fetch $flags and mask off $p1/$p2
|
||||
mov $r1 $flags
|
||||
mov $r2 0x0006
|
||||
not b32 $r2
|
||||
and $r1 $r2
|
||||
// set $p1/$p2 according to transfer type
|
||||
shl b32 $r14 1
|
||||
or $r1 $r14
|
||||
mov $flags $r1
|
||||
// transfer context data
|
||||
call #ctx_xfer
|
||||
bra #main
|
||||
|
||||
main_not_ctx_xfer:
|
||||
shl b32 $r15 $r14 16
|
||||
or $r15 E_BAD_COMMAND
|
||||
call #error
|
||||
bra #main
|
||||
|
||||
// interrupt handler
|
||||
ih:
|
||||
push $r8
|
||||
mov $r8 $flags
|
||||
push $r8
|
||||
push $r9
|
||||
push $r10
|
||||
push $r11
|
||||
push $r13
|
||||
push $r14
|
||||
push $r15
|
||||
|
||||
// incoming fifo command?
|
||||
iord $r10 I[$r0 + 0x200] // INTR
|
||||
and $r11 $r10 0x00000004
|
||||
bra e #ih_no_fifo
|
||||
// queue incoming fifo command for later processing
|
||||
mov $r11 0x1900
|
||||
mov $r13 #cmd_queue
|
||||
iord $r14 I[$r11 + 0x100] // FIFO_CMD
|
||||
iord $r15 I[$r11 + 0x000] // FIFO_DATA
|
||||
call #queue_put
|
||||
add b32 $r11 0x400
|
||||
mov $r14 1
|
||||
iowr I[$r11 + 0x000] $r14 // FIFO_ACK
|
||||
|
||||
// ack, and wake up main()
|
||||
ih_no_fifo:
|
||||
iowr I[$r0 + 0x100] $r10 // INTR_ACK
|
||||
|
||||
pop $r15
|
||||
pop $r14
|
||||
pop $r13
|
||||
pop $r11
|
||||
pop $r10
|
||||
pop $r9
|
||||
pop $r8
|
||||
mov $flags $r8
|
||||
pop $r8
|
||||
bclr $flags $p0
|
||||
iret
|
||||
|
||||
// Set this GPC's bit in HUB_BAR, used to signal completion of various
|
||||
// activities to the HUB fuc
|
||||
//
|
||||
hub_barrier_done:
|
||||
mov $r15 1
|
||||
ld b32 $r14 D[$r0 + #gpc_id]
|
||||
shl b32 $r15 $r14
|
||||
mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET
|
||||
sethi $r14 0x400000
|
||||
call #nv_wr32
|
||||
ret
|
||||
|
||||
// Disables various things, waits a bit, and re-enables them..
|
||||
//
|
||||
// Not sure how exactly this helps, perhaps "ENABLE" is not such a
|
||||
// good description for the bits we turn off? Anyways, without this,
|
||||
// funny things happen.
|
||||
//
|
||||
ctx_redswitch:
|
||||
mov $r14 0x614
|
||||
shl b32 $r14 6
|
||||
mov $r15 0x020
|
||||
iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER
|
||||
mov $r15 8
|
||||
ctx_redswitch_delay:
|
||||
sub b32 $r15 1
|
||||
bra ne #ctx_redswitch_delay
|
||||
mov $r15 0xa20
|
||||
iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER
|
||||
ret
|
||||
|
||||
// Transfer GPC context data between GPU and storage area
|
||||
//
|
||||
// In: $r15 context base address
|
||||
// $p1 clear on save, set on load
|
||||
// $p2 set if opposite direction done/will be done, so:
|
||||
// on save it means: "a load will follow this save"
|
||||
// on load it means: "a save preceeded this load"
|
||||
//
|
||||
ctx_xfer:
|
||||
// set context base address
|
||||
mov $r1 0xa04
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1 + 0x000] $r15// MEM_BASE
|
||||
bra not $p1 #ctx_xfer_not_load
|
||||
call #ctx_redswitch
|
||||
ctx_xfer_not_load:
|
||||
|
||||
// strands
|
||||
mov $r1 0x4afc
|
||||
sethi $r1 0x20000
|
||||
mov $r2 0xc
|
||||
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
|
||||
call #strand_wait
|
||||
mov $r2 0x47fc
|
||||
sethi $r2 0x20000
|
||||
iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
|
||||
xbit $r2 $flags $p1
|
||||
add b32 $r2 3
|
||||
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
|
||||
|
||||
// mmio context
|
||||
xbit $r10 $flags $p1 // direction
|
||||
or $r10 2 // first
|
||||
mov $r11 0x0000
|
||||
sethi $r11 0x500000
|
||||
ld b32 $r12 D[$r0 + #gpc_id]
|
||||
shl b32 $r12 15
|
||||
add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
|
||||
ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
|
||||
ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
|
||||
mov $r14 0 // not multi
|
||||
call #mmctx_xfer
|
||||
|
||||
// per-TPC mmio context
|
||||
xbit $r10 $flags $p1 // direction
|
||||
or $r10 4 // last
|
||||
mov $r11 0x4000
|
||||
sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0
|
||||
ld b32 $r12 D[$r0 + #gpc_id]
|
||||
shl b32 $r12 15
|
||||
add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
|
||||
ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
|
||||
ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
|
||||
ld b32 $r15 D[$r0 + #tpc_mask]
|
||||
mov $r14 0x800 // stride = 0x800
|
||||
call #mmctx_xfer
|
||||
|
||||
// wait for strands to finish
|
||||
call #strand_wait
|
||||
|
||||
// if load, or a save without a load following, do some
|
||||
// unknown stuff that's done after finishing a block of
|
||||
// strand commands
|
||||
bra $p1 #ctx_xfer_post
|
||||
bra not $p2 #ctx_xfer_done
|
||||
ctx_xfer_post:
|
||||
mov $r1 0x4afc
|
||||
sethi $r1 0x20000
|
||||
mov $r2 0xd
|
||||
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d
|
||||
call #strand_wait
|
||||
|
||||
// mark completion in HUB's barrier
|
||||
ctx_xfer_done:
|
||||
call #hub_barrier_done
|
||||
ret
|
||||
|
||||
.align 256
|
|
@ -0,0 +1,530 @@
|
|||
uint32_t nve0_grgpc_data[] = {
|
||||
/* 0x0000: gpc_id */
|
||||
0x00000000,
|
||||
/* 0x0004: gpc_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0008: gpc_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x000c: tpc_count */
|
||||
0x00000000,
|
||||
/* 0x0010: tpc_mask */
|
||||
0x00000000,
|
||||
/* 0x0014: tpc_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0018: tpc_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x001c: cmd_queue */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0064: chipsets */
|
||||
0x000000e4,
|
||||
0x01040080,
|
||||
0x014c0104,
|
||||
0x000000e7,
|
||||
0x01040080,
|
||||
0x014c0104,
|
||||
0x00000000,
|
||||
/* 0x0080: nve4_gpc_mmio_head */
|
||||
0x00000380,
|
||||
0x04000400,
|
||||
0x0800040c,
|
||||
0x20000450,
|
||||
0x00000600,
|
||||
0x00000684,
|
||||
0x10000700,
|
||||
0x00000800,
|
||||
0x08000808,
|
||||
0x00000828,
|
||||
0x00000830,
|
||||
0x000008d8,
|
||||
0x000008e0,
|
||||
0x140008e8,
|
||||
0x0000091c,
|
||||
0x08000924,
|
||||
0x00000b00,
|
||||
0x14000b08,
|
||||
0x00000bb8,
|
||||
0x00000c08,
|
||||
0x1c000c10,
|
||||
0x00000c40,
|
||||
0x00000c6c,
|
||||
0x00000c80,
|
||||
0x00000c8c,
|
||||
0x08001000,
|
||||
0x00001014,
|
||||
0x00003024,
|
||||
0x040030c0,
|
||||
0x000030e4,
|
||||
0x14003100,
|
||||
0x000031d0,
|
||||
0x040031e0,
|
||||
/* 0x0104: nve4_gpc_mmio_tail */
|
||||
/* 0x0104: nve4_tpc_mmio_head */
|
||||
0x00000048,
|
||||
0x00000064,
|
||||
0x00000088,
|
||||
0x14000200,
|
||||
0x0400021c,
|
||||
0x00000230,
|
||||
0x000002c4,
|
||||
0x08000400,
|
||||
0x08000420,
|
||||
0x000004e8,
|
||||
0x000004f4,
|
||||
0x0c000604,
|
||||
0x54000644,
|
||||
0x040006ac,
|
||||
0x000006c8,
|
||||
0x1c000730,
|
||||
0x00000758,
|
||||
0x00000778,
|
||||
};
|
||||
|
||||
uint32_t nve0_grgpc_code[] = {
|
||||
0x03060ef5,
|
||||
/* 0x0004: queue_put */
|
||||
0x9800d898,
|
||||
0x86f001d9,
|
||||
0x0489b808,
|
||||
0xf00c1bf4,
|
||||
0x21f502f7,
|
||||
0x00f802ec,
|
||||
/* 0x001c: queue_put_next */
|
||||
0xb60798c4,
|
||||
0x8dbb0384,
|
||||
0x0880b600,
|
||||
0x80008e80,
|
||||
0x90b6018f,
|
||||
0x0f94f001,
|
||||
0xf801d980,
|
||||
/* 0x0039: queue_get */
|
||||
0x0131f400,
|
||||
0x9800d898,
|
||||
0x89b801d9,
|
||||
0x210bf404,
|
||||
0xb60789c4,
|
||||
0x9dbb0394,
|
||||
0x0890b600,
|
||||
0x98009e98,
|
||||
0x80b6019f,
|
||||
0x0f84f001,
|
||||
0xf400d880,
|
||||
/* 0x0066: queue_get_done */
|
||||
0x00f80132,
|
||||
/* 0x0068: nv_rd32 */
|
||||
0x0728b7f1,
|
||||
0xb906b4b6,
|
||||
0xc9f002ec,
|
||||
0x00bcd01f,
|
||||
/* 0x0078: nv_rd32_wait */
|
||||
0xc800bccf,
|
||||
0x1bf41fcc,
|
||||
0x06a7f0fa,
|
||||
0x010321f5,
|
||||
0xf840bfcf,
|
||||
/* 0x008d: nv_wr32 */
|
||||
0x28b7f100,
|
||||
0x06b4b607,
|
||||
0xb980bfd0,
|
||||
0xc9f002ec,
|
||||
0x1ec9f01f,
|
||||
/* 0x00a3: nv_wr32_wait */
|
||||
0xcf00bcd0,
|
||||
0xccc800bc,
|
||||
0xfa1bf41f,
|
||||
/* 0x00ae: watchdog_reset */
|
||||
0x87f100f8,
|
||||
0x84b60430,
|
||||
0x1ff9f006,
|
||||
0xf8008fd0,
|
||||
/* 0x00bd: watchdog_clear */
|
||||
0x3087f100,
|
||||
0x0684b604,
|
||||
0xf80080d0,
|
||||
/* 0x00c9: wait_donez */
|
||||
0x3c87f100,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d000,
|
||||
0x081887f1,
|
||||
0xd00684b6,
|
||||
/* 0x00e2: wait_done_wait_donez */
|
||||
0x87f1008a,
|
||||
0x84b60400,
|
||||
0x0088cf06,
|
||||
0xf4888aff,
|
||||
0x87f1f31b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00099,
|
||||
/* 0x0103: wait_doneo */
|
||||
0xf100f800,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00099f0,
|
||||
0x87f10089,
|
||||
0x84b60818,
|
||||
0x008ad006,
|
||||
/* 0x011c: wait_done_wait_doneo */
|
||||
0x040087f1,
|
||||
0xcf0684b6,
|
||||
0x8aff0088,
|
||||
0xf30bf488,
|
||||
0x085c87f1,
|
||||
0xbd0684b6,
|
||||
0x0099f094,
|
||||
0xf80089d0,
|
||||
/* 0x013d: mmctx_size */
|
||||
/* 0x013f: nv_mmctx_size_loop */
|
||||
0x9894bd00,
|
||||
0x85b600e8,
|
||||
0x0180b61a,
|
||||
0xbb0284b6,
|
||||
0xe0b60098,
|
||||
0x04efb804,
|
||||
0xb9eb1bf4,
|
||||
0x00f8029f,
|
||||
/* 0x015c: mmctx_xfer */
|
||||
0x083c87f1,
|
||||
0xbd0684b6,
|
||||
0x0199f094,
|
||||
0xf10089d0,
|
||||
0xb6071087,
|
||||
0x94bd0684,
|
||||
0xf405bbfd,
|
||||
0x8bd0090b,
|
||||
0x0099f000,
|
||||
/* 0x0180: mmctx_base_disabled */
|
||||
0xf405eefd,
|
||||
0x8ed00c0b,
|
||||
0xc08fd080,
|
||||
/* 0x018f: mmctx_multi_disabled */
|
||||
0xb70199f0,
|
||||
0xc8010080,
|
||||
0xb4b600ab,
|
||||
0x0cb9f010,
|
||||
0xb601aec8,
|
||||
0xbefd11e4,
|
||||
0x008bd005,
|
||||
/* 0x01a8: mmctx_exec_loop */
|
||||
/* 0x01a8: mmctx_wait_free */
|
||||
0xf0008ecf,
|
||||
0x0bf41fe4,
|
||||
0x00ce98fa,
|
||||
0xd005e9fd,
|
||||
0xc0b6c08e,
|
||||
0x04cdb804,
|
||||
0xc8e81bf4,
|
||||
0x1bf402ab,
|
||||
/* 0x01c9: mmctx_fini_wait */
|
||||
0x008bcf18,
|
||||
0xb01fb4f0,
|
||||
0x1bf410b4,
|
||||
0x02a7f0f7,
|
||||
0xf4c921f4,
|
||||
/* 0x01de: mmctx_stop */
|
||||
0xabc81b0e,
|
||||
0x10b4b600,
|
||||
0xf00cb9f0,
|
||||
0x8bd012b9,
|
||||
/* 0x01ed: mmctx_stop_wait */
|
||||
0x008bcf00,
|
||||
0xf412bbc8,
|
||||
/* 0x01f6: mmctx_done */
|
||||
0x87f1fa1b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00199,
|
||||
/* 0x0207: strand_wait */
|
||||
0xf900f800,
|
||||
0x02a7f0a0,
|
||||
0xfcc921f4,
|
||||
/* 0x0213: strand_pre */
|
||||
0xf100f8a0,
|
||||
0xf04afc87,
|
||||
0x97f00283,
|
||||
0x0089d00c,
|
||||
0x020721f5,
|
||||
/* 0x0226: strand_post */
|
||||
0x87f100f8,
|
||||
0x83f04afc,
|
||||
0x0d97f002,
|
||||
0xf50089d0,
|
||||
0xf8020721,
|
||||
/* 0x0239: strand_set */
|
||||
0xfca7f100,
|
||||
0x02a3f04f,
|
||||
0x0500aba2,
|
||||
0xd00fc7f0,
|
||||
0xc7f000ac,
|
||||
0x00bcd00b,
|
||||
0x020721f5,
|
||||
0xf000aed0,
|
||||
0xbcd00ac7,
|
||||
0x0721f500,
|
||||
/* 0x0263: strand_ctx_init */
|
||||
0xf100f802,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x21f50089,
|
||||
0xe7f00213,
|
||||
0x3921f503,
|
||||
0xfca7f102,
|
||||
0x02a3f046,
|
||||
0x0400aba0,
|
||||
0xf040a0d0,
|
||||
0xbcd001c7,
|
||||
0x0721f500,
|
||||
0x010c9202,
|
||||
0xf000acd0,
|
||||
0xbcd002c7,
|
||||
0x0721f500,
|
||||
0x2621f502,
|
||||
0x8087f102,
|
||||
0x0684b608,
|
||||
0xb70089cf,
|
||||
0x95220080,
|
||||
/* 0x02ba: ctx_init_strand_loop */
|
||||
0x8ed008fe,
|
||||
0x408ed000,
|
||||
0xb6808acf,
|
||||
0xa0b606a5,
|
||||
0x00eabb01,
|
||||
0xb60480b6,
|
||||
0x1bf40192,
|
||||
0x08e4b6e8,
|
||||
0xf1f2efbc,
|
||||
0xb6085c87,
|
||||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x00f80089,
|
||||
/* 0x02ec: error */
|
||||
0xe7f1e0f9,
|
||||
0xe3f09814,
|
||||
0x8d21f440,
|
||||
0x041ce0b7,
|
||||
0xf401f7f0,
|
||||
0xe0fc8d21,
|
||||
/* 0x0306: init */
|
||||
0x04bd00f8,
|
||||
0xf10004fe,
|
||||
0xf0120017,
|
||||
0x12d00227,
|
||||
0x3e17f100,
|
||||
0x0010fe04,
|
||||
0x040017f1,
|
||||
0xf0c010d0,
|
||||
0x12d00427,
|
||||
0x1031f400,
|
||||
0x060817f1,
|
||||
0xcf0614b6,
|
||||
0x37f00012,
|
||||
0x1f24f001,
|
||||
0xb60432bb,
|
||||
0x02800132,
|
||||
0x04038003,
|
||||
0x040010b7,
|
||||
0x800012cf,
|
||||
0x27f10002,
|
||||
0x24b60800,
|
||||
0x0022cf06,
|
||||
/* 0x035f: init_find_chipset */
|
||||
0xb65817f0,
|
||||
0x13980c10,
|
||||
0x0432b800,
|
||||
0xb00b0bf4,
|
||||
0x1bf40034,
|
||||
/* 0x0373: init_context */
|
||||
0xf100f8f1,
|
||||
0xb6080027,
|
||||
0x22cf0624,
|
||||
0xf134bd40,
|
||||
0xb6070047,
|
||||
0x25950644,
|
||||
0x0045d008,
|
||||
0xbd4045d0,
|
||||
0x58f4bde4,
|
||||
0x1f58021e,
|
||||
0x020e4003,
|
||||
0xf5040f40,
|
||||
0xbb013d21,
|
||||
0x3fbb002f,
|
||||
0x041e5800,
|
||||
0x40051f58,
|
||||
0x0f400a0e,
|
||||
0x3d21f50c,
|
||||
0x030e9801,
|
||||
0xbb00effd,
|
||||
0x3ebb002e,
|
||||
0x0040b700,
|
||||
0x0235b613,
|
||||
0xb60043d0,
|
||||
0x35b60825,
|
||||
0x0120b606,
|
||||
0xb60130b6,
|
||||
0x34b60824,
|
||||
0x022fb908,
|
||||
0x026321f5,
|
||||
0xf1003fbb,
|
||||
0xb6080017,
|
||||
0x13d00614,
|
||||
0x0010b740,
|
||||
0xf024bd08,
|
||||
0x12d01f29,
|
||||
/* 0x0401: main */
|
||||
0x0031f400,
|
||||
0xf00028f4,
|
||||
0x21f41cd7,
|
||||
0xf401f439,
|
||||
0xf404e4b0,
|
||||
0x81fe1e18,
|
||||
0x0627f001,
|
||||
0x12fd20bd,
|
||||
0x01e4b604,
|
||||
0xfe051efd,
|
||||
0x21f50018,
|
||||
0x0ef404c3,
|
||||
/* 0x0431: main_not_ctx_xfer */
|
||||
0x10ef94d3,
|
||||
0xf501f5f0,
|
||||
0xf402ec21,
|
||||
/* 0x043e: ih */
|
||||
0x80f9c60e,
|
||||
0xf90188fe,
|
||||
0xf990f980,
|
||||
0xf9b0f9a0,
|
||||
0xf9e0f9d0,
|
||||
0x800acff0,
|
||||
0xf404abc4,
|
||||
0xb7f11d0b,
|
||||
0xd7f01900,
|
||||
0x40becf1c,
|
||||
0xf400bfcf,
|
||||
0xb0b70421,
|
||||
0xe7f00400,
|
||||
0x00bed001,
|
||||
/* 0x0474: ih_no_fifo */
|
||||
0xfc400ad0,
|
||||
0xfce0fcf0,
|
||||
0xfcb0fcd0,
|
||||
0xfc90fca0,
|
||||
0x0088fe80,
|
||||
0x32f480fc,
|
||||
/* 0x048f: hub_barrier_done */
|
||||
0xf001f800,
|
||||
0x0e9801f7,
|
||||
0x04febb00,
|
||||
0x9418e7f1,
|
||||
0xf440e3f0,
|
||||
0x00f88d21,
|
||||
/* 0x04a4: ctx_redswitch */
|
||||
0x0614e7f1,
|
||||
0xf006e4b6,
|
||||
0xefd020f7,
|
||||
0x08f7f000,
|
||||
/* 0x04b4: ctx_redswitch_delay */
|
||||
0xf401f2b6,
|
||||
0xf7f1fd1b,
|
||||
0xefd00a20,
|
||||
/* 0x04c3: ctx_xfer */
|
||||
0xf100f800,
|
||||
0xb60a0417,
|
||||
0x1fd00614,
|
||||
0x0711f400,
|
||||
0x04a421f5,
|
||||
/* 0x04d4: ctx_xfer_not_load */
|
||||
0x4afc17f1,
|
||||
0xf00213f0,
|
||||
0x12d00c27,
|
||||
0x0721f500,
|
||||
0xfc27f102,
|
||||
0x0223f047,
|
||||
0xf00020d0,
|
||||
0x20b6012c,
|
||||
0x0012d003,
|
||||
0xf001acf0,
|
||||
0xb7f002a5,
|
||||
0x50b3f000,
|
||||
0xb6000c98,
|
||||
0xbcbb0fc4,
|
||||
0x010c9800,
|
||||
0xf0020d98,
|
||||
0x21f500e7,
|
||||
0xacf0015c,
|
||||
0x04a5f001,
|
||||
0x4000b7f1,
|
||||
0x9850b3f0,
|
||||
0xc4b6000c,
|
||||
0x00bcbb0f,
|
||||
0x98050c98,
|
||||
0x0f98060d,
|
||||
0x00e7f104,
|
||||
0x5c21f508,
|
||||
0x0721f501,
|
||||
0x0601f402,
|
||||
/* 0x054b: ctx_xfer_post */
|
||||
0xf11412f4,
|
||||
0xf04afc17,
|
||||
0x27f00213,
|
||||
0x0012d00d,
|
||||
0x020721f5,
|
||||
/* 0x055c: ctx_xfer_done */
|
||||
0x048f21f5,
|
||||
0x000000f8,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
};
|
|
@ -24,11 +24,11 @@
|
|||
*/
|
||||
|
||||
/* To build:
|
||||
* m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h
|
||||
* m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h
|
||||
*/
|
||||
|
||||
.section #nvc0_grhub_data
|
||||
include(`nvc0_graph.fuc')
|
||||
include(`nvc0.fuc')
|
||||
gpc_count: .b32 0
|
||||
rop_count: .b32 0
|
||||
cmd_queue: queue_init
|
||||
|
@ -161,11 +161,11 @@ xfer_data: .b32 0
|
|||
.section #nvc0_grhub_code
|
||||
bra #init
|
||||
define(`include_code')
|
||||
include(`nvc0_graph.fuc')
|
||||
include(`nvc0.fuc')
|
||||
|
||||
// reports an exception to the host
|
||||
//
|
||||
// In: $r15 error code (see nvc0_graph.fuc)
|
||||
// In: $r15 error code (see nvc0.fuc)
|
||||
//
|
||||
error:
|
||||
push $r14
|
|
@ -1,4 +1,9 @@
|
|||
uint32_t nvc0_grhub_data[] = {
|
||||
/* 0x0000: gpc_count */
|
||||
0x00000000,
|
||||
/* 0x0004: rop_count */
|
||||
0x00000000,
|
||||
/* 0x0008: cmd_queue */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
@ -17,11 +22,13 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0050: hub_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0054: hub_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x0058: ctx_current */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x005c: chipsets */
|
||||
0x000000c0,
|
||||
0x013c00a0,
|
||||
0x000000c1,
|
||||
|
@ -39,6 +46,7 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x000000d9,
|
||||
0x01dc0140,
|
||||
0x00000000,
|
||||
/* 0x00a0: nvc0_hub_mmio_head */
|
||||
0x0417e91c,
|
||||
0x04400204,
|
||||
0x28404004,
|
||||
|
@ -78,7 +86,10 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x08408800,
|
||||
0x0c408900,
|
||||
0x00408980,
|
||||
/* 0x013c: nvc0_hub_mmio_tail */
|
||||
0x044064c0,
|
||||
/* 0x0140: nvc1_hub_mmio_tail */
|
||||
/* 0x0140: nvd9_hub_mmio_head */
|
||||
0x0417e91c,
|
||||
0x04400204,
|
||||
0x24404004,
|
||||
|
@ -118,6 +129,7 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x08408800,
|
||||
0x0c408900,
|
||||
0x00408980,
|
||||
/* 0x01dc: nvd9_hub_mmio_tail */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
@ -127,7 +139,10 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0200: chan_data */
|
||||
/* 0x0200: chan_mmio_count */
|
||||
0x00000000,
|
||||
/* 0x0204: chan_mmio_address */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
@ -191,17 +206,20 @@ uint32_t nvc0_grhub_data[] = {
|
|||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0300: xfer_data */
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
uint32_t nvc0_grhub_code[] = {
|
||||
0x03090ef5,
|
||||
/* 0x0004: queue_put */
|
||||
0x9800d898,
|
||||
0x86f001d9,
|
||||
0x0489b808,
|
||||
0xf00c1bf4,
|
||||
0x21f502f7,
|
||||
0x00f802ec,
|
||||
/* 0x001c: queue_put_next */
|
||||
0xb60798c4,
|
||||
0x8dbb0384,
|
||||
0x0880b600,
|
||||
|
@ -209,6 +227,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x90b6018f,
|
||||
0x0f94f001,
|
||||
0xf801d980,
|
||||
/* 0x0039: queue_get */
|
||||
0x0131f400,
|
||||
0x9800d898,
|
||||
0x89b801d9,
|
||||
|
@ -220,37 +239,46 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x80b6019f,
|
||||
0x0f84f001,
|
||||
0xf400d880,
|
||||
/* 0x0066: queue_get_done */
|
||||
0x00f80132,
|
||||
/* 0x0068: nv_rd32 */
|
||||
0x0728b7f1,
|
||||
0xb906b4b6,
|
||||
0xc9f002ec,
|
||||
0x00bcd01f,
|
||||
/* 0x0078: nv_rd32_wait */
|
||||
0xc800bccf,
|
||||
0x1bf41fcc,
|
||||
0x06a7f0fa,
|
||||
0x010321f5,
|
||||
0xf840bfcf,
|
||||
/* 0x008d: nv_wr32 */
|
||||
0x28b7f100,
|
||||
0x06b4b607,
|
||||
0xb980bfd0,
|
||||
0xc9f002ec,
|
||||
0x1ec9f01f,
|
||||
/* 0x00a3: nv_wr32_wait */
|
||||
0xcf00bcd0,
|
||||
0xccc800bc,
|
||||
0xfa1bf41f,
|
||||
/* 0x00ae: watchdog_reset */
|
||||
0x87f100f8,
|
||||
0x84b60430,
|
||||
0x1ff9f006,
|
||||
0xf8008fd0,
|
||||
/* 0x00bd: watchdog_clear */
|
||||
0x3087f100,
|
||||
0x0684b604,
|
||||
0xf80080d0,
|
||||
/* 0x00c9: wait_donez */
|
||||
0x3c87f100,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d000,
|
||||
0x081887f1,
|
||||
0xd00684b6,
|
||||
/* 0x00e2: wait_done_wait_donez */
|
||||
0x87f1008a,
|
||||
0x84b60400,
|
||||
0x0088cf06,
|
||||
|
@ -259,6 +287,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00099,
|
||||
/* 0x0103: wait_doneo */
|
||||
0xf100f800,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
|
@ -266,6 +295,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x87f10089,
|
||||
0x84b60818,
|
||||
0x008ad006,
|
||||
/* 0x011c: wait_done_wait_doneo */
|
||||
0x040087f1,
|
||||
0xcf0684b6,
|
||||
0x8aff0088,
|
||||
|
@ -274,6 +304,8 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xbd0684b6,
|
||||
0x0099f094,
|
||||
0xf80089d0,
|
||||
/* 0x013d: mmctx_size */
|
||||
/* 0x013f: nv_mmctx_size_loop */
|
||||
0x9894bd00,
|
||||
0x85b600e8,
|
||||
0x0180b61a,
|
||||
|
@ -282,6 +314,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x04efb804,
|
||||
0xb9eb1bf4,
|
||||
0x00f8029f,
|
||||
/* 0x015c: mmctx_xfer */
|
||||
0x083c87f1,
|
||||
0xbd0684b6,
|
||||
0x0199f094,
|
||||
|
@ -291,9 +324,11 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xf405bbfd,
|
||||
0x8bd0090b,
|
||||
0x0099f000,
|
||||
/* 0x0180: mmctx_base_disabled */
|
||||
0xf405eefd,
|
||||
0x8ed00c0b,
|
||||
0xc08fd080,
|
||||
/* 0x018f: mmctx_multi_disabled */
|
||||
0xb70199f0,
|
||||
0xc8010080,
|
||||
0xb4b600ab,
|
||||
|
@ -301,6 +336,8 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xb601aec8,
|
||||
0xbefd11e4,
|
||||
0x008bd005,
|
||||
/* 0x01a8: mmctx_exec_loop */
|
||||
/* 0x01a8: mmctx_wait_free */
|
||||
0xf0008ecf,
|
||||
0x0bf41fe4,
|
||||
0x00ce98fa,
|
||||
|
@ -309,34 +346,42 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x04cdb804,
|
||||
0xc8e81bf4,
|
||||
0x1bf402ab,
|
||||
/* 0x01c9: mmctx_fini_wait */
|
||||
0x008bcf18,
|
||||
0xb01fb4f0,
|
||||
0x1bf410b4,
|
||||
0x02a7f0f7,
|
||||
0xf4c921f4,
|
||||
/* 0x01de: mmctx_stop */
|
||||
0xabc81b0e,
|
||||
0x10b4b600,
|
||||
0xf00cb9f0,
|
||||
0x8bd012b9,
|
||||
/* 0x01ed: mmctx_stop_wait */
|
||||
0x008bcf00,
|
||||
0xf412bbc8,
|
||||
/* 0x01f6: mmctx_done */
|
||||
0x87f1fa1b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00199,
|
||||
/* 0x0207: strand_wait */
|
||||
0xf900f800,
|
||||
0x02a7f0a0,
|
||||
0xfcc921f4,
|
||||
/* 0x0213: strand_pre */
|
||||
0xf100f8a0,
|
||||
0xf04afc87,
|
||||
0x97f00283,
|
||||
0x0089d00c,
|
||||
0x020721f5,
|
||||
/* 0x0226: strand_post */
|
||||
0x87f100f8,
|
||||
0x83f04afc,
|
||||
0x0d97f002,
|
||||
0xf50089d0,
|
||||
0xf8020721,
|
||||
/* 0x0239: strand_set */
|
||||
0xfca7f100,
|
||||
0x02a3f04f,
|
||||
0x0500aba2,
|
||||
|
@ -347,6 +392,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xf000aed0,
|
||||
0xbcd00ac7,
|
||||
0x0721f500,
|
||||
/* 0x0263: strand_ctx_init */
|
||||
0xf100f802,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
|
@ -369,6 +415,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x0684b608,
|
||||
0xb70089cf,
|
||||
0x95220080,
|
||||
/* 0x02ba: ctx_init_strand_loop */
|
||||
0x8ed008fe,
|
||||
0x408ed000,
|
||||
0xb6808acf,
|
||||
|
@ -382,6 +429,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x00f80089,
|
||||
/* 0x02ec: error */
|
||||
0xe7f1e0f9,
|
||||
0xe4b60814,
|
||||
0x00efd006,
|
||||
|
@ -389,6 +437,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xf006e4b6,
|
||||
0xefd001f7,
|
||||
0xf8e0fc00,
|
||||
/* 0x0309: init */
|
||||
0xfe04bd00,
|
||||
0x07fe0004,
|
||||
0x0017f100,
|
||||
|
@ -429,11 +478,13 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x080027f1,
|
||||
0xcf0624b6,
|
||||
0xf7f00022,
|
||||
/* 0x03a9: init_find_chipset */
|
||||
0x08f0b654,
|
||||
0xb800f398,
|
||||
0x0bf40432,
|
||||
0x0034b00b,
|
||||
0xf8f11bf4,
|
||||
/* 0x03bd: init_context */
|
||||
0x0017f100,
|
||||
0x02fe5801,
|
||||
0xf003ff58,
|
||||
|
@ -454,6 +505,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x001fbb02,
|
||||
0xf1000398,
|
||||
0xf0200047,
|
||||
/* 0x040e: init_gpc */
|
||||
0x4ea05043,
|
||||
0x1fb90804,
|
||||
0x8d21f402,
|
||||
|
@ -467,6 +519,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xf7f00100,
|
||||
0x8d21f402,
|
||||
0x08004ea0,
|
||||
/* 0x0440: init_gpc_wait */
|
||||
0xc86821f4,
|
||||
0x0bf41fff,
|
||||
0x044ea0fa,
|
||||
|
@ -479,6 +532,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xb74021d0,
|
||||
0xbd080020,
|
||||
0x1f19f014,
|
||||
/* 0x0473: main */
|
||||
0xf40021d0,
|
||||
0x28f40031,
|
||||
0x08d7f000,
|
||||
|
@ -517,6 +571,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x94bd0684,
|
||||
0xd00699f0,
|
||||
0x0ef40089,
|
||||
/* 0x0509: chsw_prev_no_next */
|
||||
0xb920f931,
|
||||
0x32f40212,
|
||||
0x0232f401,
|
||||
|
@ -524,10 +579,12 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x17f120fc,
|
||||
0x14b60b00,
|
||||
0x0012d006,
|
||||
/* 0x0527: chsw_no_prev */
|
||||
0xc8130ef4,
|
||||
0x0bf41f23,
|
||||
0x0131f40d,
|
||||
0xf50232f4,
|
||||
/* 0x0537: chsw_done */
|
||||
0xf1082921,
|
||||
0xb60b0c17,
|
||||
0x27f00614,
|
||||
|
@ -536,10 +593,12 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xbd0684b6,
|
||||
0x0499f094,
|
||||
0xf50089d0,
|
||||
/* 0x0557: main_not_ctx_switch */
|
||||
0xb0ff200e,
|
||||
0x1bf401e4,
|
||||
0x02f2b90d,
|
||||
0x07b521f5,
|
||||
/* 0x0567: main_not_ctx_chan */
|
||||
0xb0420ef4,
|
||||
0x1bf402e4,
|
||||
0x3c87f12e,
|
||||
|
@ -553,14 +612,17 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xf094bd06,
|
||||
0x89d00799,
|
||||
0x110ef400,
|
||||
/* 0x0598: main_not_ctx_save */
|
||||
0xf010ef94,
|
||||
0x21f501f5,
|
||||
0x0ef502ec,
|
||||
/* 0x05a6: main_done */
|
||||
0x17f1fed1,
|
||||
0x14b60820,
|
||||
0xf024bd06,
|
||||
0x12d01f29,
|
||||
0xbe0ef500,
|
||||
/* 0x05b9: ih */
|
||||
0xfe80f9fe,
|
||||
0x80f90188,
|
||||
0xa0f990f9,
|
||||
|
@ -574,16 +636,19 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x21f400bf,
|
||||
0x00b0b704,
|
||||
0x01e7f004,
|
||||
/* 0x05ef: ih_no_fifo */
|
||||
0xe400bed0,
|
||||
0xf40100ab,
|
||||
0xd7f00d0b,
|
||||
0x01e7f108,
|
||||
0x0421f440,
|
||||
/* 0x0600: ih_no_ctxsw */
|
||||
0x0104b7f1,
|
||||
0xabffb0bd,
|
||||
0x0d0bf4b4,
|
||||
0x0c1ca7f1,
|
||||
0xd006a4b6,
|
||||
/* 0x0616: ih_no_other */
|
||||
0x0ad000ab,
|
||||
0xfcf0fc40,
|
||||
0xfcd0fce0,
|
||||
|
@ -591,32 +656,40 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xfe80fc90,
|
||||
0x80fc0088,
|
||||
0xf80032f4,
|
||||
/* 0x0631: ctx_4160s */
|
||||
0x60e7f101,
|
||||
0x40e3f041,
|
||||
0xf401f7f0,
|
||||
/* 0x063e: ctx_4160s_wait */
|
||||
0x21f48d21,
|
||||
0x04ffc868,
|
||||
0xf8fa0bf4,
|
||||
/* 0x0649: ctx_4160c */
|
||||
0x60e7f100,
|
||||
0x40e3f041,
|
||||
0x21f4f4bd,
|
||||
/* 0x0657: ctx_4170s */
|
||||
0xf100f88d,
|
||||
0xf04170e7,
|
||||
0xf5f040e3,
|
||||
0x8d21f410,
|
||||
/* 0x0666: ctx_4170w */
|
||||
0xe7f100f8,
|
||||
0xe3f04170,
|
||||
0x6821f440,
|
||||
0xf410f4f0,
|
||||
0x00f8f31b,
|
||||
/* 0x0678: ctx_redswitch */
|
||||
0x0614e7f1,
|
||||
0xf106e4b6,
|
||||
0xd00270f7,
|
||||
0xf7f000ef,
|
||||
/* 0x0689: ctx_redswitch_delay */
|
||||
0x01f2b608,
|
||||
0xf1fd1bf4,
|
||||
0xd00770f7,
|
||||
0x00f800ef,
|
||||
/* 0x0698: ctx_86c */
|
||||
0x086ce7f1,
|
||||
0xd006e4b6,
|
||||
0xe7f100ef,
|
||||
|
@ -625,6 +698,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xa86ce7f1,
|
||||
0xf441e3f0,
|
||||
0x00f88d21,
|
||||
/* 0x06b8: ctx_load */
|
||||
0x083c87f1,
|
||||
0xbd0684b6,
|
||||
0x0599f094,
|
||||
|
@ -639,6 +713,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x0614b60a,
|
||||
0xd00747f0,
|
||||
0x14d00012,
|
||||
/* 0x06f1: ctx_chan_wait_0 */
|
||||
0x4014cf40,
|
||||
0xf41f44f0,
|
||||
0x32d0fa1b,
|
||||
|
@ -688,6 +763,7 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xbd0684b6,
|
||||
0x0599f094,
|
||||
0xf80089d0,
|
||||
/* 0x07b5: ctx_chan */
|
||||
0x3121f500,
|
||||
0xb821f506,
|
||||
0x0ca7f006,
|
||||
|
@ -695,39 +771,48 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0xb60a1017,
|
||||
0x27f00614,
|
||||
0x0012d005,
|
||||
/* 0x07d0: ctx_chan_wait */
|
||||
0xfd0012cf,
|
||||
0x1bf40522,
|
||||
0x4921f5fa,
|
||||
/* 0x07df: ctx_mmio_exec */
|
||||
0x9800f806,
|
||||
0x27f18103,
|
||||
0x24b60a04,
|
||||
0x0023d006,
|
||||
/* 0x07ee: ctx_mmio_loop */
|
||||
0x34c434bd,
|
||||
0x0f1bf4ff,
|
||||
0x030057f1,
|
||||
0xfa0653f0,
|
||||
0x03f80535,
|
||||
/* 0x0800: ctx_mmio_pull */
|
||||
0x98c04e98,
|
||||
0x21f4c14f,
|
||||
0x0830b68d,
|
||||
0xf40112b6,
|
||||
/* 0x0812: ctx_mmio_done */
|
||||
0x0398df1b,
|
||||
0x0023d016,
|
||||
0xf1800080,
|
||||
0xf0020017,
|
||||
0x01fa0613,
|
||||
0xf803f806,
|
||||
/* 0x0829: ctx_xfer */
|
||||
0x0611f400,
|
||||
/* 0x082f: ctx_xfer_pre */
|
||||
0xf01102f4,
|
||||
0x21f510f7,
|
||||
0x21f50698,
|
||||
0x11f40631,
|
||||
/* 0x083d: ctx_xfer_pre_load */
|
||||
0x02f7f01c,
|
||||
0x065721f5,
|
||||
0x066621f5,
|
||||
0x067821f5,
|
||||
0x21f5f4bd,
|
||||
0x21f50657,
|
||||
/* 0x0856: ctx_xfer_exec */
|
||||
0x019806b8,
|
||||
0x1427f116,
|
||||
0x0624b604,
|
||||
|
@ -762,9 +847,11 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x0a1017f1,
|
||||
0xf00614b6,
|
||||
0x12d00527,
|
||||
/* 0x08dd: ctx_xfer_post_save_wait */
|
||||
0x0012cf00,
|
||||
0xf40522fd,
|
||||
0x02f4fa1b,
|
||||
/* 0x08e9: ctx_xfer_post */
|
||||
0x02f7f032,
|
||||
0x065721f5,
|
||||
0x21f5f4bd,
|
||||
|
@ -776,7 +863,9 @@ uint32_t nvc0_grhub_code[] = {
|
|||
0x11fd8001,
|
||||
0x070bf405,
|
||||
0x07df21f5,
|
||||
/* 0x0914: ctx_xfer_no_post_mmio */
|
||||
0x064921f5,
|
||||
/* 0x0918: ctx_xfer_done */
|
||||
0x000000f8,
|
||||
0x00000000,
|
||||
0x00000000,
|
|
@ -0,0 +1,780 @@
|
|||
/* fuc microcode for nve0 PGRAPH/HUB
|
||||
*
|
||||
* Copyright 2011 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
/* To build:
|
||||
* m4 nve0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grhub.fuc.h
|
||||
*/
|
||||
|
||||
.section #nve0_grhub_data
|
||||
include(`nve0.fuc')
|
||||
gpc_count: .b32 0
|
||||
rop_count: .b32 0
|
||||
cmd_queue: queue_init
|
||||
hub_mmio_list_head: .b32 0
|
||||
hub_mmio_list_tail: .b32 0
|
||||
|
||||
ctx_current: .b32 0
|
||||
|
||||
chipsets:
|
||||
.b8 0xe4 0 0 0
|
||||
.b16 #nve4_hub_mmio_head
|
||||
.b16 #nve4_hub_mmio_tail
|
||||
.b8 0xe7 0 0 0
|
||||
.b16 #nve4_hub_mmio_head
|
||||
.b16 #nve4_hub_mmio_tail
|
||||
.b8 0 0 0 0
|
||||
|
||||
nve4_hub_mmio_head:
|
||||
mmctx_data(0x17e91c, 2)
|
||||
mmctx_data(0x400204, 2)
|
||||
mmctx_data(0x404010, 7)
|
||||
mmctx_data(0x4040a8, 9)
|
||||
mmctx_data(0x4040d0, 7)
|
||||
mmctx_data(0x4040f8, 1)
|
||||
mmctx_data(0x404130, 3)
|
||||
mmctx_data(0x404150, 3)
|
||||
mmctx_data(0x404164, 1)
|
||||
mmctx_data(0x4041a0, 4)
|
||||
mmctx_data(0x404200, 4)
|
||||
mmctx_data(0x404404, 14)
|
||||
mmctx_data(0x404460, 4)
|
||||
mmctx_data(0x404480, 1)
|
||||
mmctx_data(0x404498, 1)
|
||||
mmctx_data(0x404604, 4)
|
||||
mmctx_data(0x404618, 4)
|
||||
mmctx_data(0x40462c, 2)
|
||||
mmctx_data(0x404640, 1)
|
||||
mmctx_data(0x404654, 1)
|
||||
mmctx_data(0x404660, 1)
|
||||
mmctx_data(0x404678, 19)
|
||||
mmctx_data(0x4046c8, 3)
|
||||
mmctx_data(0x404700, 3)
|
||||
mmctx_data(0x404718, 10)
|
||||
mmctx_data(0x404744, 2)
|
||||
mmctx_data(0x404754, 1)
|
||||
mmctx_data(0x405800, 1)
|
||||
mmctx_data(0x405830, 3)
|
||||
mmctx_data(0x405854, 1)
|
||||
mmctx_data(0x405870, 4)
|
||||
mmctx_data(0x405a00, 2)
|
||||
mmctx_data(0x405a18, 1)
|
||||
mmctx_data(0x405b00, 1)
|
||||
mmctx_data(0x405b10, 1)
|
||||
mmctx_data(0x406020, 1)
|
||||
mmctx_data(0x406028, 4)
|
||||
mmctx_data(0x4064a8, 2)
|
||||
mmctx_data(0x4064b4, 2)
|
||||
mmctx_data(0x4064c0, 12)
|
||||
mmctx_data(0x4064fc, 1)
|
||||
mmctx_data(0x407040, 1)
|
||||
mmctx_data(0x407804, 1)
|
||||
mmctx_data(0x40780c, 6)
|
||||
mmctx_data(0x4078bc, 1)
|
||||
mmctx_data(0x408000, 7)
|
||||
mmctx_data(0x408064, 1)
|
||||
mmctx_data(0x408800, 3)
|
||||
mmctx_data(0x408840, 1)
|
||||
mmctx_data(0x408900, 3)
|
||||
mmctx_data(0x408980, 1)
|
||||
nve4_hub_mmio_tail:
|
||||
|
||||
.align 256
|
||||
chan_data:
|
||||
chan_mmio_count: .b32 0
|
||||
chan_mmio_address: .b32 0
|
||||
|
||||
.align 256
|
||||
xfer_data: .b32 0
|
||||
|
||||
.section #nve0_grhub_code
|
||||
bra #init
|
||||
define(`include_code')
|
||||
include(`nve0.fuc')
|
||||
|
||||
// reports an exception to the host
|
||||
//
|
||||
// In: $r15 error code (see nve0.fuc)
|
||||
//
|
||||
error:
|
||||
push $r14
|
||||
mov $r14 0x814
|
||||
shl b32 $r14 6
|
||||
iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code
|
||||
mov $r14 0xc1c
|
||||
shl b32 $r14 6
|
||||
mov $r15 1
|
||||
iowr I[$r14 + 0x000] $r15 // INTR_UP_SET
|
||||
pop $r14
|
||||
ret
|
||||
|
||||
// HUB fuc initialisation, executed by triggering ucode start, will
|
||||
// fall through to main loop after completion.
|
||||
//
|
||||
// Input:
|
||||
// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
|
||||
//
|
||||
// Output:
|
||||
// CC_SCRATCH[0]:
|
||||
// 31:31: set to signal completion
|
||||
// CC_SCRATCH[1]:
|
||||
// 31:0: total PGRAPH context size
|
||||
//
|
||||
init:
|
||||
clear b32 $r0
|
||||
mov $sp $r0
|
||||
mov $xdbase $r0
|
||||
|
||||
// enable fifo access
|
||||
mov $r1 0x1200
|
||||
mov $r2 2
|
||||
iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
|
||||
|
||||
// setup i0 handler, and route all interrupts to it
|
||||
mov $r1 #ih
|
||||
mov $iv0 $r1
|
||||
mov $r1 0x400
|
||||
iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
|
||||
|
||||
// route HUB_CHANNEL_SWITCH to fuc interrupt 8
|
||||
mov $r3 0x404
|
||||
shl b32 $r3 6
|
||||
mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
|
||||
iowr I[$r3 + 0x000] $r2
|
||||
|
||||
// not sure what these are, route them because NVIDIA does, and
|
||||
// the IRQ handler will signal the host if we ever get one.. we
|
||||
// may find out if/why we need to handle these if so..
|
||||
//
|
||||
mov $r2 0x2004
|
||||
iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
|
||||
mov $r2 0x200b
|
||||
iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
|
||||
mov $r2 0x200c
|
||||
iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
|
||||
|
||||
// enable all INTR_UP interrupts
|
||||
mov $r2 0xc24
|
||||
shl b32 $r2 6
|
||||
not b32 $r3 $r0
|
||||
iowr I[$r2] $r3
|
||||
|
||||
// enable fifo, ctxsw, 9, 10, 15 interrupts
|
||||
mov $r2 -0x78fc // 0x8704
|
||||
sethi $r2 0
|
||||
iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
|
||||
|
||||
// fifo level triggered, rest edge
|
||||
sub b32 $r1 0x100
|
||||
mov $r2 4
|
||||
iowr I[$r1] $r2
|
||||
|
||||
// enable interrupts
|
||||
bset $flags ie0
|
||||
|
||||
// fetch enabled GPC/ROP counts
|
||||
mov $r14 -0x69fc // 0x409604
|
||||
sethi $r14 0x400000
|
||||
call #nv_rd32
|
||||
extr $r1 $r15 16:20
|
||||
st b32 D[$r0 + #rop_count] $r1
|
||||
and $r15 0x1f
|
||||
st b32 D[$r0 + #gpc_count] $r15
|
||||
|
||||
// set BAR_REQMASK to GPC mask
|
||||
mov $r1 1
|
||||
shl b32 $r1 $r15
|
||||
sub b32 $r1 1
|
||||
mov $r2 0x40c
|
||||
shl b32 $r2 6
|
||||
iowr I[$r2 + 0x000] $r1
|
||||
iowr I[$r2 + 0x100] $r1
|
||||
|
||||
// find context data for this chipset
|
||||
mov $r2 0x800
|
||||
shl b32 $r2 6
|
||||
iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
|
||||
mov $r15 #chipsets - 8
|
||||
init_find_chipset:
|
||||
add b32 $r15 8
|
||||
ld b32 $r3 D[$r15 + 0x00]
|
||||
cmpu b32 $r3 $r2
|
||||
bra e #init_context
|
||||
cmpu b32 $r3 0
|
||||
bra ne #init_find_chipset
|
||||
// unknown chipset
|
||||
ret
|
||||
|
||||
// context size calculation, reserve first 256 bytes for use by fuc
|
||||
init_context:
|
||||
mov $r1 256
|
||||
|
||||
// calculate size of mmio context data
|
||||
ld b16 $r14 D[$r15 + 4]
|
||||
ld b16 $r15 D[$r15 + 6]
|
||||
sethi $r14 0
|
||||
st b32 D[$r0 + #hub_mmio_list_head] $r14
|
||||
st b32 D[$r0 + #hub_mmio_list_tail] $r15
|
||||
call #mmctx_size
|
||||
|
||||
// set mmctx base addresses now so we don't have to do it later,
|
||||
// they don't (currently) ever change
|
||||
mov $r3 0x700
|
||||
shl b32 $r3 6
|
||||
shr b32 $r4 $r1 8
|
||||
iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE
|
||||
iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE
|
||||
add b32 $r3 0x1300
|
||||
add b32 $r1 $r15
|
||||
shr b32 $r15 2
|
||||
iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!?
|
||||
|
||||
// strands, base offset needs to be aligned to 256 bytes
|
||||
shr b32 $r1 8
|
||||
add b32 $r1 1
|
||||
shl b32 $r1 8
|
||||
mov b32 $r15 $r1
|
||||
call #strand_ctx_init
|
||||
add b32 $r1 $r15
|
||||
|
||||
// initialise each GPC in sequence by passing in the offset of its
|
||||
// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
|
||||
// has previously been uploaded by the host) running.
|
||||
//
|
||||
// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
|
||||
// when it has completed, and return the size of its context data
|
||||
// in GPCn_CC_SCRATCH[1]
|
||||
//
|
||||
ld b32 $r3 D[$r0 + #gpc_count]
|
||||
mov $r4 0x2000
|
||||
sethi $r4 0x500000
|
||||
init_gpc:
|
||||
// setup, and start GPC ucode running
|
||||
add b32 $r14 $r4 0x804
|
||||
mov b32 $r15 $r1
|
||||
call #nv_wr32 // CC_SCRATCH[1] = ctx offset
|
||||
add b32 $r14 $r4 0x800
|
||||
mov b32 $r15 $r2
|
||||
call #nv_wr32 // CC_SCRATCH[0] = chipset
|
||||
add b32 $r14 $r4 0x10c
|
||||
clear b32 $r15
|
||||
call #nv_wr32
|
||||
add b32 $r14 $r4 0x104
|
||||
call #nv_wr32 // ENTRY
|
||||
add b32 $r14 $r4 0x100
|
||||
mov $r15 2 // CTRL_START_TRIGGER
|
||||
call #nv_wr32 // CTRL
|
||||
|
||||
// wait for it to complete, and adjust context size
|
||||
add b32 $r14 $r4 0x800
|
||||
init_gpc_wait:
|
||||
call #nv_rd32
|
||||
xbit $r15 $r15 31
|
||||
bra e #init_gpc_wait
|
||||
add b32 $r14 $r4 0x804
|
||||
call #nv_rd32
|
||||
add b32 $r1 $r15
|
||||
|
||||
// next!
|
||||
add b32 $r4 0x8000
|
||||
sub b32 $r3 1
|
||||
bra ne #init_gpc
|
||||
|
||||
// save context size, and tell host we're ready
|
||||
mov $r2 0x800
|
||||
shl b32 $r2 6
|
||||
iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size
|
||||
add b32 $r2 0x800
|
||||
clear b32 $r1
|
||||
bset $r1 31
|
||||
iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000
|
||||
|
||||
// Main program loop, very simple, sleeps until woken up by the interrupt
|
||||
// handler, pulls a command from the queue and executes its handler
|
||||
//
|
||||
main:
|
||||
// sleep until we have something to do
|
||||
bset $flags $p0
|
||||
sleep $p0
|
||||
mov $r13 #cmd_queue
|
||||
call #queue_get
|
||||
bra $p1 #main
|
||||
|
||||
// context switch, requested by GPU?
|
||||
cmpu b32 $r14 0x4001
|
||||
bra ne #main_not_ctx_switch
|
||||
trace_set(T_AUTO)
|
||||
mov $r1 0xb00
|
||||
shl b32 $r1 6
|
||||
iord $r2 I[$r1 + 0x100] // CHAN_NEXT
|
||||
iord $r1 I[$r1 + 0x000] // CHAN_CUR
|
||||
|
||||
xbit $r3 $r1 31
|
||||
bra e #chsw_no_prev
|
||||
xbit $r3 $r2 31
|
||||
bra e #chsw_prev_no_next
|
||||
push $r2
|
||||
mov b32 $r2 $r1
|
||||
trace_set(T_SAVE)
|
||||
bclr $flags $p1
|
||||
bset $flags $p2
|
||||
call #ctx_xfer
|
||||
trace_clr(T_SAVE);
|
||||
pop $r2
|
||||
trace_set(T_LOAD);
|
||||
bset $flags $p1
|
||||
call #ctx_xfer
|
||||
trace_clr(T_LOAD);
|
||||
bra #chsw_done
|
||||
chsw_prev_no_next:
|
||||
push $r2
|
||||
mov b32 $r2 $r1
|
||||
bclr $flags $p1
|
||||
bclr $flags $p2
|
||||
call #ctx_xfer
|
||||
pop $r2
|
||||
mov $r1 0xb00
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1] $r2
|
||||
bra #chsw_done
|
||||
chsw_no_prev:
|
||||
xbit $r3 $r2 31
|
||||
bra e #chsw_done
|
||||
bset $flags $p1
|
||||
bclr $flags $p2
|
||||
call #ctx_xfer
|
||||
|
||||
// ack the context switch request
|
||||
chsw_done:
|
||||
mov $r1 0xb0c
|
||||
shl b32 $r1 6
|
||||
mov $r2 1
|
||||
iowr I[$r1 + 0x000] $r2 // 0x409b0c
|
||||
trace_clr(T_AUTO)
|
||||
bra #main
|
||||
|
||||
// request to set current channel? (*not* a context switch)
|
||||
main_not_ctx_switch:
|
||||
cmpu b32 $r14 0x0001
|
||||
bra ne #main_not_ctx_chan
|
||||
mov b32 $r2 $r15
|
||||
call #ctx_chan
|
||||
bra #main_done
|
||||
|
||||
// request to store current channel context?
|
||||
main_not_ctx_chan:
|
||||
cmpu b32 $r14 0x0002
|
||||
bra ne #main_not_ctx_save
|
||||
trace_set(T_SAVE)
|
||||
bclr $flags $p1
|
||||
bclr $flags $p2
|
||||
call #ctx_xfer
|
||||
trace_clr(T_SAVE)
|
||||
bra #main_done
|
||||
|
||||
main_not_ctx_save:
|
||||
shl b32 $r15 $r14 16
|
||||
or $r15 E_BAD_COMMAND
|
||||
call #error
|
||||
bra #main
|
||||
|
||||
main_done:
|
||||
mov $r1 0x820
|
||||
shl b32 $r1 6
|
||||
clear b32 $r2
|
||||
bset $r2 31
|
||||
iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
|
||||
bra #main
|
||||
|
||||
// interrupt handler
|
||||
ih:
|
||||
push $r8
|
||||
mov $r8 $flags
|
||||
push $r8
|
||||
push $r9
|
||||
push $r10
|
||||
push $r11
|
||||
push $r13
|
||||
push $r14
|
||||
push $r15
|
||||
|
||||
// incoming fifo command?
|
||||
iord $r10 I[$r0 + 0x200] // INTR
|
||||
and $r11 $r10 0x00000004
|
||||
bra e #ih_no_fifo
|
||||
// queue incoming fifo command for later processing
|
||||
mov $r11 0x1900
|
||||
mov $r13 #cmd_queue
|
||||
iord $r14 I[$r11 + 0x100] // FIFO_CMD
|
||||
iord $r15 I[$r11 + 0x000] // FIFO_DATA
|
||||
call #queue_put
|
||||
add b32 $r11 0x400
|
||||
mov $r14 1
|
||||
iowr I[$r11 + 0x000] $r14 // FIFO_ACK
|
||||
|
||||
// context switch request?
|
||||
ih_no_fifo:
|
||||
and $r11 $r10 0x00000100
|
||||
bra e #ih_no_ctxsw
|
||||
// enqueue a context switch for later processing
|
||||
mov $r13 #cmd_queue
|
||||
mov $r14 0x4001
|
||||
call #queue_put
|
||||
|
||||
// anything we didn't handle, bring it to the host's attention
|
||||
ih_no_ctxsw:
|
||||
mov $r11 0x104
|
||||
not b32 $r11
|
||||
and $r11 $r10 $r11
|
||||
bra e #ih_no_other
|
||||
mov $r10 0xc1c
|
||||
shl b32 $r10 6
|
||||
iowr I[$r10] $r11 // INTR_UP_SET
|
||||
|
||||
// ack, and wake up main()
|
||||
ih_no_other:
|
||||
iowr I[$r0 + 0x100] $r10 // INTR_ACK
|
||||
|
||||
pop $r15
|
||||
pop $r14
|
||||
pop $r13
|
||||
pop $r11
|
||||
pop $r10
|
||||
pop $r9
|
||||
pop $r8
|
||||
mov $flags $r8
|
||||
pop $r8
|
||||
bclr $flags $p0
|
||||
iret
|
||||
|
||||
// Again, not real sure
|
||||
//
|
||||
// In: $r15 value to set 0x404170 to
|
||||
//
|
||||
ctx_4170s:
|
||||
mov $r14 0x4170
|
||||
sethi $r14 0x400000
|
||||
or $r15 0x10
|
||||
call #nv_wr32
|
||||
ret
|
||||
|
||||
// Waits for a ctx_4170s() call to complete
|
||||
//
|
||||
ctx_4170w:
|
||||
mov $r14 0x4170
|
||||
sethi $r14 0x400000
|
||||
call #nv_rd32
|
||||
and $r15 0x10
|
||||
bra ne #ctx_4170w
|
||||
ret
|
||||
|
||||
// Disables various things, waits a bit, and re-enables them..
|
||||
//
|
||||
// Not sure how exactly this helps, perhaps "ENABLE" is not such a
|
||||
// good description for the bits we turn off? Anyways, without this,
|
||||
// funny things happen.
|
||||
//
|
||||
ctx_redswitch:
|
||||
mov $r14 0x614
|
||||
shl b32 $r14 6
|
||||
mov $r15 0x270
|
||||
iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
|
||||
mov $r15 8
|
||||
ctx_redswitch_delay:
|
||||
sub b32 $r15 1
|
||||
bra ne #ctx_redswitch_delay
|
||||
mov $r15 0x770
|
||||
iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
|
||||
ret
|
||||
|
||||
// Not a clue what this is for, except that unless the value is 0x10, the
|
||||
// strand context is saved (and presumably restored) incorrectly..
|
||||
//
|
||||
// In: $r15 value to set to (0x00/0x10 are used)
|
||||
//
|
||||
ctx_86c:
|
||||
mov $r14 0x86c
|
||||
shl b32 $r14 6
|
||||
iowr I[$r14] $r15 // HUB(0x86c) = val
|
||||
mov $r14 -0x75ec
|
||||
sethi $r14 0x400000
|
||||
call #nv_wr32 // ROP(0xa14) = val
|
||||
mov $r14 -0x5794
|
||||
sethi $r14 0x410000
|
||||
call #nv_wr32 // GPC(0x86c) = val
|
||||
ret
|
||||
|
||||
// ctx_load - load's a channel's ctxctl data, and selects its vm
|
||||
//
|
||||
// In: $r2 channel address
|
||||
//
|
||||
ctx_load:
|
||||
trace_set(T_CHAN)
|
||||
|
||||
// switch to channel, somewhat magic in parts..
|
||||
mov $r10 12 // DONE_UNK12
|
||||
call #wait_donez
|
||||
mov $r1 0xa24
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1 + 0x000] $r0 // 0x409a24
|
||||
mov $r3 0xb00
|
||||
shl b32 $r3 6
|
||||
iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
|
||||
mov $r1 0xa0c
|
||||
shl b32 $r1 6
|
||||
mov $r4 7
|
||||
iowr I[$r1 + 0x000] $r2 // MEM_CHAN
|
||||
iowr I[$r1 + 0x100] $r4 // MEM_CMD
|
||||
ctx_chan_wait_0:
|
||||
iord $r4 I[$r1 + 0x100]
|
||||
and $r4 0x1f
|
||||
bra ne #ctx_chan_wait_0
|
||||
iowr I[$r3 + 0x000] $r2 // CHAN_CUR
|
||||
|
||||
// load channel header, fetch PGRAPH context pointer
|
||||
mov $xtargets $r0
|
||||
bclr $r2 31
|
||||
shl b32 $r2 4
|
||||
add b32 $r2 2
|
||||
|
||||
trace_set(T_LCHAN)
|
||||
mov $r1 0xa04
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1 + 0x000] $r2 // MEM_BASE
|
||||
mov $r1 0xa20
|
||||
shl b32 $r1 6
|
||||
mov $r2 0x0002
|
||||
sethi $r2 0x80000000
|
||||
iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram
|
||||
mov $r1 0x10 // chan + 0x0210
|
||||
mov $r2 #xfer_data
|
||||
sethi $r2 0x00020000 // 16 bytes
|
||||
xdld $r1 $r2
|
||||
xdwait
|
||||
trace_clr(T_LCHAN)
|
||||
|
||||
// update current context
|
||||
ld b32 $r1 D[$r0 + #xfer_data + 4]
|
||||
shl b32 $r1 24
|
||||
ld b32 $r2 D[$r0 + #xfer_data + 0]
|
||||
shr b32 $r2 8
|
||||
or $r1 $r2
|
||||
st b32 D[$r0 + #ctx_current] $r1
|
||||
|
||||
// set transfer base to start of context, and fetch context header
|
||||
trace_set(T_LCTXH)
|
||||
mov $r2 0xa04
|
||||
shl b32 $r2 6
|
||||
iowr I[$r2 + 0x000] $r1 // MEM_BASE
|
||||
mov $r2 1
|
||||
mov $r1 0xa20
|
||||
shl b32 $r1 6
|
||||
iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm
|
||||
mov $r1 #chan_data
|
||||
sethi $r1 0x00060000 // 256 bytes
|
||||
xdld $r0 $r1
|
||||
xdwait
|
||||
trace_clr(T_LCTXH)
|
||||
|
||||
trace_clr(T_CHAN)
|
||||
ret
|
||||
|
||||
// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
|
||||
// the active channel for ctxctl, but not actually transfer
|
||||
// any context data. intended for use only during initial
|
||||
// context construction.
|
||||
//
|
||||
// In: $r2 channel address
|
||||
//
|
||||
ctx_chan:
|
||||
call #ctx_load
|
||||
mov $r10 12 // DONE_UNK12
|
||||
call #wait_donez
|
||||
mov $r1 0xa10
|
||||
shl b32 $r1 6
|
||||
mov $r2 5
|
||||
iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???)
|
||||
ctx_chan_wait:
|
||||
iord $r2 I[$r1 + 0x000]
|
||||
or $r2 $r2
|
||||
bra ne #ctx_chan_wait
|
||||
ret
|
||||
|
||||
// Execute per-context state overrides list
|
||||
//
|
||||
// Only executed on the first load of a channel. Might want to look into
|
||||
// removing this and having the host directly modify the channel's context
|
||||
// to change this state... The nouveau DRM already builds this list as
|
||||
// it's definitely needed for NVIDIA's, so we may as well use it for now
|
||||
//
|
||||
// Input: $r1 mmio list length
|
||||
//
|
||||
ctx_mmio_exec:
|
||||
// set transfer base to be the mmio list
|
||||
ld b32 $r3 D[$r0 + #chan_mmio_address]
|
||||
mov $r2 0xa04
|
||||
shl b32 $r2 6
|
||||
iowr I[$r2 + 0x000] $r3 // MEM_BASE
|
||||
|
||||
clear b32 $r3
|
||||
ctx_mmio_loop:
|
||||
// fetch next 256 bytes of mmio list if necessary
|
||||
and $r4 $r3 0xff
|
||||
bra ne #ctx_mmio_pull
|
||||
mov $r5 #xfer_data
|
||||
sethi $r5 0x00060000 // 256 bytes
|
||||
xdld $r3 $r5
|
||||
xdwait
|
||||
|
||||
// execute a single list entry
|
||||
ctx_mmio_pull:
|
||||
ld b32 $r14 D[$r4 + #xfer_data + 0x00]
|
||||
ld b32 $r15 D[$r4 + #xfer_data + 0x04]
|
||||
call #nv_wr32
|
||||
|
||||
// next!
|
||||
add b32 $r3 8
|
||||
sub b32 $r1 1
|
||||
bra ne #ctx_mmio_loop
|
||||
|
||||
// set transfer base back to the current context
|
||||
ctx_mmio_done:
|
||||
ld b32 $r3 D[$r0 + #ctx_current]
|
||||
iowr I[$r2 + 0x000] $r3 // MEM_BASE
|
||||
|
||||
// disable the mmio list now, we don't need/want to execute it again
|
||||
st b32 D[$r0 + #chan_mmio_count] $r0
|
||||
mov $r1 #chan_data
|
||||
sethi $r1 0x00060000 // 256 bytes
|
||||
xdst $r0 $r1
|
||||
xdwait
|
||||
ret
|
||||
|
||||
// Transfer HUB context data between GPU and storage area
|
||||
//
|
||||
// In: $r2 channel address
|
||||
// $p1 clear on save, set on load
|
||||
// $p2 set if opposite direction done/will be done, so:
|
||||
// on save it means: "a load will follow this save"
|
||||
// on load it means: "a save preceeded this load"
|
||||
//
|
||||
ctx_xfer:
|
||||
bra not $p1 #ctx_xfer_pre
|
||||
bra $p2 #ctx_xfer_pre_load
|
||||
ctx_xfer_pre:
|
||||
mov $r15 0x10
|
||||
call #ctx_86c
|
||||
bra not $p1 #ctx_xfer_exec
|
||||
|
||||
ctx_xfer_pre_load:
|
||||
mov $r15 2
|
||||
call #ctx_4170s
|
||||
call #ctx_4170w
|
||||
call #ctx_redswitch
|
||||
clear b32 $r15
|
||||
call #ctx_4170s
|
||||
call #ctx_load
|
||||
|
||||
// fetch context pointer, and initiate xfer on all GPCs
|
||||
ctx_xfer_exec:
|
||||
ld b32 $r1 D[$r0 + #ctx_current]
|
||||
mov $r2 0x414
|
||||
shl b32 $r2 6
|
||||
iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
|
||||
mov $r14 -0x5b00
|
||||
sethi $r14 0x410000
|
||||
mov b32 $r15 $r1
|
||||
call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer
|
||||
add b32 $r14 4
|
||||
xbit $r15 $flags $p1
|
||||
xbit $r2 $flags $p2
|
||||
shl b32 $r2 1
|
||||
or $r15 $r2
|
||||
call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
|
||||
|
||||
// strands
|
||||
mov $r1 0x4afc
|
||||
sethi $r1 0x20000
|
||||
mov $r2 0xc
|
||||
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
|
||||
call #strand_wait
|
||||
mov $r2 0x47fc
|
||||
sethi $r2 0x20000
|
||||
iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
|
||||
xbit $r2 $flags $p1
|
||||
add b32 $r2 3
|
||||
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
|
||||
|
||||
// mmio context
|
||||
xbit $r10 $flags $p1 // direction
|
||||
or $r10 6 // first, last
|
||||
mov $r11 0 // base = 0
|
||||
ld b32 $r12 D[$r0 + #hub_mmio_list_head]
|
||||
ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
|
||||
mov $r14 0 // not multi
|
||||
call #mmctx_xfer
|
||||
|
||||
// wait for GPCs to all complete
|
||||
mov $r10 8 // DONE_BAR
|
||||
call #wait_doneo
|
||||
|
||||
// wait for strand xfer to complete
|
||||
call #strand_wait
|
||||
|
||||
// post-op
|
||||
bra $p1 #ctx_xfer_post
|
||||
mov $r10 12 // DONE_UNK12
|
||||
call #wait_donez
|
||||
mov $r1 0xa10
|
||||
shl b32 $r1 6
|
||||
mov $r2 5
|
||||
iowr I[$r1] $r2 // MEM_CMD
|
||||
ctx_xfer_post_save_wait:
|
||||
iord $r2 I[$r1]
|
||||
or $r2 $r2
|
||||
bra ne #ctx_xfer_post_save_wait
|
||||
|
||||
bra $p2 #ctx_xfer_done
|
||||
ctx_xfer_post:
|
||||
mov $r15 2
|
||||
call #ctx_4170s
|
||||
clear b32 $r15
|
||||
call #ctx_86c
|
||||
call #strand_post
|
||||
call #ctx_4170w
|
||||
clear b32 $r15
|
||||
call #ctx_4170s
|
||||
|
||||
bra not $p1 #ctx_xfer_no_post_mmio
|
||||
ld b32 $r1 D[$r0 + #chan_mmio_count]
|
||||
or $r1 $r1
|
||||
bra e #ctx_xfer_no_post_mmio
|
||||
call #ctx_mmio_exec
|
||||
|
||||
ctx_xfer_no_post_mmio:
|
||||
|
||||
ctx_xfer_done:
|
||||
ret
|
||||
|
||||
.align 256
|
|
@ -0,0 +1,857 @@
|
|||
uint32_t nve0_grhub_data[] = {
|
||||
/* 0x0000: gpc_count */
|
||||
0x00000000,
|
||||
/* 0x0004: rop_count */
|
||||
0x00000000,
|
||||
/* 0x0008: cmd_queue */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0050: hub_mmio_list_head */
|
||||
0x00000000,
|
||||
/* 0x0054: hub_mmio_list_tail */
|
||||
0x00000000,
|
||||
/* 0x0058: ctx_current */
|
||||
0x00000000,
|
||||
/* 0x005c: chipsets */
|
||||
0x000000e4,
|
||||
0x013c0070,
|
||||
0x000000e7,
|
||||
0x013c0070,
|
||||
0x00000000,
|
||||
/* 0x0070: nve4_hub_mmio_head */
|
||||
0x0417e91c,
|
||||
0x04400204,
|
||||
0x18404010,
|
||||
0x204040a8,
|
||||
0x184040d0,
|
||||
0x004040f8,
|
||||
0x08404130,
|
||||
0x08404150,
|
||||
0x00404164,
|
||||
0x0c4041a0,
|
||||
0x0c404200,
|
||||
0x34404404,
|
||||
0x0c404460,
|
||||
0x00404480,
|
||||
0x00404498,
|
||||
0x0c404604,
|
||||
0x0c404618,
|
||||
0x0440462c,
|
||||
0x00404640,
|
||||
0x00404654,
|
||||
0x00404660,
|
||||
0x48404678,
|
||||
0x084046c8,
|
||||
0x08404700,
|
||||
0x24404718,
|
||||
0x04404744,
|
||||
0x00404754,
|
||||
0x00405800,
|
||||
0x08405830,
|
||||
0x00405854,
|
||||
0x0c405870,
|
||||
0x04405a00,
|
||||
0x00405a18,
|
||||
0x00405b00,
|
||||
0x00405b10,
|
||||
0x00406020,
|
||||
0x0c406028,
|
||||
0x044064a8,
|
||||
0x044064b4,
|
||||
0x2c4064c0,
|
||||
0x004064fc,
|
||||
0x00407040,
|
||||
0x00407804,
|
||||
0x1440780c,
|
||||
0x004078bc,
|
||||
0x18408000,
|
||||
0x00408064,
|
||||
0x08408800,
|
||||
0x00408840,
|
||||
0x08408900,
|
||||
0x00408980,
|
||||
/* 0x013c: nve4_hub_mmio_tail */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0200: chan_data */
|
||||
/* 0x0200: chan_mmio_count */
|
||||
0x00000000,
|
||||
/* 0x0204: chan_mmio_address */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
/* 0x0300: xfer_data */
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
uint32_t nve0_grhub_code[] = {
|
||||
0x03090ef5,
|
||||
/* 0x0004: queue_put */
|
||||
0x9800d898,
|
||||
0x86f001d9,
|
||||
0x0489b808,
|
||||
0xf00c1bf4,
|
||||
0x21f502f7,
|
||||
0x00f802ec,
|
||||
/* 0x001c: queue_put_next */
|
||||
0xb60798c4,
|
||||
0x8dbb0384,
|
||||
0x0880b600,
|
||||
0x80008e80,
|
||||
0x90b6018f,
|
||||
0x0f94f001,
|
||||
0xf801d980,
|
||||
/* 0x0039: queue_get */
|
||||
0x0131f400,
|
||||
0x9800d898,
|
||||
0x89b801d9,
|
||||
0x210bf404,
|
||||
0xb60789c4,
|
||||
0x9dbb0394,
|
||||
0x0890b600,
|
||||
0x98009e98,
|
||||
0x80b6019f,
|
||||
0x0f84f001,
|
||||
0xf400d880,
|
||||
/* 0x0066: queue_get_done */
|
||||
0x00f80132,
|
||||
/* 0x0068: nv_rd32 */
|
||||
0x0728b7f1,
|
||||
0xb906b4b6,
|
||||
0xc9f002ec,
|
||||
0x00bcd01f,
|
||||
/* 0x0078: nv_rd32_wait */
|
||||
0xc800bccf,
|
||||
0x1bf41fcc,
|
||||
0x06a7f0fa,
|
||||
0x010321f5,
|
||||
0xf840bfcf,
|
||||
/* 0x008d: nv_wr32 */
|
||||
0x28b7f100,
|
||||
0x06b4b607,
|
||||
0xb980bfd0,
|
||||
0xc9f002ec,
|
||||
0x1ec9f01f,
|
||||
/* 0x00a3: nv_wr32_wait */
|
||||
0xcf00bcd0,
|
||||
0xccc800bc,
|
||||
0xfa1bf41f,
|
||||
/* 0x00ae: watchdog_reset */
|
||||
0x87f100f8,
|
||||
0x84b60430,
|
||||
0x1ff9f006,
|
||||
0xf8008fd0,
|
||||
/* 0x00bd: watchdog_clear */
|
||||
0x3087f100,
|
||||
0x0684b604,
|
||||
0xf80080d0,
|
||||
/* 0x00c9: wait_donez */
|
||||
0x3c87f100,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d000,
|
||||
0x081887f1,
|
||||
0xd00684b6,
|
||||
/* 0x00e2: wait_done_wait_donez */
|
||||
0x87f1008a,
|
||||
0x84b60400,
|
||||
0x0088cf06,
|
||||
0xf4888aff,
|
||||
0x87f1f31b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00099,
|
||||
/* 0x0103: wait_doneo */
|
||||
0xf100f800,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00099f0,
|
||||
0x87f10089,
|
||||
0x84b60818,
|
||||
0x008ad006,
|
||||
/* 0x011c: wait_done_wait_doneo */
|
||||
0x040087f1,
|
||||
0xcf0684b6,
|
||||
0x8aff0088,
|
||||
0xf30bf488,
|
||||
0x085c87f1,
|
||||
0xbd0684b6,
|
||||
0x0099f094,
|
||||
0xf80089d0,
|
||||
/* 0x013d: mmctx_size */
|
||||
/* 0x013f: nv_mmctx_size_loop */
|
||||
0x9894bd00,
|
||||
0x85b600e8,
|
||||
0x0180b61a,
|
||||
0xbb0284b6,
|
||||
0xe0b60098,
|
||||
0x04efb804,
|
||||
0xb9eb1bf4,
|
||||
0x00f8029f,
|
||||
/* 0x015c: mmctx_xfer */
|
||||
0x083c87f1,
|
||||
0xbd0684b6,
|
||||
0x0199f094,
|
||||
0xf10089d0,
|
||||
0xb6071087,
|
||||
0x94bd0684,
|
||||
0xf405bbfd,
|
||||
0x8bd0090b,
|
||||
0x0099f000,
|
||||
/* 0x0180: mmctx_base_disabled */
|
||||
0xf405eefd,
|
||||
0x8ed00c0b,
|
||||
0xc08fd080,
|
||||
/* 0x018f: mmctx_multi_disabled */
|
||||
0xb70199f0,
|
||||
0xc8010080,
|
||||
0xb4b600ab,
|
||||
0x0cb9f010,
|
||||
0xb601aec8,
|
||||
0xbefd11e4,
|
||||
0x008bd005,
|
||||
/* 0x01a8: mmctx_exec_loop */
|
||||
/* 0x01a8: mmctx_wait_free */
|
||||
0xf0008ecf,
|
||||
0x0bf41fe4,
|
||||
0x00ce98fa,
|
||||
0xd005e9fd,
|
||||
0xc0b6c08e,
|
||||
0x04cdb804,
|
||||
0xc8e81bf4,
|
||||
0x1bf402ab,
|
||||
/* 0x01c9: mmctx_fini_wait */
|
||||
0x008bcf18,
|
||||
0xb01fb4f0,
|
||||
0x1bf410b4,
|
||||
0x02a7f0f7,
|
||||
0xf4c921f4,
|
||||
/* 0x01de: mmctx_stop */
|
||||
0xabc81b0e,
|
||||
0x10b4b600,
|
||||
0xf00cb9f0,
|
||||
0x8bd012b9,
|
||||
/* 0x01ed: mmctx_stop_wait */
|
||||
0x008bcf00,
|
||||
0xf412bbc8,
|
||||
/* 0x01f6: mmctx_done */
|
||||
0x87f1fa1b,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00199,
|
||||
/* 0x0207: strand_wait */
|
||||
0xf900f800,
|
||||
0x02a7f0a0,
|
||||
0xfcc921f4,
|
||||
/* 0x0213: strand_pre */
|
||||
0xf100f8a0,
|
||||
0xf04afc87,
|
||||
0x97f00283,
|
||||
0x0089d00c,
|
||||
0x020721f5,
|
||||
/* 0x0226: strand_post */
|
||||
0x87f100f8,
|
||||
0x83f04afc,
|
||||
0x0d97f002,
|
||||
0xf50089d0,
|
||||
0xf8020721,
|
||||
/* 0x0239: strand_set */
|
||||
0xfca7f100,
|
||||
0x02a3f04f,
|
||||
0x0500aba2,
|
||||
0xd00fc7f0,
|
||||
0xc7f000ac,
|
||||
0x00bcd00b,
|
||||
0x020721f5,
|
||||
0xf000aed0,
|
||||
0xbcd00ac7,
|
||||
0x0721f500,
|
||||
/* 0x0263: strand_ctx_init */
|
||||
0xf100f802,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x21f50089,
|
||||
0xe7f00213,
|
||||
0x3921f503,
|
||||
0xfca7f102,
|
||||
0x02a3f046,
|
||||
0x0400aba0,
|
||||
0xf040a0d0,
|
||||
0xbcd001c7,
|
||||
0x0721f500,
|
||||
0x010c9202,
|
||||
0xf000acd0,
|
||||
0xbcd002c7,
|
||||
0x0721f500,
|
||||
0x2621f502,
|
||||
0x8087f102,
|
||||
0x0684b608,
|
||||
0xb70089cf,
|
||||
0x95220080,
|
||||
/* 0x02ba: ctx_init_strand_loop */
|
||||
0x8ed008fe,
|
||||
0x408ed000,
|
||||
0xb6808acf,
|
||||
0xa0b606a5,
|
||||
0x00eabb01,
|
||||
0xb60480b6,
|
||||
0x1bf40192,
|
||||
0x08e4b6e8,
|
||||
0xf1f2efbc,
|
||||
0xb6085c87,
|
||||
0x94bd0684,
|
||||
0xd00399f0,
|
||||
0x00f80089,
|
||||
/* 0x02ec: error */
|
||||
0xe7f1e0f9,
|
||||
0xe4b60814,
|
||||
0x00efd006,
|
||||
0x0c1ce7f1,
|
||||
0xf006e4b6,
|
||||
0xefd001f7,
|
||||
0xf8e0fc00,
|
||||
/* 0x0309: init */
|
||||
0xfe04bd00,
|
||||
0x07fe0004,
|
||||
0x0017f100,
|
||||
0x0227f012,
|
||||
0xf10012d0,
|
||||
0xfe05b917,
|
||||
0x17f10010,
|
||||
0x10d00400,
|
||||
0x0437f1c0,
|
||||
0x0634b604,
|
||||
0x200327f1,
|
||||
0xf10032d0,
|
||||
0xd0200427,
|
||||
0x27f10132,
|
||||
0x32d0200b,
|
||||
0x0c27f102,
|
||||
0x0732d020,
|
||||
0x0c2427f1,
|
||||
0xb90624b6,
|
||||
0x23d00003,
|
||||
0x0427f100,
|
||||
0x0023f087,
|
||||
0xb70012d0,
|
||||
0xf0010012,
|
||||
0x12d00427,
|
||||
0x1031f400,
|
||||
0x9604e7f1,
|
||||
0xf440e3f0,
|
||||
0xf1c76821,
|
||||
0x01018090,
|
||||
0x801ff4f0,
|
||||
0x17f0000f,
|
||||
0x041fbb01,
|
||||
0xf10112b6,
|
||||
0xb6040c27,
|
||||
0x21d00624,
|
||||
0x4021d000,
|
||||
0x080027f1,
|
||||
0xcf0624b6,
|
||||
0xf7f00022,
|
||||
/* 0x03a9: init_find_chipset */
|
||||
0x08f0b654,
|
||||
0xb800f398,
|
||||
0x0bf40432,
|
||||
0x0034b00b,
|
||||
0xf8f11bf4,
|
||||
/* 0x03bd: init_context */
|
||||
0x0017f100,
|
||||
0x02fe5801,
|
||||
0xf003ff58,
|
||||
0x0e8000e3,
|
||||
0x150f8014,
|
||||
0x013d21f5,
|
||||
0x070037f1,
|
||||
0x950634b6,
|
||||
0x34d00814,
|
||||
0x4034d000,
|
||||
0x130030b7,
|
||||
0xb6001fbb,
|
||||
0x3fd002f5,
|
||||
0x0815b600,
|
||||
0xb60110b6,
|
||||
0x1fb90814,
|
||||
0x6321f502,
|
||||
0x001fbb02,
|
||||
0xf1000398,
|
||||
0xf0200047,
|
||||
/* 0x040e: init_gpc */
|
||||
0x4ea05043,
|
||||
0x1fb90804,
|
||||
0x8d21f402,
|
||||
0x08004ea0,
|
||||
0xf4022fb9,
|
||||
0x4ea08d21,
|
||||
0xf4bd010c,
|
||||
0xa08d21f4,
|
||||
0xf401044e,
|
||||
0x4ea08d21,
|
||||
0xf7f00100,
|
||||
0x8d21f402,
|
||||
0x08004ea0,
|
||||
/* 0x0440: init_gpc_wait */
|
||||
0xc86821f4,
|
||||
0x0bf41fff,
|
||||
0x044ea0fa,
|
||||
0x6821f408,
|
||||
0xb7001fbb,
|
||||
0xb6800040,
|
||||
0x1bf40132,
|
||||
0x0027f1b4,
|
||||
0x0624b608,
|
||||
0xb74021d0,
|
||||
0xbd080020,
|
||||
0x1f19f014,
|
||||
/* 0x0473: main */
|
||||
0xf40021d0,
|
||||
0x28f40031,
|
||||
0x08d7f000,
|
||||
0xf43921f4,
|
||||
0xe4b1f401,
|
||||
0x1bf54001,
|
||||
0x87f100d1,
|
||||
0x84b6083c,
|
||||
0xf094bd06,
|
||||
0x89d00499,
|
||||
0x0017f100,
|
||||
0x0614b60b,
|
||||
0xcf4012cf,
|
||||
0x13c80011,
|
||||
0x7e0bf41f,
|
||||
0xf41f23c8,
|
||||
0x20f95a0b,
|
||||
0xf10212b9,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00799f0,
|
||||
0x32f40089,
|
||||
0x0231f401,
|
||||
0x07fb21f5,
|
||||
0x085c87f1,
|
||||
0xbd0684b6,
|
||||
0x0799f094,
|
||||
0xfc0089d0,
|
||||
0x3c87f120,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d006,
|
||||
0xf50131f4,
|
||||
0xf107fb21,
|
||||
0xb6085c87,
|
||||
0x94bd0684,
|
||||
0xd00699f0,
|
||||
0x0ef40089,
|
||||
/* 0x0509: chsw_prev_no_next */
|
||||
0xb920f931,
|
||||
0x32f40212,
|
||||
0x0232f401,
|
||||
0x07fb21f5,
|
||||
0x17f120fc,
|
||||
0x14b60b00,
|
||||
0x0012d006,
|
||||
/* 0x0527: chsw_no_prev */
|
||||
0xc8130ef4,
|
||||
0x0bf41f23,
|
||||
0x0131f40d,
|
||||
0xf50232f4,
|
||||
/* 0x0537: chsw_done */
|
||||
0xf107fb21,
|
||||
0xb60b0c17,
|
||||
0x27f00614,
|
||||
0x0012d001,
|
||||
0x085c87f1,
|
||||
0xbd0684b6,
|
||||
0x0499f094,
|
||||
0xf50089d0,
|
||||
/* 0x0557: main_not_ctx_switch */
|
||||
0xb0ff200e,
|
||||
0x1bf401e4,
|
||||
0x02f2b90d,
|
||||
0x078f21f5,
|
||||
/* 0x0567: main_not_ctx_chan */
|
||||
0xb0420ef4,
|
||||
0x1bf402e4,
|
||||
0x3c87f12e,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d007,
|
||||
0xf40132f4,
|
||||
0x21f50232,
|
||||
0x87f107fb,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00799,
|
||||
0x110ef400,
|
||||
/* 0x0598: main_not_ctx_save */
|
||||
0xf010ef94,
|
||||
0x21f501f5,
|
||||
0x0ef502ec,
|
||||
/* 0x05a6: main_done */
|
||||
0x17f1fed1,
|
||||
0x14b60820,
|
||||
0xf024bd06,
|
||||
0x12d01f29,
|
||||
0xbe0ef500,
|
||||
/* 0x05b9: ih */
|
||||
0xfe80f9fe,
|
||||
0x80f90188,
|
||||
0xa0f990f9,
|
||||
0xd0f9b0f9,
|
||||
0xf0f9e0f9,
|
||||
0xc4800acf,
|
||||
0x0bf404ab,
|
||||
0x00b7f11d,
|
||||
0x08d7f019,
|
||||
0xcf40becf,
|
||||
0x21f400bf,
|
||||
0x00b0b704,
|
||||
0x01e7f004,
|
||||
/* 0x05ef: ih_no_fifo */
|
||||
0xe400bed0,
|
||||
0xf40100ab,
|
||||
0xd7f00d0b,
|
||||
0x01e7f108,
|
||||
0x0421f440,
|
||||
/* 0x0600: ih_no_ctxsw */
|
||||
0x0104b7f1,
|
||||
0xabffb0bd,
|
||||
0x0d0bf4b4,
|
||||
0x0c1ca7f1,
|
||||
0xd006a4b6,
|
||||
/* 0x0616: ih_no_other */
|
||||
0x0ad000ab,
|
||||
0xfcf0fc40,
|
||||
0xfcd0fce0,
|
||||
0xfca0fcb0,
|
||||
0xfe80fc90,
|
||||
0x80fc0088,
|
||||
0xf80032f4,
|
||||
/* 0x0631: ctx_4170s */
|
||||
0x70e7f101,
|
||||
0x40e3f041,
|
||||
0xf410f5f0,
|
||||
0x00f88d21,
|
||||
/* 0x0640: ctx_4170w */
|
||||
0x4170e7f1,
|
||||
0xf440e3f0,
|
||||
0xf4f06821,
|
||||
0xf31bf410,
|
||||
/* 0x0652: ctx_redswitch */
|
||||
0xe7f100f8,
|
||||
0xe4b60614,
|
||||
0x70f7f106,
|
||||
0x00efd002,
|
||||
/* 0x0663: ctx_redswitch_delay */
|
||||
0xb608f7f0,
|
||||
0x1bf401f2,
|
||||
0x70f7f1fd,
|
||||
0x00efd007,
|
||||
/* 0x0672: ctx_86c */
|
||||
0xe7f100f8,
|
||||
0xe4b6086c,
|
||||
0x00efd006,
|
||||
0x8a14e7f1,
|
||||
0xf440e3f0,
|
||||
0xe7f18d21,
|
||||
0xe3f0a86c,
|
||||
0x8d21f441,
|
||||
/* 0x0692: ctx_load */
|
||||
0x87f100f8,
|
||||
0x84b6083c,
|
||||
0xf094bd06,
|
||||
0x89d00599,
|
||||
0x0ca7f000,
|
||||
0xf1c921f4,
|
||||
0xb60a2417,
|
||||
0x10d00614,
|
||||
0x0037f100,
|
||||
0x0634b60b,
|
||||
0xf14032d0,
|
||||
0xb60a0c17,
|
||||
0x47f00614,
|
||||
0x0012d007,
|
||||
/* 0x06cb: ctx_chan_wait_0 */
|
||||
0xcf4014d0,
|
||||
0x44f04014,
|
||||
0xfa1bf41f,
|
||||
0xfe0032d0,
|
||||
0x2af0000b,
|
||||
0x0424b61f,
|
||||
0xf10220b6,
|
||||
0xb6083c87,
|
||||
0x94bd0684,
|
||||
0xd00899f0,
|
||||
0x17f10089,
|
||||
0x14b60a04,
|
||||
0x0012d006,
|
||||
0x0a2017f1,
|
||||
0xf00614b6,
|
||||
0x23f10227,
|
||||
0x12d08000,
|
||||
0x1017f000,
|
||||
0x030027f1,
|
||||
0xfa0223f0,
|
||||
0x03f80512,
|
||||
0x085c87f1,
|
||||
0xbd0684b6,
|
||||
0x0899f094,
|
||||
0x980089d0,
|
||||
0x14b6c101,
|
||||
0xc0029818,
|
||||
0xfd0825b6,
|
||||
0x01800512,
|
||||
0x3c87f116,
|
||||
0x0684b608,
|
||||
0x99f094bd,
|
||||
0x0089d009,
|
||||
0x0a0427f1,
|
||||
0xd00624b6,
|
||||
0x27f00021,
|
||||
0x2017f101,
|
||||
0x0614b60a,
|
||||
0xf10012d0,
|
||||
0xf0020017,
|
||||
0x01fa0613,
|
||||
0xf103f805,
|
||||
0xb6085c87,
|
||||
0x94bd0684,
|
||||
0xd00999f0,
|
||||
0x87f10089,
|
||||
0x84b6085c,
|
||||
0xf094bd06,
|
||||
0x89d00599,
|
||||
/* 0x078f: ctx_chan */
|
||||
0xf500f800,
|
||||
0xf0069221,
|
||||
0x21f40ca7,
|
||||
0x1017f1c9,
|
||||
0x0614b60a,
|
||||
0xd00527f0,
|
||||
/* 0x07a6: ctx_chan_wait */
|
||||
0x12cf0012,
|
||||
0x0522fd00,
|
||||
0xf8fa1bf4,
|
||||
/* 0x07b1: ctx_mmio_exec */
|
||||
0x81039800,
|
||||
0x0a0427f1,
|
||||
0xd00624b6,
|
||||
0x34bd0023,
|
||||
/* 0x07c0: ctx_mmio_loop */
|
||||
0xf4ff34c4,
|
||||
0x57f10f1b,
|
||||
0x53f00300,
|
||||
0x0535fa06,
|
||||
/* 0x07d2: ctx_mmio_pull */
|
||||
0x4e9803f8,
|
||||
0xc14f98c0,
|
||||
0xb68d21f4,
|
||||
0x12b60830,
|
||||
0xdf1bf401,
|
||||
/* 0x07e4: ctx_mmio_done */
|
||||
0xd0160398,
|
||||
0x00800023,
|
||||
0x0017f180,
|
||||
0x0613f002,
|
||||
0xf80601fa,
|
||||
/* 0x07fb: ctx_xfer */
|
||||
0xf400f803,
|
||||
0x02f40611,
|
||||
/* 0x0801: ctx_xfer_pre */
|
||||
0x10f7f00d,
|
||||
0x067221f5,
|
||||
/* 0x080b: ctx_xfer_pre_load */
|
||||
0xf01c11f4,
|
||||
0x21f502f7,
|
||||
0x21f50631,
|
||||
0x21f50640,
|
||||
0xf4bd0652,
|
||||
0x063121f5,
|
||||
0x069221f5,
|
||||
/* 0x0824: ctx_xfer_exec */
|
||||
0xf1160198,
|
||||
0xb6041427,
|
||||
0x20d00624,
|
||||
0x00e7f100,
|
||||
0x41e3f0a5,
|
||||
0xf4021fb9,
|
||||
0xe0b68d21,
|
||||
0x01fcf004,
|
||||
0xb6022cf0,
|
||||
0xf2fd0124,
|
||||
0x8d21f405,
|
||||
0x4afc17f1,
|
||||
0xf00213f0,
|
||||
0x12d00c27,
|
||||
0x0721f500,
|
||||
0xfc27f102,
|
||||
0x0223f047,
|
||||
0xf00020d0,
|
||||
0x20b6012c,
|
||||
0x0012d003,
|
||||
0xf001acf0,
|
||||
0xb7f006a5,
|
||||
0x140c9800,
|
||||
0xf0150d98,
|
||||
0x21f500e7,
|
||||
0xa7f0015c,
|
||||
0x0321f508,
|
||||
0x0721f501,
|
||||
0x2201f402,
|
||||
0xf40ca7f0,
|
||||
0x17f1c921,
|
||||
0x14b60a10,
|
||||
0x0527f006,
|
||||
/* 0x08ab: ctx_xfer_post_save_wait */
|
||||
0xcf0012d0,
|
||||
0x22fd0012,
|
||||
0xfa1bf405,
|
||||
/* 0x08b7: ctx_xfer_post */
|
||||
0xf02e02f4,
|
||||
0x21f502f7,
|
||||
0xf4bd0631,
|
||||
0x067221f5,
|
||||
0x022621f5,
|
||||
0x064021f5,
|
||||
0x21f5f4bd,
|
||||
0x11f40631,
|
||||
0x80019810,
|
||||
0xf40511fd,
|
||||
0x21f5070b,
|
||||
/* 0x08e2: ctx_xfer_no_post_mmio */
|
||||
/* 0x08e2: ctx_xfer_done */
|
||||
0x00f807b1,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
};
|
|
@ -0,0 +1,400 @@
|
|||
/* fuc microcode util functions for nve0 PGRAPH
|
||||
*
|
||||
* Copyright 2011 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
|
||||
define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
|
||||
|
||||
ifdef(`include_code', `
|
||||
// Error codes
|
||||
define(`E_BAD_COMMAND', 0x01)
|
||||
define(`E_CMD_OVERFLOW', 0x02)
|
||||
|
||||
// Util macros to help with debugging ucode hangs etc
|
||||
define(`T_WAIT', 0)
|
||||
define(`T_MMCTX', 1)
|
||||
define(`T_STRWAIT', 2)
|
||||
define(`T_STRINIT', 3)
|
||||
define(`T_AUTO', 4)
|
||||
define(`T_CHAN', 5)
|
||||
define(`T_LOAD', 6)
|
||||
define(`T_SAVE', 7)
|
||||
define(`T_LCHAN', 8)
|
||||
define(`T_LCTXH', 9)
|
||||
|
||||
define(`trace_set', `
|
||||
mov $r8 0x83c
|
||||
shl b32 $r8 6
|
||||
clear b32 $r9
|
||||
bset $r9 $1
|
||||
iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
|
||||
')
|
||||
|
||||
define(`trace_clr', `
|
||||
mov $r8 0x85c
|
||||
shl b32 $r8 6
|
||||
clear b32 $r9
|
||||
bset $r9 $1
|
||||
iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
|
||||
')
|
||||
|
||||
// queue_put - add request to queue
|
||||
//
|
||||
// In : $r13 queue pointer
|
||||
// $r14 command
|
||||
// $r15 data
|
||||
//
|
||||
queue_put:
|
||||
// make sure we have space..
|
||||
ld b32 $r8 D[$r13 + 0x0] // GET
|
||||
ld b32 $r9 D[$r13 + 0x4] // PUT
|
||||
xor $r8 8
|
||||
cmpu b32 $r8 $r9
|
||||
bra ne #queue_put_next
|
||||
mov $r15 E_CMD_OVERFLOW
|
||||
call #error
|
||||
ret
|
||||
|
||||
// store cmd/data on queue
|
||||
queue_put_next:
|
||||
and $r8 $r9 7
|
||||
shl b32 $r8 3
|
||||
add b32 $r8 $r13
|
||||
add b32 $r8 8
|
||||
st b32 D[$r8 + 0x0] $r14
|
||||
st b32 D[$r8 + 0x4] $r15
|
||||
|
||||
// update PUT
|
||||
add b32 $r9 1
|
||||
and $r9 0xf
|
||||
st b32 D[$r13 + 0x4] $r9
|
||||
ret
|
||||
|
||||
// queue_get - fetch request from queue
|
||||
//
|
||||
// In : $r13 queue pointer
|
||||
//
|
||||
// Out: $p1 clear on success (data available)
|
||||
// $r14 command
|
||||
// $r15 data
|
||||
//
|
||||
queue_get:
|
||||
bset $flags $p1
|
||||
ld b32 $r8 D[$r13 + 0x0] // GET
|
||||
ld b32 $r9 D[$r13 + 0x4] // PUT
|
||||
cmpu b32 $r8 $r9
|
||||
bra e #queue_get_done
|
||||
// fetch first cmd/data pair
|
||||
and $r9 $r8 7
|
||||
shl b32 $r9 3
|
||||
add b32 $r9 $r13
|
||||
add b32 $r9 8
|
||||
ld b32 $r14 D[$r9 + 0x0]
|
||||
ld b32 $r15 D[$r9 + 0x4]
|
||||
|
||||
// update GET
|
||||
add b32 $r8 1
|
||||
and $r8 0xf
|
||||
st b32 D[$r13 + 0x0] $r8
|
||||
bclr $flags $p1
|
||||
queue_get_done:
|
||||
ret
|
||||
|
||||
// nv_rd32 - read 32-bit value from nv register
|
||||
//
|
||||
// In : $r14 register
|
||||
// Out: $r15 value
|
||||
//
|
||||
nv_rd32:
|
||||
mov $r11 0x728
|
||||
shl b32 $r11 6
|
||||
mov b32 $r12 $r14
|
||||
bset $r12 31 // MMIO_CTRL_PENDING
|
||||
iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
|
||||
nv_rd32_wait:
|
||||
iord $r12 I[$r11 + 0x000]
|
||||
xbit $r12 $r12 31
|
||||
bra ne #nv_rd32_wait
|
||||
mov $r10 6 // DONE_MMIO_RD
|
||||
call #wait_doneo
|
||||
iord $r15 I[$r11 + 0x100] // MMIO_RDVAL
|
||||
ret
|
||||
|
||||
// nv_wr32 - write 32-bit value to nv register
|
||||
//
|
||||
// In : $r14 register
|
||||
// $r15 value
|
||||
//
|
||||
nv_wr32:
|
||||
mov $r11 0x728
|
||||
shl b32 $r11 6
|
||||
iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL
|
||||
mov b32 $r12 $r14
|
||||
bset $r12 31 // MMIO_CTRL_PENDING
|
||||
bset $r12 30 // MMIO_CTRL_WRITE
|
||||
iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
|
||||
nv_wr32_wait:
|
||||
iord $r12 I[$r11 + 0x000]
|
||||
xbit $r12 $r12 31
|
||||
bra ne #nv_wr32_wait
|
||||
ret
|
||||
|
||||
// (re)set watchdog timer
|
||||
//
|
||||
// In : $r15 timeout
|
||||
//
|
||||
watchdog_reset:
|
||||
mov $r8 0x430
|
||||
shl b32 $r8 6
|
||||
bset $r15 31
|
||||
iowr I[$r8 + 0x000] $r15
|
||||
ret
|
||||
|
||||
// clear watchdog timer
|
||||
watchdog_clear:
|
||||
mov $r8 0x430
|
||||
shl b32 $r8 6
|
||||
iowr I[$r8 + 0x000] $r0
|
||||
ret
|
||||
|
||||
// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
|
||||
//
|
||||
// In : $r10 bit to wait on
|
||||
//
|
||||
define(`wait_done', `
|
||||
$1:
|
||||
trace_set(T_WAIT);
|
||||
mov $r8 0x818
|
||||
shl b32 $r8 6
|
||||
iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit
|
||||
wait_done_$1:
|
||||
mov $r8 0x400
|
||||
shl b32 $r8 6
|
||||
iord $r8 I[$r8 + 0x000] // DONE
|
||||
xbit $r8 $r8 $r10
|
||||
bra $2 #wait_done_$1
|
||||
trace_clr(T_WAIT)
|
||||
ret
|
||||
')
|
||||
wait_done(wait_donez, ne)
|
||||
wait_done(wait_doneo, e)
|
||||
|
||||
// mmctx_size - determine size of a mmio list transfer
|
||||
//
|
||||
// In : $r14 mmio list head
|
||||
// $r15 mmio list tail
|
||||
// Out: $r15 transfer size (in bytes)
|
||||
//
|
||||
mmctx_size:
|
||||
clear b32 $r9
|
||||
nv_mmctx_size_loop:
|
||||
ld b32 $r8 D[$r14]
|
||||
shr b32 $r8 26
|
||||
add b32 $r8 1
|
||||
shl b32 $r8 2
|
||||
add b32 $r9 $r8
|
||||
add b32 $r14 4
|
||||
cmpu b32 $r14 $r15
|
||||
bra ne #nv_mmctx_size_loop
|
||||
mov b32 $r15 $r9
|
||||
ret
|
||||
|
||||
// mmctx_xfer - execute a list of mmio transfers
|
||||
//
|
||||
// In : $r10 flags
|
||||
// bit 0: direction (0 = save, 1 = load)
|
||||
// bit 1: set if first transfer
|
||||
// bit 2: set if last transfer
|
||||
// $r11 base
|
||||
// $r12 mmio list head
|
||||
// $r13 mmio list tail
|
||||
// $r14 multi_stride
|
||||
// $r15 multi_mask
|
||||
//
|
||||
mmctx_xfer:
|
||||
trace_set(T_MMCTX)
|
||||
mov $r8 0x710
|
||||
shl b32 $r8 6
|
||||
clear b32 $r9
|
||||
or $r11 $r11
|
||||
bra e #mmctx_base_disabled
|
||||
iowr I[$r8 + 0x000] $r11 // MMCTX_BASE
|
||||
bset $r9 0 // BASE_EN
|
||||
mmctx_base_disabled:
|
||||
or $r14 $r14
|
||||
bra e #mmctx_multi_disabled
|
||||
iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE
|
||||
iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK
|
||||
bset $r9 1 // MULTI_EN
|
||||
mmctx_multi_disabled:
|
||||
add b32 $r8 0x100
|
||||
|
||||
xbit $r11 $r10 0
|
||||
shl b32 $r11 16 // DIR
|
||||
bset $r11 12 // QLIMIT = 0x10
|
||||
xbit $r14 $r10 1
|
||||
shl b32 $r14 17
|
||||
or $r11 $r14 // START_TRIGGER
|
||||
iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
|
||||
|
||||
// loop over the mmio list, and send requests to the hw
|
||||
mmctx_exec_loop:
|
||||
// wait for space in mmctx queue
|
||||
mmctx_wait_free:
|
||||
iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
|
||||
and $r14 0x1f
|
||||
bra e #mmctx_wait_free
|
||||
|
||||
// queue up an entry
|
||||
ld b32 $r14 D[$r12]
|
||||
or $r14 $r9
|
||||
iowr I[$r8 + 0x300] $r14
|
||||
add b32 $r12 4
|
||||
cmpu b32 $r12 $r13
|
||||
bra ne #mmctx_exec_loop
|
||||
|
||||
xbit $r11 $r10 2
|
||||
bra ne #mmctx_stop
|
||||
// wait for queue to empty
|
||||
mmctx_fini_wait:
|
||||
iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
|
||||
and $r11 0x1f
|
||||
cmpu b32 $r11 0x10
|
||||
bra ne #mmctx_fini_wait
|
||||
mov $r10 2 // DONE_MMCTX
|
||||
call #wait_donez
|
||||
bra #mmctx_done
|
||||
mmctx_stop:
|
||||
xbit $r11 $r10 0
|
||||
shl b32 $r11 16 // DIR
|
||||
bset $r11 12 // QLIMIT = 0x10
|
||||
bset $r11 18 // STOP_TRIGGER
|
||||
iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
|
||||
mmctx_stop_wait:
|
||||
// wait for STOP_TRIGGER to clear
|
||||
iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
|
||||
xbit $r11 $r11 18
|
||||
bra ne #mmctx_stop_wait
|
||||
mmctx_done:
|
||||
trace_clr(T_MMCTX)
|
||||
ret
|
||||
|
||||
// Wait for DONE_STRAND
|
||||
//
|
||||
strand_wait:
|
||||
push $r10
|
||||
mov $r10 2
|
||||
call #wait_donez
|
||||
pop $r10
|
||||
ret
|
||||
|
||||
// unknown - call before issuing strand commands
|
||||
//
|
||||
strand_pre:
|
||||
mov $r8 0x4afc
|
||||
sethi $r8 0x20000
|
||||
mov $r9 0xc
|
||||
iowr I[$r8] $r9
|
||||
call #strand_wait
|
||||
ret
|
||||
|
||||
// unknown - call after issuing strand commands
|
||||
//
|
||||
strand_post:
|
||||
mov $r8 0x4afc
|
||||
sethi $r8 0x20000
|
||||
mov $r9 0xd
|
||||
iowr I[$r8] $r9
|
||||
call #strand_wait
|
||||
ret
|
||||
|
||||
// Selects strand set?!
|
||||
//
|
||||
// In: $r14 id
|
||||
//
|
||||
strand_set:
|
||||
mov $r10 0x4ffc
|
||||
sethi $r10 0x20000
|
||||
sub b32 $r11 $r10 0x500
|
||||
mov $r12 0xf
|
||||
iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf
|
||||
mov $r12 0xb
|
||||
iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb
|
||||
call #strand_wait
|
||||
iowr I[$r10 + 0x000] $r14 // 0x93c = <id>
|
||||
mov $r12 0xa
|
||||
iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa
|
||||
call #strand_wait
|
||||
ret
|
||||
|
||||
// Initialise strand context data
|
||||
//
|
||||
// In : $r15 context base
|
||||
// Out: $r15 context size (in bytes)
|
||||
//
|
||||
// Strandset(?) 3 hardcoded currently
|
||||
//
|
||||
strand_ctx_init:
|
||||
trace_set(T_STRINIT)
|
||||
call #strand_pre
|
||||
mov $r14 3
|
||||
call #strand_set
|
||||
mov $r10 0x46fc
|
||||
sethi $r10 0x20000
|
||||
add b32 $r11 $r10 0x400
|
||||
iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0
|
||||
mov $r12 1
|
||||
iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE
|
||||
call #strand_wait
|
||||
sub b32 $r12 $r0 1
|
||||
iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff
|
||||
mov $r12 2
|
||||
iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT
|
||||
call #strand_wait
|
||||
call #strand_post
|
||||
|
||||
// read the size of each strand, poke the context offset of
|
||||
// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
|
||||
// about it later then.
|
||||
mov $r8 0x880
|
||||
shl b32 $r8 6
|
||||
iord $r9 I[$r8 + 0x000] // STRANDS
|
||||
add b32 $r8 0x2200
|
||||
shr b32 $r14 $r15 8
|
||||
ctx_init_strand_loop:
|
||||
iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE
|
||||
iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE
|
||||
iord $r10 I[$r8 + 0x200] // STRAND_SIZE
|
||||
shr b32 $r10 6
|
||||
add b32 $r10 1
|
||||
add b32 $r14 $r10
|
||||
add b32 $r8 4
|
||||
sub b32 $r9 1
|
||||
bra ne #ctx_init_strand_loop
|
||||
|
||||
shl b32 $r14 8
|
||||
sub b32 $r15 $r14 $r15
|
||||
trace_clr(T_STRINIT)
|
||||
ret
|
||||
')
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,381 @@
|
|||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
#include "nv20.h"
|
||||
#include "regs.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Graphics object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv20_graph_sclass[] = {
|
||||
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
|
||||
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
|
||||
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
|
||||
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
|
||||
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
|
||||
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
|
||||
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
|
||||
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
|
||||
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
|
||||
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
|
||||
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
|
||||
{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
|
||||
{ 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */
|
||||
{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
|
||||
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv20_graph_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_chan *chan;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
|
||||
0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC,
|
||||
&chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan->chid = nouveau_fifo_chan(parent)->chid;
|
||||
|
||||
nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
|
||||
nv_wo32(chan, 0x033c, 0xffff0000);
|
||||
nv_wo32(chan, 0x03a0, 0x0fff0000);
|
||||
nv_wo32(chan, 0x03a4, 0x0fff0000);
|
||||
nv_wo32(chan, 0x047c, 0x00000101);
|
||||
nv_wo32(chan, 0x0490, 0x00000111);
|
||||
nv_wo32(chan, 0x04a8, 0x44400000);
|
||||
for (i = 0x04d4; i <= 0x04e0; i += 4)
|
||||
nv_wo32(chan, i, 0x00030303);
|
||||
for (i = 0x04f4; i <= 0x0500; i += 4)
|
||||
nv_wo32(chan, i, 0x00080000);
|
||||
for (i = 0x050c; i <= 0x0518; i += 4)
|
||||
nv_wo32(chan, i, 0x01012000);
|
||||
for (i = 0x051c; i <= 0x0528; i += 4)
|
||||
nv_wo32(chan, i, 0x000105b8);
|
||||
for (i = 0x052c; i <= 0x0538; i += 4)
|
||||
nv_wo32(chan, i, 0x00080008);
|
||||
for (i = 0x055c; i <= 0x0598; i += 4)
|
||||
nv_wo32(chan, i, 0x07ff0000);
|
||||
nv_wo32(chan, 0x05a4, 0x4b7fffff);
|
||||
nv_wo32(chan, 0x05fc, 0x00000001);
|
||||
nv_wo32(chan, 0x0604, 0x00004000);
|
||||
nv_wo32(chan, 0x0610, 0x00000001);
|
||||
nv_wo32(chan, 0x0618, 0x00040000);
|
||||
nv_wo32(chan, 0x061c, 0x00010000);
|
||||
for (i = 0x1c1c; i <= 0x248c; i += 16) {
|
||||
nv_wo32(chan, (i + 0), 0x10700ff9);
|
||||
nv_wo32(chan, (i + 4), 0x0436086c);
|
||||
nv_wo32(chan, (i + 8), 0x000c001b);
|
||||
}
|
||||
nv_wo32(chan, 0x281c, 0x3f800000);
|
||||
nv_wo32(chan, 0x2830, 0x3f800000);
|
||||
nv_wo32(chan, 0x285c, 0x40000000);
|
||||
nv_wo32(chan, 0x2860, 0x3f800000);
|
||||
nv_wo32(chan, 0x2864, 0x3f000000);
|
||||
nv_wo32(chan, 0x286c, 0x40000000);
|
||||
nv_wo32(chan, 0x2870, 0x3f800000);
|
||||
nv_wo32(chan, 0x2878, 0xbf800000);
|
||||
nv_wo32(chan, 0x2880, 0xbf800000);
|
||||
nv_wo32(chan, 0x34a4, 0x000fe000);
|
||||
nv_wo32(chan, 0x3530, 0x000003f8);
|
||||
nv_wo32(chan, 0x3540, 0x002fe000);
|
||||
for (i = 0x355c; i <= 0x3578; i += 4)
|
||||
nv_wo32(chan, i, 0x001c527c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv20_graph_context_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv20_graph_priv *priv = (void *)object->engine;
|
||||
struct nv20_graph_chan *chan = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_context_init(&chan->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv20_graph_context_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv20_graph_priv *priv = (void *)object->engine;
|
||||
struct nv20_graph_chan *chan = (void *)object;
|
||||
int chid = -1;
|
||||
|
||||
nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
|
||||
if (nv_rd32(priv, 0x400144) & 0x00010000)
|
||||
chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
|
||||
if (chan->chid == chid) {
|
||||
nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
|
||||
nv_wr32(priv, 0x400788, 0x00000002);
|
||||
nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
|
||||
nv_wr32(priv, 0x400144, 0x10000000);
|
||||
nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
|
||||
}
|
||||
nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
|
||||
|
||||
nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
|
||||
return nouveau_graph_context_fini(&chan->base, suspend);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv20_graph_cclass = {
|
||||
.handle = NV_ENGCTX(GR, 0x20),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv20_graph_context_ctor,
|
||||
.dtor = _nouveau_graph_context_dtor,
|
||||
.init = nv20_graph_context_init,
|
||||
.fini = nv20_graph_context_fini,
|
||||
.rd32 = _nouveau_graph_context_rd32,
|
||||
.wr32 = _nouveau_graph_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
|
||||
{
|
||||
struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(engine);
|
||||
struct nv20_graph_priv *priv = (void *)engine;
|
||||
unsigned long flags;
|
||||
|
||||
pfifo->pause(pfifo, &flags);
|
||||
nv04_graph_idle(priv);
|
||||
|
||||
nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
|
||||
nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
|
||||
nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
|
||||
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
|
||||
|
||||
if (nv_device(engine)->card_type == NV_20) {
|
||||
nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
|
||||
}
|
||||
|
||||
pfifo->start(pfifo, &flags);
|
||||
}
|
||||
|
||||
void
|
||||
nv20_graph_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_engine *engine = nv_engine(subdev);
|
||||
struct nouveau_object *engctx;
|
||||
struct nouveau_handle *handle;
|
||||
struct nv20_graph_priv *priv = (void *)subdev;
|
||||
u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
|
||||
u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
|
||||
u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
|
||||
u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
|
||||
u32 chid = (addr & 0x01f00000) >> 20;
|
||||
u32 subc = (addr & 0x00070000) >> 16;
|
||||
u32 mthd = (addr & 0x00001ffc);
|
||||
u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
|
||||
u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
|
||||
u32 show = stat;
|
||||
|
||||
engctx = nouveau_engctx_get(engine, chid);
|
||||
if (stat & NV_PGRAPH_INTR_ERROR) {
|
||||
if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
|
||||
handle = nouveau_handle_get_class(engctx, class);
|
||||
if (handle && !nv_call(handle->object, mthd, data))
|
||||
show &= ~NV_PGRAPH_INTR_ERROR;
|
||||
nouveau_handle_put(handle);
|
||||
}
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV03_PGRAPH_INTR, stat);
|
||||
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_info(priv, "");
|
||||
nouveau_bitfield_print(nv10_graph_intr_name, show);
|
||||
printk(" nsource:");
|
||||
nouveau_bitfield_print(nv04_graph_nsource, nsource);
|
||||
printk(" nstatus:");
|
||||
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
|
||||
printk("\n");
|
||||
nv_info(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, subc, class, mthd, data);
|
||||
}
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00001000;
|
||||
nv_subdev(priv)->intr = nv20_graph_intr;
|
||||
nv_engine(priv)->cclass = &nv20_graph_cclass;
|
||||
nv_engine(priv)->sclass = nv20_graph_sclass;
|
||||
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv20_graph_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nv20_graph_priv *priv = (void *)object;
|
||||
nouveau_gpuobj_ref(NULL, &priv->ctxtab);
|
||||
nouveau_graph_destroy(&priv->base);
|
||||
}
|
||||
|
||||
int
|
||||
nv20_graph_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_engine *engine = nv_engine(object);
|
||||
struct nv20_graph_priv *priv = (void *)engine;
|
||||
struct nouveau_fb *pfb = nouveau_fb(object);
|
||||
u32 tmp, vramsz;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
|
||||
|
||||
if (nv_device(priv)->chipset == 0x20) {
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
|
||||
for (i = 0; i < 15; i++)
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
|
||||
nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
|
||||
} else {
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
|
||||
for (i = 0; i < 32; i++)
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
|
||||
nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
|
||||
nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
|
||||
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
|
||||
nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
|
||||
nv_wr32(priv, 0x40009C , 0x00000040);
|
||||
|
||||
if (nv_device(priv)->chipset >= 0x25) {
|
||||
nv_wr32(priv, 0x400890, 0x00a8cfff);
|
||||
nv_wr32(priv, 0x400610, 0x304B1FB6);
|
||||
nv_wr32(priv, 0x400B80, 0x1cbd3883);
|
||||
nv_wr32(priv, 0x400B84, 0x44000000);
|
||||
nv_wr32(priv, 0x400098, 0x40000080);
|
||||
nv_wr32(priv, 0x400B88, 0x000000ff);
|
||||
|
||||
} else {
|
||||
nv_wr32(priv, 0x400880, 0x0008c7df);
|
||||
nv_wr32(priv, 0x400094, 0x00000005);
|
||||
nv_wr32(priv, 0x400B80, 0x45eae20e);
|
||||
nv_wr32(priv, 0x400B84, 0x24000000);
|
||||
nv_wr32(priv, 0x400098, 0x00000040);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
|
||||
}
|
||||
|
||||
/* Turn all the tiling regions off. */
|
||||
for (i = 0; i < pfb->tile.regions; i++)
|
||||
engine->tile_prog(engine, i);
|
||||
|
||||
nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
|
||||
|
||||
nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
|
||||
nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
|
||||
|
||||
tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
|
||||
nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
|
||||
tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
|
||||
nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
|
||||
|
||||
/* begin RAM config */
|
||||
vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
|
||||
nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
|
||||
nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
|
||||
nv_wr32(priv, 0x400820, 0);
|
||||
nv_wr32(priv, 0x400824, 0);
|
||||
nv_wr32(priv, 0x400864, vramsz - 1);
|
||||
nv_wr32(priv, 0x400868, vramsz - 1);
|
||||
|
||||
/* interesting.. the below overwrites some of the tile setup above.. */
|
||||
nv_wr32(priv, 0x400B20, 0x00000000);
|
||||
nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
|
||||
|
||||
nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
|
||||
nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
|
||||
nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
|
||||
nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv20_graph_oclass = {
|
||||
.handle = NV_ENGINE(GR, 0x20),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv20_graph_ctor,
|
||||
.dtor = nv20_graph_dtor,
|
||||
.init = nv20_graph_init,
|
||||
.fini = _nouveau_graph_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef __NV20_GRAPH_H__
|
||||
#define __NV20_GRAPH_H__
|
||||
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
struct nv20_graph_priv {
|
||||
struct nouveau_graph base;
|
||||
struct nouveau_gpuobj *ctxtab;
|
||||
};
|
||||
|
||||
struct nv20_graph_chan {
|
||||
struct nouveau_graph_chan base;
|
||||
int chid;
|
||||
};
|
||||
|
||||
extern struct nouveau_oclass nv25_graph_sclass[];
|
||||
int nv20_graph_context_init(struct nouveau_object *);
|
||||
int nv20_graph_context_fini(struct nouveau_object *, bool);
|
||||
|
||||
void nv20_graph_tile_prog(struct nouveau_engine *, int);
|
||||
void nv20_graph_intr(struct nouveau_subdev *);
|
||||
|
||||
void nv20_graph_dtor(struct nouveau_object *);
|
||||
int nv20_graph_init(struct nouveau_object *);
|
||||
|
||||
int nv30_graph_init(struct nouveau_object *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,167 @@
|
|||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
|
||||
#include "nv20.h"
|
||||
#include "regs.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Graphics object classes
|
||||
******************************************************************************/
|
||||
|
||||
struct nouveau_oclass
|
||||
nv25_graph_sclass[] = {
|
||||
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
|
||||
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
|
||||
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
|
||||
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
|
||||
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
|
||||
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
|
||||
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
|
||||
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
|
||||
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
|
||||
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
|
||||
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
|
||||
{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
|
||||
{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
|
||||
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
|
||||
{ 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv25_graph_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_chan *chan;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
|
||||
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan->chid = nouveau_fifo_chan(parent)->chid;
|
||||
|
||||
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
|
||||
nv_wo32(chan, 0x035c, 0xffff0000);
|
||||
nv_wo32(chan, 0x03c0, 0x0fff0000);
|
||||
nv_wo32(chan, 0x03c4, 0x0fff0000);
|
||||
nv_wo32(chan, 0x049c, 0x00000101);
|
||||
nv_wo32(chan, 0x04b0, 0x00000111);
|
||||
nv_wo32(chan, 0x04c8, 0x00000080);
|
||||
nv_wo32(chan, 0x04cc, 0xffff0000);
|
||||
nv_wo32(chan, 0x04d0, 0x00000001);
|
||||
nv_wo32(chan, 0x04e4, 0x44400000);
|
||||
nv_wo32(chan, 0x04fc, 0x4b800000);
|
||||
for (i = 0x0510; i <= 0x051c; i += 4)
|
||||
nv_wo32(chan, i, 0x00030303);
|
||||
for (i = 0x0530; i <= 0x053c; i += 4)
|
||||
nv_wo32(chan, i, 0x00080000);
|
||||
for (i = 0x0548; i <= 0x0554; i += 4)
|
||||
nv_wo32(chan, i, 0x01012000);
|
||||
for (i = 0x0558; i <= 0x0564; i += 4)
|
||||
nv_wo32(chan, i, 0x000105b8);
|
||||
for (i = 0x0568; i <= 0x0574; i += 4)
|
||||
nv_wo32(chan, i, 0x00080008);
|
||||
for (i = 0x0598; i <= 0x05d4; i += 4)
|
||||
nv_wo32(chan, i, 0x07ff0000);
|
||||
nv_wo32(chan, 0x05e0, 0x4b7fffff);
|
||||
nv_wo32(chan, 0x0620, 0x00000080);
|
||||
nv_wo32(chan, 0x0624, 0x30201000);
|
||||
nv_wo32(chan, 0x0628, 0x70605040);
|
||||
nv_wo32(chan, 0x062c, 0xb0a09080);
|
||||
nv_wo32(chan, 0x0630, 0xf0e0d0c0);
|
||||
nv_wo32(chan, 0x0664, 0x00000001);
|
||||
nv_wo32(chan, 0x066c, 0x00004000);
|
||||
nv_wo32(chan, 0x0678, 0x00000001);
|
||||
nv_wo32(chan, 0x0680, 0x00040000);
|
||||
nv_wo32(chan, 0x0684, 0x00010000);
|
||||
for (i = 0x1b04; i <= 0x2374; i += 16) {
|
||||
nv_wo32(chan, (i + 0), 0x10700ff9);
|
||||
nv_wo32(chan, (i + 4), 0x0436086c);
|
||||
nv_wo32(chan, (i + 8), 0x000c001b);
|
||||
}
|
||||
nv_wo32(chan, 0x2704, 0x3f800000);
|
||||
nv_wo32(chan, 0x2718, 0x3f800000);
|
||||
nv_wo32(chan, 0x2744, 0x40000000);
|
||||
nv_wo32(chan, 0x2748, 0x3f800000);
|
||||
nv_wo32(chan, 0x274c, 0x3f000000);
|
||||
nv_wo32(chan, 0x2754, 0x40000000);
|
||||
nv_wo32(chan, 0x2758, 0x3f800000);
|
||||
nv_wo32(chan, 0x2760, 0xbf800000);
|
||||
nv_wo32(chan, 0x2768, 0xbf800000);
|
||||
nv_wo32(chan, 0x308c, 0x000fe000);
|
||||
nv_wo32(chan, 0x3108, 0x000003f8);
|
||||
nv_wo32(chan, 0x3468, 0x002fe000);
|
||||
for (i = 0x3484; i <= 0x34a0; i += 4)
|
||||
nv_wo32(chan, i, 0x001c527c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv25_graph_cclass = {
|
||||
.handle = NV_ENGCTX(GR, 0x25),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv25_graph_context_ctor,
|
||||
.dtor = _nouveau_graph_context_dtor,
|
||||
.init = nv20_graph_context_init,
|
||||
.fini = nv20_graph_context_fini,
|
||||
.rd32 = _nouveau_graph_context_rd32,
|
||||
.wr32 = _nouveau_graph_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00001000;
|
||||
nv_subdev(priv)->intr = nv20_graph_intr;
|
||||
nv_engine(priv)->cclass = &nv25_graph_cclass;
|
||||
nv_engine(priv)->sclass = nv25_graph_sclass;
|
||||
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv25_graph_oclass = {
|
||||
.handle = NV_ENGINE(GR, 0x25),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv25_graph_ctor,
|
||||
.dtor = nv20_graph_dtor,
|
||||
.init = nv20_graph_init,
|
||||
.fini = _nouveau_graph_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,134 @@
|
|||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
|
||||
#include "nv20.h"
|
||||
#include "regs.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv2a_graph_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_chan *chan;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
|
||||
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan->chid = nouveau_fifo_chan(parent)->chid;
|
||||
|
||||
nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
|
||||
nv_wo32(chan, 0x033c, 0xffff0000);
|
||||
nv_wo32(chan, 0x03a0, 0x0fff0000);
|
||||
nv_wo32(chan, 0x03a4, 0x0fff0000);
|
||||
nv_wo32(chan, 0x047c, 0x00000101);
|
||||
nv_wo32(chan, 0x0490, 0x00000111);
|
||||
nv_wo32(chan, 0x04a8, 0x44400000);
|
||||
for (i = 0x04d4; i <= 0x04e0; i += 4)
|
||||
nv_wo32(chan, i, 0x00030303);
|
||||
for (i = 0x04f4; i <= 0x0500; i += 4)
|
||||
nv_wo32(chan, i, 0x00080000);
|
||||
for (i = 0x050c; i <= 0x0518; i += 4)
|
||||
nv_wo32(chan, i, 0x01012000);
|
||||
for (i = 0x051c; i <= 0x0528; i += 4)
|
||||
nv_wo32(chan, i, 0x000105b8);
|
||||
for (i = 0x052c; i <= 0x0538; i += 4)
|
||||
nv_wo32(chan, i, 0x00080008);
|
||||
for (i = 0x055c; i <= 0x0598; i += 4)
|
||||
nv_wo32(chan, i, 0x07ff0000);
|
||||
nv_wo32(chan, 0x05a4, 0x4b7fffff);
|
||||
nv_wo32(chan, 0x05fc, 0x00000001);
|
||||
nv_wo32(chan, 0x0604, 0x00004000);
|
||||
nv_wo32(chan, 0x0610, 0x00000001);
|
||||
nv_wo32(chan, 0x0618, 0x00040000);
|
||||
nv_wo32(chan, 0x061c, 0x00010000);
|
||||
for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
|
||||
nv_wo32(chan, (i + 0), 0x10700ff9);
|
||||
nv_wo32(chan, (i + 4), 0x0436086c);
|
||||
nv_wo32(chan, (i + 8), 0x000c001b);
|
||||
}
|
||||
nv_wo32(chan, 0x269c, 0x3f800000);
|
||||
nv_wo32(chan, 0x26b0, 0x3f800000);
|
||||
nv_wo32(chan, 0x26dc, 0x40000000);
|
||||
nv_wo32(chan, 0x26e0, 0x3f800000);
|
||||
nv_wo32(chan, 0x26e4, 0x3f000000);
|
||||
nv_wo32(chan, 0x26ec, 0x40000000);
|
||||
nv_wo32(chan, 0x26f0, 0x3f800000);
|
||||
nv_wo32(chan, 0x26f8, 0xbf800000);
|
||||
nv_wo32(chan, 0x2700, 0xbf800000);
|
||||
nv_wo32(chan, 0x3024, 0x000fe000);
|
||||
nv_wo32(chan, 0x30a0, 0x000003f8);
|
||||
nv_wo32(chan, 0x33fc, 0x002fe000);
|
||||
for (i = 0x341c; i <= 0x3438; i += 4)
|
||||
nv_wo32(chan, i, 0x001c527c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv2a_graph_cclass = {
|
||||
.handle = NV_ENGCTX(GR, 0x2a),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv2a_graph_context_ctor,
|
||||
.dtor = _nouveau_graph_context_dtor,
|
||||
.init = nv20_graph_context_init,
|
||||
.fini = nv20_graph_context_fini,
|
||||
.rd32 = _nouveau_graph_context_rd32,
|
||||
.wr32 = _nouveau_graph_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00001000;
|
||||
nv_subdev(priv)->intr = nv20_graph_intr;
|
||||
nv_engine(priv)->cclass = &nv2a_graph_cclass;
|
||||
nv_engine(priv)->sclass = nv25_graph_sclass;
|
||||
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv2a_graph_oclass = {
|
||||
.handle = NV_ENGINE(GR, 0x2a),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv2a_graph_ctor,
|
||||
.dtor = nv20_graph_dtor,
|
||||
.init = nv20_graph_init,
|
||||
.fini = _nouveau_graph_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,238 @@
|
|||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
|
||||
#include "nv20.h"
|
||||
#include "regs.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Graphics object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv30_graph_sclass[] = {
|
||||
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
|
||||
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
|
||||
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
|
||||
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
|
||||
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
|
||||
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
|
||||
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
|
||||
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
|
||||
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
|
||||
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
|
||||
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
|
||||
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
|
||||
{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
|
||||
{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
|
||||
{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
|
||||
{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
|
||||
{ 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv30_graph_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_chan *chan;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
|
||||
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan->chid = nouveau_fifo_chan(parent)->chid;
|
||||
|
||||
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
|
||||
nv_wo32(chan, 0x0410, 0x00000101);
|
||||
nv_wo32(chan, 0x0424, 0x00000111);
|
||||
nv_wo32(chan, 0x0428, 0x00000060);
|
||||
nv_wo32(chan, 0x0444, 0x00000080);
|
||||
nv_wo32(chan, 0x0448, 0xffff0000);
|
||||
nv_wo32(chan, 0x044c, 0x00000001);
|
||||
nv_wo32(chan, 0x0460, 0x44400000);
|
||||
nv_wo32(chan, 0x048c, 0xffff0000);
|
||||
for (i = 0x04e0; i < 0x04e8; i += 4)
|
||||
nv_wo32(chan, i, 0x0fff0000);
|
||||
nv_wo32(chan, 0x04ec, 0x00011100);
|
||||
for (i = 0x0508; i < 0x0548; i += 4)
|
||||
nv_wo32(chan, i, 0x07ff0000);
|
||||
nv_wo32(chan, 0x0550, 0x4b7fffff);
|
||||
nv_wo32(chan, 0x058c, 0x00000080);
|
||||
nv_wo32(chan, 0x0590, 0x30201000);
|
||||
nv_wo32(chan, 0x0594, 0x70605040);
|
||||
nv_wo32(chan, 0x0598, 0xb8a89888);
|
||||
nv_wo32(chan, 0x059c, 0xf8e8d8c8);
|
||||
nv_wo32(chan, 0x05b0, 0xb0000000);
|
||||
for (i = 0x0600; i < 0x0640; i += 4)
|
||||
nv_wo32(chan, i, 0x00010588);
|
||||
for (i = 0x0640; i < 0x0680; i += 4)
|
||||
nv_wo32(chan, i, 0x00030303);
|
||||
for (i = 0x06c0; i < 0x0700; i += 4)
|
||||
nv_wo32(chan, i, 0x0008aae4);
|
||||
for (i = 0x0700; i < 0x0740; i += 4)
|
||||
nv_wo32(chan, i, 0x01012000);
|
||||
for (i = 0x0740; i < 0x0780; i += 4)
|
||||
nv_wo32(chan, i, 0x00080008);
|
||||
nv_wo32(chan, 0x085c, 0x00040000);
|
||||
nv_wo32(chan, 0x0860, 0x00010000);
|
||||
for (i = 0x0864; i < 0x0874; i += 4)
|
||||
nv_wo32(chan, i, 0x00040004);
|
||||
for (i = 0x1f18; i <= 0x3088 ; i += 16) {
|
||||
nv_wo32(chan, i + 0, 0x10700ff9);
|
||||
nv_wo32(chan, i + 1, 0x0436086c);
|
||||
nv_wo32(chan, i + 2, 0x000c001b);
|
||||
}
|
||||
for (i = 0x30b8; i < 0x30c8; i += 4)
|
||||
nv_wo32(chan, i, 0x0000ffff);
|
||||
nv_wo32(chan, 0x344c, 0x3f800000);
|
||||
nv_wo32(chan, 0x3808, 0x3f800000);
|
||||
nv_wo32(chan, 0x381c, 0x3f800000);
|
||||
nv_wo32(chan, 0x3848, 0x40000000);
|
||||
nv_wo32(chan, 0x384c, 0x3f800000);
|
||||
nv_wo32(chan, 0x3850, 0x3f000000);
|
||||
nv_wo32(chan, 0x3858, 0x40000000);
|
||||
nv_wo32(chan, 0x385c, 0x3f800000);
|
||||
nv_wo32(chan, 0x3864, 0xbf800000);
|
||||
nv_wo32(chan, 0x386c, 0xbf800000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv30_graph_cclass = {
|
||||
.handle = NV_ENGCTX(GR, 0x30),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv30_graph_context_ctor,
|
||||
.dtor = _nouveau_graph_context_dtor,
|
||||
.init = nv20_graph_context_init,
|
||||
.fini = nv20_graph_context_fini,
|
||||
.rd32 = _nouveau_graph_context_rd32,
|
||||
.wr32 = _nouveau_graph_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00001000;
|
||||
nv_subdev(priv)->intr = nv20_graph_intr;
|
||||
nv_engine(priv)->cclass = &nv30_graph_cclass;
|
||||
nv_engine(priv)->sclass = nv30_graph_sclass;
|
||||
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv30_graph_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_engine *engine = nv_engine(object);
|
||||
struct nv20_graph_priv *priv = (void *)engine;
|
||||
struct nouveau_fb *pfb = nouveau_fb(object);
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
|
||||
|
||||
nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
|
||||
nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
|
||||
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
|
||||
nv_wr32(priv, 0x400890, 0x01b463ff);
|
||||
nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
|
||||
nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
|
||||
nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
|
||||
nv_wr32(priv, 0x400B80, 0x1003d888);
|
||||
nv_wr32(priv, 0x400B84, 0x0c000000);
|
||||
nv_wr32(priv, 0x400098, 0x00000000);
|
||||
nv_wr32(priv, 0x40009C, 0x0005ad00);
|
||||
nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
|
||||
nv_wr32(priv, 0x4000a0, 0x00000000);
|
||||
nv_wr32(priv, 0x4000a4, 0x00000008);
|
||||
nv_wr32(priv, 0x4008a8, 0xb784a400);
|
||||
nv_wr32(priv, 0x400ba0, 0x002f8685);
|
||||
nv_wr32(priv, 0x400ba4, 0x00231f3f);
|
||||
nv_wr32(priv, 0x4008a4, 0x40000020);
|
||||
|
||||
if (nv_device(priv)->chipset == 0x34) {
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
|
||||
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x4000c0, 0x00000016);
|
||||
|
||||
/* Turn all the tiling regions off. */
|
||||
for (i = 0; i < pfb->tile.regions; i++)
|
||||
engine->tile_prog(engine, i);
|
||||
|
||||
nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
|
||||
nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
|
||||
nv_wr32(priv, 0x0040075c , 0x00000001);
|
||||
|
||||
/* begin RAM config */
|
||||
/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
|
||||
nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
|
||||
nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
|
||||
if (nv_device(priv)->chipset != 0x34) {
|
||||
nv_wr32(priv, 0x400750, 0x00EA0000);
|
||||
nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
|
||||
nv_wr32(priv, 0x400750, 0x00EA0004);
|
||||
nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv30_graph_oclass = {
|
||||
.handle = NV_ENGINE(GR, 0x30),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv30_graph_ctor,
|
||||
.dtor = nv20_graph_dtor,
|
||||
.init = nv30_graph_init,
|
||||
.fini = _nouveau_graph_fini,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,168 @@
|
|||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
|
||||
#include <engine/graph.h>
|
||||
|
||||
#include "nv20.h"
|
||||
#include "regs.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Graphics object classes
|
||||
******************************************************************************/
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv34_graph_sclass[] = {
|
||||
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
|
||||
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
|
||||
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
|
||||
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
|
||||
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
|
||||
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
|
||||
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
|
||||
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
|
||||
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
|
||||
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
|
||||
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
|
||||
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
|
||||
{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
|
||||
{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
|
||||
{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
|
||||
{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
|
||||
{ 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv34_graph_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_chan *chan;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
|
||||
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan->chid = nouveau_fifo_chan(parent)->chid;
|
||||
|
||||
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
|
||||
nv_wo32(chan, 0x040c, 0x01000101);
|
||||
nv_wo32(chan, 0x0420, 0x00000111);
|
||||
nv_wo32(chan, 0x0424, 0x00000060);
|
||||
nv_wo32(chan, 0x0440, 0x00000080);
|
||||
nv_wo32(chan, 0x0444, 0xffff0000);
|
||||
nv_wo32(chan, 0x0448, 0x00000001);
|
||||
nv_wo32(chan, 0x045c, 0x44400000);
|
||||
nv_wo32(chan, 0x0480, 0xffff0000);
|
||||
for (i = 0x04d4; i < 0x04dc; i += 4)
|
||||
nv_wo32(chan, i, 0x0fff0000);
|
||||
nv_wo32(chan, 0x04e0, 0x00011100);
|
||||
for (i = 0x04fc; i < 0x053c; i += 4)
|
||||
nv_wo32(chan, i, 0x07ff0000);
|
||||
nv_wo32(chan, 0x0544, 0x4b7fffff);
|
||||
nv_wo32(chan, 0x057c, 0x00000080);
|
||||
nv_wo32(chan, 0x0580, 0x30201000);
|
||||
nv_wo32(chan, 0x0584, 0x70605040);
|
||||
nv_wo32(chan, 0x0588, 0xb8a89888);
|
||||
nv_wo32(chan, 0x058c, 0xf8e8d8c8);
|
||||
nv_wo32(chan, 0x05a0, 0xb0000000);
|
||||
for (i = 0x05f0; i < 0x0630; i += 4)
|
||||
nv_wo32(chan, i, 0x00010588);
|
||||
for (i = 0x0630; i < 0x0670; i += 4)
|
||||
nv_wo32(chan, i, 0x00030303);
|
||||
for (i = 0x06b0; i < 0x06f0; i += 4)
|
||||
nv_wo32(chan, i, 0x0008aae4);
|
||||
for (i = 0x06f0; i < 0x0730; i += 4)
|
||||
nv_wo32(chan, i, 0x01012000);
|
||||
for (i = 0x0730; i < 0x0770; i += 4)
|
||||
nv_wo32(chan, i, 0x00080008);
|
||||
nv_wo32(chan, 0x0850, 0x00040000);
|
||||
nv_wo32(chan, 0x0854, 0x00010000);
|
||||
for (i = 0x0858; i < 0x0868; i += 4)
|
||||
nv_wo32(chan, i, 0x00040004);
|
||||
for (i = 0x15ac; i <= 0x271c ; i += 16) {
|
||||
nv_wo32(chan, i + 0, 0x10700ff9);
|
||||
nv_wo32(chan, i + 1, 0x0436086c);
|
||||
nv_wo32(chan, i + 2, 0x000c001b);
|
||||
}
|
||||
for (i = 0x274c; i < 0x275c; i += 4)
|
||||
nv_wo32(chan, i, 0x0000ffff);
|
||||
nv_wo32(chan, 0x2ae0, 0x3f800000);
|
||||
nv_wo32(chan, 0x2e9c, 0x3f800000);
|
||||
nv_wo32(chan, 0x2eb0, 0x3f800000);
|
||||
nv_wo32(chan, 0x2edc, 0x40000000);
|
||||
nv_wo32(chan, 0x2ee0, 0x3f800000);
|
||||
nv_wo32(chan, 0x2ee4, 0x3f000000);
|
||||
nv_wo32(chan, 0x2eec, 0x40000000);
|
||||
nv_wo32(chan, 0x2ef0, 0x3f800000);
|
||||
nv_wo32(chan, 0x2ef8, 0xbf800000);
|
||||
nv_wo32(chan, 0x2f00, 0xbf800000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv34_graph_cclass = {
|
||||
.handle = NV_ENGCTX(GR, 0x34),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv34_graph_context_ctor,
|
||||
.dtor = _nouveau_graph_context_dtor,
|
||||
.init = nv20_graph_context_init,
|
||||
.fini = nv20_graph_context_fini,
|
||||
.rd32 = _nouveau_graph_context_rd32,
|
||||
.wr32 = _nouveau_graph_context_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* PGRAPH engine/subdev functions
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv20_graph_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00001000;
|
||||
nv_subdev(priv)->intr = nv20_graph_intr;
|
||||
nv_engine(priv)->cclass = &nv34_graph_cclass;
|
||||
nv_engine(priv)->sclass = nv34_graph_sclass;
|
||||
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv34_graph_oclass = {
|
||||
.handle = NV_ENGINE(GR, 0x34),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv34_graph_ctor,
|
||||
.dtor = nv20_graph_dtor,
|
||||
.init = nv30_graph_init,
|
||||
.fini = _nouveau_graph_fini,
|
||||
},
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue