From 37cd8b7c4c2c25775fdef480be81e6caf5a92ced Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 1 Aug 2010 20:57:07 -0400 Subject: [PATCH 001/277] .35 is a released kernel, so set it as such. --- kernel.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index 4878d6a66..5258140f9 100644 --- a/kernel.spec +++ b/kernel.spec @@ -6,7 +6,7 @@ Summary: The Linux kernel # For a stable, released kernel, released_kernel should be 1. For rawhide # and/or a kernel built from an rc or git snapshot, released_kernel should # be 0. -%global released_kernel 0 +%global released_kernel 1 # Save original buildid for later if it's defined %if 0%{?buildid:1} From f8200febc948906eaa9285e635e8d108f1e1eaed Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 1 Aug 2010 23:25:18 -0400 Subject: [PATCH 002/277] Bump baserelease --- kernel.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index 5258140f9..a18ca9e95 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 0 +%global baserelease 1 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching From 4d5b94503018a6ee1e35acc7350e8fb0e3e5124c Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Mon, 2 Aug 2010 10:15:45 -0400 Subject: [PATCH 003/277] Port shared source tree updates from f13. --- kernel.spec | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/kernel.spec b/kernel.spec index a18ca9e95..f3a158b46 100644 --- a/kernel.spec +++ b/kernel.spec @@ -969,16 +969,23 @@ ApplyOptionalPatch() %endif %endif -# We can share hardlinked source trees by putting a list of -# directory names of the CVS checkouts that we want to share -# with in .shared-srctree. (Full pathnames are required.) -[ -f .shared-srctree ] && sharedirs=$(cat .shared-srctree) +# %{vanillaversion} : the full version name, e.g. 2.6.35-rc6-git3 +# %{kversion} : the base version, e.g. 2.6.34 -if [ ! -d kernel-%{kversion}/vanilla-%{vanillaversion} ]; then +# Use kernel-%{kversion}%{?dist} as the top-level directory name +# so we can prep different trees within a single git directory. - if [ -d kernel-%{kversion}/vanilla-%{kversion} ]; then +# Build a list of the other top-level kernel tree directories. +# This will be used to hardlink identical vanilla subdirs. +sharedirs=$(find "$PWD" -maxdepth 1 -type d -name 'kernel-2.6.*' \ + | grep -x -v "$PWD"/kernel-%{kversion}%{?dist}) ||: - cd kernel-%{kversion} +if [ ! -d kernel-%{kversion}%{?dist}/vanilla-%{vanillaversion} ]; then + + if [ -d kernel-%{kversion}%{?dist}/vanilla-%{kversion} ]; then + + # The base vanilla version already exists. + cd kernel-%{kversion}%{?dist} # Any vanilla-* directories other than the base one are stale. for dir in vanilla-*; do @@ -987,18 +994,18 @@ if [ ! -d kernel-%{kversion}/vanilla-%{vanillaversion} ]; then else - # Ok, first time we do a make prep. rm -f pax_global_header + # Look for an identical base vanilla dir that can be hardlinked. for sharedir in $sharedirs ; do - if [[ ! -z $sharedir && -d $sharedir/kernel-%{kversion}/vanilla-%{kversion} ]] ; then + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{kversion} ]] ; then break fi done - if [[ ! -z $sharedir && -d $sharedir/kernel-%{kversion}/vanilla-%{kversion} ]] ; then -%setup -q -n kernel-%{kversion} -c -T - cp -rl $sharedir/kernel-%{kversion}/vanilla-%{kversion} . + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{kversion} ]] ; then +%setup -q -n kernel-%{kversion}%{?dist} -c -T + cp -rl $sharedir/vanilla-%{kversion} . else -%setup -q -n kernel-%{kversion} -c +%setup -q -n kernel-%{kversion}%{?dist} -c mv linux-%{kversion} vanilla-%{kversion} fi @@ -1007,16 +1014,17 @@ if [ ! -d kernel-%{kversion}/vanilla-%{vanillaversion} ]; then %if "%{kversion}" != "%{vanillaversion}" for sharedir in $sharedirs ; do - if [[ ! -z $sharedir && -d $sharedir/kernel-%{kversion}/vanilla-%{vanillaversion} ]] ; then + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{vanillaversion} ]] ; then break fi done - if [[ ! -z $sharedir && -d $sharedir/kernel-%{kversion}/vanilla-%{vanillaversion} ]] ; then + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{vanillaversion} ]] ; then - cp -rl $sharedir/kernel-%{kversion}/vanilla-%{vanillaversion} . + cp -rl $sharedir/vanilla-%{vanillaversion} . else + # Need to apply patches to the base vanilla version. cp -rl vanilla-%{kversion} vanilla-%{vanillaversion} cd vanilla-%{vanillaversion} @@ -1041,10 +1049,13 @@ if [ ! -d kernel-%{kversion}/vanilla-%{vanillaversion} ]; then %endif else - # We already have a vanilla dir. - cd kernel-%{kversion} + + # We already have all vanilla dirs, just change to the top-level directory. + cd kernel-%{kversion}%{?dist} + fi +# Now build the fedora kernel tree. if [ -d linux-%{kversion}.%{_target_cpu} ]; then # Just in case we ctrl-c'd a prep already rm -rf deleteme.%{_target_cpu} From 4326aa56d83fb74d6a4ea9f2c71375aa3c8bb915 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 4 Aug 2010 15:06:07 -0400 Subject: [PATCH 004/277] sched: Revert nohz_ratelimit() which causes a lot of extra wakeups burning CPU, and my legs. --- kernel.spec | 10 ++- ...894d289d69bacf5acd983c97cd6e21a14c08.patch | 75 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch diff --git a/kernel.spec b/kernel.spec index f3a158b46..3c17c3d8c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 1 +%global baserelease 2 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -597,6 +597,8 @@ Patch09: linux-2.6-upstream-reverts.patch # Standalone patches Patch20: linux-2.6-hotfixes.patch +Patch21: linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch + Patch30: git-utrace.patch Patch31: utrace-ptrace-fix-build.patch Patch32: utrace-remove-use-of-kref_set.patch @@ -1118,6 +1120,8 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R ApplyPatch linux-2.6-hotfixes.patch +ApplyPatch linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch + # Roland's utrace ptrace replacement. ApplyPatch git-utrace.patch ApplyPatch utrace-ptrace-fix-build.patch @@ -1877,6 +1881,10 @@ fi # || || %changelog +* Wed Aug 04 2010 Dave Jones +- sched: Revert nohz_ratelimit() which causes a lot of + extra wakeups burning CPU, and my legs. + * Sun Aug 01 2010 Dave Jones - Linux 2.6.35 diff --git a/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch b/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch new file mode 100644 index 000000000..c13d98776 --- /dev/null +++ b/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch @@ -0,0 +1,75 @@ +From: Peter Zijlstra +Date: Fri, 9 Jul 2010 13:12:27 +0000 (+0200) +Subject: sched: Revert nohz_ratelimit() for now +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fx86%2Flinux-2.6-tip.git;a=commitdiff_plain;h=396e894d289d69bacf5acd983c97cd6e21a14c08 + +sched: Revert nohz_ratelimit() for now + +Norbert reported that nohz_ratelimit() causes his laptop to burn about +4W (40%) extra. For now back out the change and see if we can adjust +the power management code to make better decisions. + +Reported-by: Norbert Preining +Signed-off-by: Peter Zijlstra +Acked-by: Mike Galbraith +Cc: Arjan van de Ven +LKML-Reference: +Signed-off-by: Ingo Molnar +--- + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 747fcae..6e0bb86 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -273,17 +273,11 @@ extern cpumask_var_t nohz_cpu_mask; + #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ) + extern int select_nohz_load_balancer(int cpu); + extern int get_nohz_load_balancer(void); +-extern int nohz_ratelimit(int cpu); + #else + static inline int select_nohz_load_balancer(int cpu) + { + return 0; + } +- +-static inline int nohz_ratelimit(int cpu) +-{ +- return 0; +-} + #endif + + /* +diff --git a/kernel/sched.c b/kernel/sched.c +index f52a880..63b4a14 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -1232,16 +1232,6 @@ void wake_up_idle_cpu(int cpu) + smp_send_reschedule(cpu); + } + +-int nohz_ratelimit(int cpu) +-{ +- struct rq *rq = cpu_rq(cpu); +- u64 diff = rq->clock - rq->nohz_stamp; +- +- rq->nohz_stamp = rq->clock; +- +- return diff < (NSEC_PER_SEC / HZ) >> 1; +-} +- + #endif /* CONFIG_NO_HZ */ + + static u64 sched_avg_period(void) +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index 813993b..f898af6 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -325,7 +325,7 @@ void tick_nohz_stop_sched_tick(int inidle) + } while (read_seqretry(&xtime_lock, seq)); + + if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) || +- arch_needs_cpu(cpu) || nohz_ratelimit(cpu)) { ++ arch_needs_cpu(cpu)) { + next_jiffies = last_jiffies + 1; + delta_jiffies = 1; + } else { From 85a693ce782fe3e27750bb4619f2e799ec52b08d Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Thu, 5 Aug 2010 14:22:55 -0400 Subject: [PATCH 005/277] Disable CONFIG_MULTICORE_RAID456 --- config-generic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-generic b/config-generic index f948700b2..90b3924ba 100644 --- a/config-generic +++ b/config-generic @@ -684,7 +684,7 @@ CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID456=m -CONFIG_MULTICORE_RAID456=y +# CONFIG_MULTICORE_RAID456 is not set CONFIG_ASYNC_RAID6_TEST=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m From 6c58ce89ec02157ffb33c505af1b3a4f8a990aaa Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 6 Aug 2010 15:34:00 -0400 Subject: [PATCH 006/277] Copy fix for bug #617699 from f13. --- direct-io-move-aio_complete-into-end_io.patch | 204 ++++++++++++++++++ ...on-after-unwritten-extent-conversion.patch | 95 ++++++++ kernel.spec | 27 ++- ...on-after-unwritten-extent-conversion.patch | 83 +++++++ 4 files changed, 398 insertions(+), 11 deletions(-) create mode 100644 direct-io-move-aio_complete-into-end_io.patch create mode 100644 ext4-move-aio-completion-after-unwritten-extent-conversion.patch create mode 100644 xfs-move-aio-completion-after-unwritten-extent-conversion.patch diff --git a/direct-io-move-aio_complete-into-end_io.patch b/direct-io-move-aio_complete-into-end_io.patch new file mode 100644 index 000000000..b40487155 --- /dev/null +++ b/direct-io-move-aio_complete-into-end_io.patch @@ -0,0 +1,204 @@ +From: Christoph Hellwig +Date: Sun, 18 Jul 2010 21:17:09 +0000 (+0000) +Subject: direct-io: move aio_complete into ->end_io +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=40e2e97316af6e62affab7a392e792494b8d9dde + +direct-io: move aio_complete into ->end_io + +Filesystems with unwritten extent support must not complete an AIO request +until the transaction to convert the extent has been commited. That means +the aio_complete calls needs to be moved into the ->end_io callback so +that the filesystem can control when to call it exactly. + +This makes a bit of a mess out of dio_complete and the ->end_io callback +prototype even more complicated. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Jan Kara +Signed-off-by: Alex Elder +--- + +diff --git a/fs/direct-io.c b/fs/direct-io.c +index 7600aac..a10cb91 100644 +--- a/fs/direct-io.c ++++ b/fs/direct-io.c +@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio) + * filesystems can use it to hold additional state between get_block calls and + * dio_complete. + */ +-static int dio_complete(struct dio *dio, loff_t offset, int ret) ++static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async) + { + ssize_t transferred = 0; + +@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) + transferred = dio->i_size - offset; + } + +- if (dio->end_io && dio->result) +- dio->end_io(dio->iocb, offset, transferred, +- dio->map_bh.b_private); +- +- if (dio->flags & DIO_LOCKING) +- /* lockdep: non-owner release */ +- up_read_non_owner(&dio->inode->i_alloc_sem); +- + if (ret == 0) + ret = dio->page_errors; + if (ret == 0) +@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) + if (ret == 0) + ret = transferred; + ++ if (dio->end_io && dio->result) { ++ dio->end_io(dio->iocb, offset, transferred, ++ dio->map_bh.b_private, ret, is_async); ++ } else if (is_async) { ++ aio_complete(dio->iocb, ret, 0); ++ } ++ ++ if (dio->flags & DIO_LOCKING) ++ /* lockdep: non-owner release */ ++ up_read_non_owner(&dio->inode->i_alloc_sem); ++ + return ret; + } + +@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error) + spin_unlock_irqrestore(&dio->bio_lock, flags); + + if (remaining == 0) { +- int ret = dio_complete(dio, dio->iocb->ki_pos, 0); +- aio_complete(dio->iocb, ret, 0); ++ dio_complete(dio, dio->iocb->ki_pos, 0, true); + kfree(dio); + } + } +@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, + spin_unlock_irqrestore(&dio->bio_lock, flags); + + if (ret2 == 0) { +- ret = dio_complete(dio, offset, ret); ++ ret = dio_complete(dio, offset, ret, false); + kfree(dio); + } else + BUG_ON(ret != -EIOCBQUEUED); +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 42272d6..0afc8c1 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3775,7 +3775,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) + } + + static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, +- ssize_t size, void *private) ++ ssize_t size, void *private, int ret, ++ bool is_async) + { + ext4_io_end_t *io_end = iocb->private; + struct workqueue_struct *wq; +@@ -3784,7 +3785,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + + /* if not async direct IO or dio with 0 bytes write, just return */ + if (!io_end || !size) +- return; ++ goto out; + + ext_debug("ext4_end_io_dio(): io_end 0x%p" + "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", +@@ -3795,7 +3796,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + if (io_end->flag != EXT4_IO_UNWRITTEN){ + ext4_free_io_end(io_end); + iocb->private = NULL; +- return; ++ goto out; + } + + io_end->offset = offset; +@@ -3812,6 +3813,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + list_add_tail(&io_end->list, &ei->i_completed_io_list); + spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); + iocb->private = NULL; ++out: ++ if (is_async) ++ aio_complete(iocb, ret, 0); + } + + static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) +diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c +index 356e976..96337a4 100644 +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -578,7 +578,9 @@ bail: + static void ocfs2_dio_end_io(struct kiocb *iocb, + loff_t offset, + ssize_t bytes, +- void *private) ++ void *private, ++ int ret, ++ bool is_async) + { + struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; + int level; +@@ -592,6 +594,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, + if (!level) + up_read(&inode->i_alloc_sem); + ocfs2_rw_unlock(inode, level); ++ ++ if (is_async) ++ aio_complete(iocb, ret, 0); + } + + /* +diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c +index 8abbf05..95d1e26 100644 +--- a/fs/xfs/linux-2.6/xfs_aops.c ++++ b/fs/xfs/linux-2.6/xfs_aops.c +@@ -1406,7 +1406,9 @@ xfs_end_io_direct( + struct kiocb *iocb, + loff_t offset, + ssize_t size, +- void *private) ++ void *private, ++ int ret, ++ bool is_async) + { + xfs_ioend_t *ioend = iocb->private; + +@@ -1452,6 +1454,9 @@ xfs_end_io_direct( + * against double-freeing. + */ + iocb->private = NULL; ++ ++ if (is_async) ++ aio_complete(iocb, ret, 0); + } + + STATIC ssize_t +diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h +index 319da17..c5057fb 100644 +--- a/fs/xfs/linux-2.6/xfs_aops.h ++++ b/fs/xfs/linux-2.6/xfs_aops.h +@@ -37,6 +37,8 @@ typedef struct xfs_ioend { + size_t io_size; /* size of the extent */ + xfs_off_t io_offset; /* offset in the file */ + struct work_struct io_work; /* xfsdatad work queue */ ++ struct kiocb *io_iocb; ++ int io_result; + } xfs_ioend_t; + + extern const struct address_space_operations xfs_address_space_operations; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 68ca1b0..f91affb 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -415,7 +415,8 @@ struct buffer_head; + typedef int (get_block_t)(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create); + typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, +- ssize_t bytes, void *private); ++ ssize_t bytes, void *private, int ret, ++ bool is_async); + + /* + * Attribute flags. These should be or-ed together to figure out what diff --git a/ext4-move-aio-completion-after-unwritten-extent-conversion.patch b/ext4-move-aio-completion-after-unwritten-extent-conversion.patch new file mode 100644 index 000000000..7e2cb1702 --- /dev/null +++ b/ext4-move-aio-completion-after-unwritten-extent-conversion.patch @@ -0,0 +1,95 @@ +From: jiayingz@google.com (Jiaying Zhang) <> +Date: Tue, 27 Jul 2010 15:56:06 +0000 (-0400) +Subject: ext4: move aio completion after unwritten extent conversion +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftytso%2Fext4.git;a=commitdiff_plain;h=5b3ff237bef43b9e7fb7d1eb858e29b73fd664f9 + +ext4: move aio completion after unwritten extent conversion + +This patch is to be applied upon Christoph's "direct-io: move aio_complete +into ->end_io" patch. It adds iocb and result fields to struct ext4_io_end_t, +so that we can call aio_complete from ext4_end_io_nolock() after the extent +conversion has finished. + +I have verified with Christoph's aio-dio test that used to fail after a few +runs on an original kernel but now succeeds on the patched kernel. + +See http://thread.gmane.org/gmane.comp.file-systems.ext4/19659 for details. + +Signed-off-by: Jiaying Zhang +Signed-off-by: "Theodore Ts'o" +--- + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 4c7d472..fbb3947 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -170,13 +170,15 @@ struct mpage_da_data { + }; + #define EXT4_IO_UNWRITTEN 0x1 + typedef struct ext4_io_end { +- struct list_head list; /* per-file finished AIO list */ ++ struct list_head list; /* per-file finished IO list */ + struct inode *inode; /* file being written to */ + unsigned int flag; /* unwritten or not */ + struct page *page; /* page struct for buffer write */ + loff_t offset; /* offset in the file */ + ssize_t size; /* size of the extent */ + struct work_struct work; /* data work queue */ ++ struct kiocb *iocb; /* iocb struct for AIO */ ++ int result; /* error value for AIO */ + } ext4_io_end_t; + + /* +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 609159e..46d2079 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3668,6 +3668,8 @@ static int ext4_end_io_nolock(ext4_io_end_t *io) + return ret; + } + ++ if (io->iocb) ++ aio_complete(io->iocb, io->result, 0); + /* clear the DIO AIO unwritten flag */ + io->flag = 0; + return ret; +@@ -3767,6 +3769,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) + io->offset = 0; + io->size = 0; + io->page = NULL; ++ io->iocb = NULL; ++ io->result = 0; + INIT_WORK(&io->work, ext4_end_io_work); + INIT_LIST_HEAD(&io->list); + } +@@ -3796,12 +3800,18 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + if (io_end->flag != EXT4_IO_UNWRITTEN){ + ext4_free_io_end(io_end); + iocb->private = NULL; +- goto out; ++out: ++ if (is_async) ++ aio_complete(iocb, ret, 0); ++ return; + } + + io_end->offset = offset; + io_end->size = size; +- io_end->flag = EXT4_IO_UNWRITTEN; ++ if (is_async) { ++ io_end->iocb = iocb; ++ io_end->result = ret; ++ } + wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; + + /* queue the work to convert unwritten extents to written */ +@@ -3813,9 +3823,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + list_add_tail(&io_end->list, &ei->i_completed_io_list); + spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); + iocb->private = NULL; +-out: +- if (is_async) +- aio_complete(iocb, ret, 0); + } + + static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) diff --git a/kernel.spec b/kernel.spec index 3c17c3d8c..1bcae334f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 2 +%global baserelease 3 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -700,6 +700,11 @@ Patch12030: ssb_check_for_sprom.patch Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch +# rhbz #617699 +Patch12050: direct-io-move-aio_complete-into-end_io.patch +Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch +Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1287,6 +1292,11 @@ ApplyPatch neuter_intel_microcode_load.patch ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch +# rhbz #617699 +ApplyPatch direct-io-move-aio_complete-into-end_io.patch +ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch +ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch + # END OF PATCH APPLICATIONS %endif @@ -1870,17 +1880,12 @@ fi # plz don't put in a version string unless you're going to tag # and build. -# ___________________________________________________________ -# / This branch is for Fedora 14. You probably want to commit \ -# \ to the F-13 branch instead, or in addition to this one. / -# ----------------------------------------------------------- -# \ ^__^ -# \ (@@)\_______ -# (__)\ )\/\ -# ||----w | -# || || - %changelog +* Fri Aug 06 2010 Chuck Ebbert 2.6.35-3 +- Copy fix for bug #617699 ("ext4 and xfs wrong data returned on read + after write if file size was changed with ftruncate") from F-13 +- Disable CONFIG_MULTICORE_RAID456 + * Wed Aug 04 2010 Dave Jones - sched: Revert nohz_ratelimit() which causes a lot of extra wakeups burning CPU, and my legs. diff --git a/xfs-move-aio-completion-after-unwritten-extent-conversion.patch b/xfs-move-aio-completion-after-unwritten-extent-conversion.patch new file mode 100644 index 000000000..290be17fd --- /dev/null +++ b/xfs-move-aio-completion-after-unwritten-extent-conversion.patch @@ -0,0 +1,83 @@ +From: Christoph Hellwig +Date: Sun, 18 Jul 2010 21:17:10 +0000 (+0000) +Subject: xfs: move aio completion after unwritten extent conversion +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fb511f2150174b18b28ad54708c1adda0df39b17 + +xfs: move aio completion after unwritten extent conversion + +If we write into an unwritten extent using AIO we need to complete the AIO +request after the extent conversion has finished. Without that a read could +race to see see the extent still unwritten and return zeros. For synchronous +I/O we already take care of that by flushing the xfsconvertd workqueue (which +might be a bit of overkill). + +To do that add iocb and result fields to struct xfs_ioend, so that we can +call aio_complete from xfs_end_io after the extent conversion has happened. +Note that we need a new result field as io_error is used for positive errno +values, while the AIO code can return negative error values and positive +transfer sizes. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Dave Chinner +Signed-off-by: Alex Elder +--- + +diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c +index 95d1e26..13622d5 100644 +--- a/fs/xfs/linux-2.6/xfs_aops.c ++++ b/fs/xfs/linux-2.6/xfs_aops.c +@@ -265,8 +265,11 @@ xfs_end_io( + xfs_finish_ioend(ioend, 0); + /* ensure we don't spin on blocked ioends */ + delay(1); +- } else ++ } else { ++ if (ioend->io_iocb) ++ aio_complete(ioend->io_iocb, ioend->io_result, 0); + xfs_destroy_ioend(ioend); ++ } + } + + /* +@@ -299,6 +302,8 @@ xfs_alloc_ioend( + atomic_inc(&XFS_I(ioend->io_inode)->i_iocount); + ioend->io_offset = 0; + ioend->io_size = 0; ++ ioend->io_iocb = NULL; ++ ioend->io_result = 0; + + INIT_WORK(&ioend->io_work, xfs_end_io); + return ioend; +@@ -1411,6 +1416,7 @@ xfs_end_io_direct( + bool is_async) + { + xfs_ioend_t *ioend = iocb->private; ++ bool complete_aio = is_async; + + /* + * Non-NULL private data means we need to issue a transaction to +@@ -1436,7 +1442,14 @@ xfs_end_io_direct( + if (ioend->io_type == IO_READ) { + xfs_finish_ioend(ioend, 0); + } else if (private && size > 0) { +- xfs_finish_ioend(ioend, is_sync_kiocb(iocb)); ++ if (is_async) { ++ ioend->io_iocb = iocb; ++ ioend->io_result = ret; ++ complete_aio = false; ++ xfs_finish_ioend(ioend, 0); ++ } else { ++ xfs_finish_ioend(ioend, 1); ++ } + } else { + /* + * A direct I/O write ioend starts it's life in unwritten +@@ -1455,7 +1468,7 @@ xfs_end_io_direct( + */ + iocb->private = NULL; + +- if (is_async) ++ if (complete_aio) + aio_complete(iocb, ret, 0); + } + From 9a98a7ebe364452045f3c2a80aeedf03e64db5a5 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 7 Aug 2010 12:36:54 -0400 Subject: [PATCH 007/277] Require newer linux-firmware package --- kernel.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index 1bcae334f..fc9c5fca9 100644 --- a/kernel.spec +++ b/kernel.spec @@ -451,7 +451,7 @@ Requires(pre): %{initrd_prereq}\ %if %{with_firmware}\ Requires(pre): kernel-firmware >= %{rpmversion}-%{pkg_release}\ %else\ -Requires(pre): linux-firmware\ +Requires(pre): linux-firmware >= 20100806-2\ %endif\ Requires(post): /sbin/new-kernel-pkg\ Requires(preun): /sbin/new-kernel-pkg\ From 74b9092d383eb6e1bb726ea6e6f0b9f658d74115 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 7 Aug 2010 12:55:01 -0400 Subject: [PATCH 008/277] Linux 2.6.35.1-rc1 --- kernel.spec | 9 ++++++--- sources | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel.spec b/kernel.spec index fc9c5fca9..fa52cd6fb 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 3 +%global baserelease 4 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,9 +60,9 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 0 +%define stable_update 1 # Is it a -stable RC? -%define stable_rc 0 +%define stable_rc 1 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1881,6 +1881,9 @@ fi # and build. %changelog +* Sat Aug 07 2010 Chuck Ebbert 2.6.35.1-4.rc1 +- Linux 2.6.35.1-rc1 + * Fri Aug 06 2010 Chuck Ebbert 2.6.35-3 - Copy fix for bug #617699 ("ext4 and xfs wrong data returned on read after write if file size was changed with ftruncate") from F-13 diff --git a/sources b/sources index 1cb4ebe00..ac901c98a 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 +58fd95172e18ed00310ec8b2f625f38f patch-2.6.35.1-rc1.bz2 From 71e9b6763f5b9c006f2cf1d34cc27299578e41e2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Aug 2010 11:43:52 +1000 Subject: [PATCH 009/277] nouveau: bring in misc fixes + fermi kms support --- config-generic | 1 + drm-i2c-ch7006-fix.patch | 57 + drm-nouveau-race-fix.patch | 141 ++ drm-nouveau-updates.patch | 3988 ++++++++++++++++++++++++++++++--- drm-sil164-module.patch | 592 +++++ drm-simplify-i2c-config.patch | 45 + kernel.spec | 14 +- 7 files changed, 4529 insertions(+), 309 deletions(-) create mode 100644 drm-i2c-ch7006-fix.patch create mode 100644 drm-nouveau-race-fix.patch create mode 100644 drm-sil164-module.patch create mode 100644 drm-simplify-i2c-config.patch diff --git a/config-generic b/config-generic index 90b3924ba..7cc1a746b 100644 --- a/config-generic +++ b/config-generic @@ -2308,6 +2308,7 @@ CONFIG_DRM_NOUVEAU=m CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_DEBUG=y CONFIG_DRM_I2C_CH7006=m +CONFIG_DRM_I2C_SIL164=m CONFIG_DRM_VMWGFX=m # diff --git a/drm-i2c-ch7006-fix.patch b/drm-i2c-ch7006-fix.patch new file mode 100644 index 000000000..11eef90e7 --- /dev/null +++ b/drm-i2c-ch7006-fix.patch @@ -0,0 +1,57 @@ +From 9fa9e790eb301bade8fe4ea0fd9ecb72617f0928 Mon Sep 17 00:00:00 2001 +From: Francisco Jerez +Date: Thu, 5 Aug 2010 22:57:08 +0200 +Subject: [PATCH 3/5] drm-i2c-ch7006-fix + +drm/i2c/ch7006: Don't use POWER_LEVEL_FULL_POWER_OFF on early chip versions. + +Signed-off-by: Francisco Jerez +--- + drivers/gpu/drm/i2c/ch7006_drv.c | 1 + + drivers/gpu/drm/i2c/ch7006_mode.c | 5 ++++- + drivers/gpu/drm/i2c/ch7006_priv.h | 1 + + 3 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c +index 81681a0..8c760c7 100644 +--- a/drivers/gpu/drm/i2c/ch7006_drv.c ++++ b/drivers/gpu/drm/i2c/ch7006_drv.c +@@ -454,6 +454,7 @@ static int ch7006_encoder_init(struct i2c_client *client, + priv->hmargin = 50; + priv->vmargin = 50; + priv->last_dpms = -1; ++ priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); + + if (ch7006_tv_norm) { + for (i = 0; i < NUM_TV_NORMS; i++) { +diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c +index e447dfb..c860f24 100644 +--- a/drivers/gpu/drm/i2c/ch7006_mode.c ++++ b/drivers/gpu/drm/i2c/ch7006_mode.c +@@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder) + } + + } else { +- *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); ++ if (priv->chip_version >= 0x20) ++ *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); ++ else ++ *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); + } + } + +diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h +index b06d3d9..9487123 100644 +--- a/drivers/gpu/drm/i2c/ch7006_priv.h ++++ b/drivers/gpu/drm/i2c/ch7006_priv.h +@@ -95,6 +95,7 @@ struct ch7006_priv { + int flicker; + int scale; + ++ int chip_version; + int last_dpms; + }; + +-- +1.7.2 + diff --git a/drm-nouveau-race-fix.patch b/drm-nouveau-race-fix.patch new file mode 100644 index 000000000..8b6f4dfd7 --- /dev/null +++ b/drm-nouveau-race-fix.patch @@ -0,0 +1,141 @@ +From 6b33cff9cd4f6f26df99e1486d53c91698d133b4 Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Fri, 23 Jul 2010 09:06:52 +1000 +Subject: [PATCH 5/5] drm-nouveau-race-fix + +drm/nouveau: fix race condition when under memory pressure + +rhbz#602663 + +When VRAM is running out it's possible that the client's push buffers get +evicted to main memory. When they're validated back in, the GPU may +be used for the copy back to VRAM, but the existing synchronisation code +only deals with inter-channel sync, not sync between PFIFO and PGRAPH on +the same channel. This leads to PFIFO fetching from command buffers that +haven't quite been copied by PGRAPH yet. + +This patch marks push buffers as so, and forces any GPU-assisted buffer +moves to be done on a different channel, which triggers the correct +synchronisation to happen before we submit them. + +After discussion with another nouveau developer, it was agreed that while +this patch is fine in itself, that we'd prefer to work out a nicer, but +likely much more invasive, fix upstream. + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++++++ + drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + + drivers/gpu/drm/nouveau/nouveau_gem.c | 36 +++++++++++++++++++++++--------- + 3 files changed, 42 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index f1357f1..f552c76 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -36,6 +36,21 @@ + #include + #include + ++int ++nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan) ++{ ++ struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; ++ int ret; ++ ++ if (!prev_fence || nouveau_fence_channel(prev_fence) == chan) ++ return 0; ++ ++ spin_lock(&nvbo->bo.lock); ++ ret = ttm_bo_wait(&nvbo->bo, false, false, false); ++ spin_unlock(&nvbo->bo.lock); ++ return ret; ++} ++ + static void + nouveau_bo_del_ttm(struct ttm_buffer_object *bo) + { +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h +index c001574..922ef43 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -1165,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); + extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); + extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); + extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); ++extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); + + /* nouveau_fence.c */ + struct nouveau_fence; +diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c +index 547f2c2..a915dcd 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_gem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c +@@ -361,16 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, + + list_for_each_entry(nvbo, list, entry) { + struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; +- struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; + +- if (prev_fence && nouveau_fence_channel(prev_fence) != chan) { +- spin_lock(&nvbo->bo.lock); +- ret = ttm_bo_wait(&nvbo->bo, false, false, false); +- spin_unlock(&nvbo->bo.lock); +- if (unlikely(ret)) { +- NV_ERROR(dev, "fail wait other chan\n"); +- return ret; +- } ++ ret = nouveau_bo_sync_gpu(nvbo, chan); ++ if (unlikely(ret)) { ++ NV_ERROR(dev, "fail pre-validate sync\n"); ++ return ret; + } + + ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains, +@@ -381,7 +376,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, + return ret; + } + +- nvbo->channel = chan; ++ nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; + ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, + false, false, false); + nvbo->channel = NULL; +@@ -390,6 +385,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, + return ret; + } + ++ ret = nouveau_bo_sync_gpu(nvbo, chan); ++ if (unlikely(ret)) { ++ NV_ERROR(dev, "fail post-validate sync\n"); ++ return ret; ++ } ++ + if (nvbo->bo.offset == b->presumed.offset && + ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && + b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || +@@ -615,6 +616,21 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, + + mutex_lock(&dev->struct_mutex); + ++ /* Mark push buffers as being used on PFIFO, the validation code ++ * will then make sure that if the pushbuf bo moves, that they ++ * happen on the kernel channel, which will in turn cause a sync ++ * to happen before we try and submit the push buffer. ++ */ ++ for (i = 0; i < req->nr_push; i++) { ++ if (push[i].bo_index >= req->nr_buffers) { ++ NV_ERROR(dev, "push %d buffer not in list\n", i); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ bo[push[i].bo_index].read_domains |= (1 << 31); ++ } ++ + /* Validate buffer list */ + ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, + req->nr_buffers, &op, &do_reloc); +-- +1.7.2 + diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 1b704ff0a..08baed1e1 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,56 +1,735 @@ +From 0983b95112413e5239b09f1f1a4500c0bccfe3b7 Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Tue, 1 Jun 2010 15:32:24 +1000 +Subject: [PATCH 4/4] drm-nouveau-updates +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +drm/nouveau: use drm_mm in preference to custom code doing the same thing + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove left-over !DRIVER_MODESET paths + +It's far preferable to have the driver do nothing at all for "nomodeset". + +Signed-off-by: Ben Skeggs + +drm/nouveau: missed some braces + +Luckily this had absolutely no effect whatsoever :) + +Reported-by: Marcin Slusarz +Signed-off-by: Ben Skeggs + +drm/nouveau: move LVDS detection back to connector detect() time + +Signed-off-by: Ben Skeggs + +drm/nouveau: Put the dithering check back in nouveau_connector_create. + +a7b9f9e5adef dropped it by accident. + +Signed-off-by: Francisco Jerez +Tested-by: Thibaut Girka +Signed-off-by: Ben Skeggs + +drm/nouveau: Don't clear AGPCMD completely on INIT_RESET. + +We just need to clear the SBA and ENABLE bits to reset the AGP +controller: If the AGP bridge was configured to use "fast writes", +clearing the FW bit would break the subsequent MMIO writes and +eventually end with a lockup. + +Note that all the BIOSes I've seen do the same as we did (it works for +them because they don't use MMIO), OTOH the blob leaves FW untouched. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: Ignore broken legacy I2C entries. + +The nv05 card in the bug report [1] doesn't have usable I2C port +register offsets (they're all filled with zeros). Ignore them and use +the defaults. + +[1] http://bugs.launchpad.net/bugs/569505 + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: set encoder for lvds + +fixes oops in nouveau_connector_get_modes with nv_encoder is NULL + +Signed-off-by: Albert Damen +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: tidy connector/encoder creation a little + +Create connectors before encoders to avoid having to do another loop across +encoder list whenever we create a new connector. This allows us to pass +the connector to the encoder creation functions, and avoid using a +create_resources() callback since we can now call it directly. + +This can also potentially modify the connector ordering on nv50. On cards +where the DCB connector and encoder tables are in the same order, things +will be unchanged. However, there's some cards where the ordering between +the tables differ, and in one case, leads us to naming the connectors +"wrongly". + +Signed-off-by: Ben Skeggs + +drm/nouveau: downgrade severity of most init table parser errors + +As long as we know the length of the opcode, we're probably better off +trying to parse the remainder of an init table rather than aborting in +the middle of it. + +Signed-off-by: Ben Skeggs + +drm/nv50: fix DP->DVI if output has been programmed for native DP previously + +Signed-off-by: Ben Skeggs + +drm/nv50: DCB quirk for Dell M6300 + +Uncertain if this is a weirdo configuration, or a BIOS bug. If it's not +a BIOS bug, we still don't know how to make it work anyway so ignore a +"conflicting" DCB entry to prevent a display hang. + +Signed-off-by: Ben Skeggs + +drm: disable encoder rather than dpms off in drm_crtc_prepare_encoders() + +Original behaviour will be preserved for drivers that don't implement +disable() hooks for an encoder. + +Signed-off-by: Ben Skeggs + +drm/nv50: supply encoder disable() hook for SOR outputs + +Allows us to remove a driver hack that used to be necessary to disable +encoders in certain situations before setting up a mode. The DRM has +better knowledge of when this is needed than the driver does. + +This fixes a number of display switching issues. + +Signed-off-by: Ben Skeggs + +drm/nv50: fix regression caused by ed15e77b6ee7c4fa6f50c18b3325e7f96ed3aade + +It became possible for us to have connectors present without any encoders +attached (TV out, we don't support TVDAC yet), which caused the DDX to +segfault. + +Signed-off-by: Ben Skeggs + +drm/nv04: fix regression caused by ed15e77b6ee7c4fa6f50c18b3325e7f96ed3aade + +Signed-off-by: Ben Skeggs + +drm/nv50: when debugging on, log which crtc we connect an encoder to + +Signed-off-by: Ben Skeggs + +drm/nv17-nv40: Avoid using active CRTCs for load detection. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv04-nv40: Prevent invalid DAC/TVDAC combinations. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv04-nv40: Disable connector polling when there're no spare CRTCs left. + +Load detection needs the connector wired to a CRTC, when there are no +inactive CRTCs left that means we need to cut some other head off for +a while, causing intermittent flickering. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv50: fix memory detection for cards with >=4GiB VRAM + +Signed-off-by: Ben Skeggs + +drm/nouveau: Fix a couple of sparse warnings. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: INIT_CONFIGURE_PREINIT/CLK/MEM on newer BIOSes is not an error. + +No need to spam the logs when they're found, they're equivalent to +INIT_DONE. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv04-nv40: Drop redundant logging. + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: Move the fence wait before migration resource clean-up. + +Avoids an oops in the fence wait failure path (bug 26521). + +Signed-off-by: Francisco Jerez +Tested-by: Marcin Slusarz +Signed-off-by: Ben Skeggs + +drm/nouveau: Workaround broken TV load detection on a "Zotac FX5200". + +The blob seems to have the same problem so it's probably a hardware +issue (bug 28810). + +Signed-off-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv50: send evo "update" command after each disconnect + +It turns out that the display engine signals an interrupt for disconnects +too. In order to make it easier to process the display interrupts +correctly, we want to ensure we only get one operation per interrupt +sequence - this is what this commit achieves. + +Signed-off-by: Ben Skeggs + +drm/nv50: rewrite display irq handler + +The previous handler basically worked correctly for a full-blown mode +change. However, it did nothing at all when a partial (encoder only) +reconfiguation was necessary, leading to the display hanging on certain +types of mode switch. + +Signed-off-by: Ben Skeggs + +drm/nouveau: move DP script invocation to nouveau_dp.c + +Signed-off-by: Ben Skeggs + +drm/nv50: set DP display power state during DPMS + +Signed-off-by: Ben Skeggs + +drm/nouveau: add scaler-only modes for eDP too + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove dev_priv->init_state and friends + +Nouveau will no longer load at all if card initialisation fails, so all +these checks are unnecessary. + +Signed-off-by: Ben Skeggs + +drm/nv50: implement DAC disconnect fix missed in earlier commit + +Signed-off-by: Ben Skeggs + +drm/nouveau: reduce usage of fence spinlock to when absolutely necessary + +Signed-off-by: Ben Skeggs + +drm/nouveau: place notifiers in system memory by default + +Signed-off-by: Ben Skeggs + +drm/nouveau: add instmem flush() hook + +This removes the previous prepare_access() and finish_access() hooks, and +replaces it with a much simpler flush() hook. + +All the chipset-specific code before nv50 has its use removed completely, +as it's not required there at all. + +Signed-off-by: Ben Skeggs + +drm/nv50: move tlb flushing to a helper function + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove ability to use external firmware + +This was always really a developer option, and if it's really necessary we +can hack this in ourselves. + +Signed-off-by: Ben Skeggs + +drm/nouveau: allocate fixed amount of PRAMIN per channel on all chipsets + +Previously only done on nv50+ + +This commit also switches unknown NV2x/NV3x chipsets to noaccel mode. + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove unused fbdev_info + +Signed-off-by: Ben Skeggs + +drm/nv50: cleanup nv50_fifo.c + +Signed-off-by: Ben Skeggs + +drm/nv20-nv30: move context table object out of dev_priv + +Signed-off-by: Ben Skeggs + +drm/nv50: fix dp_set_tmds to work on the right OR + +Signed-off-by: Ben Skeggs + +drm/nouveau: fix mtrr cleanup path + +Signed-off-by: Ben Skeggs + +drm/nv50: move dp_set_tmds() function to happen in the last display irq + +It seems on some chipsets that doing this from the 0x20 handler causes the +display engine to not ever signal the final 0x40 stage. + +Signed-off-by: Ben Skeggs + +drm/nouveau: initialise display before enabling interrupts + +In some situations it's possible we can receive a spurious hotplug IRQ +before we're ready to handle it, leading to an oops. + +Calling the display init before enabling interrupts should clear any +pending IRQs on the GPU and prevent this from happening. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Disable PROM access on init. + +On older cards ( + +drm/i2c/ch7006: Fix up suspend/resume. + +Signed-off-by: Francisco Jerez + +drm/nv04: Enable context switching on PFIFO init. + +Fixes a lockup when coming back from suspend. + +Signed-off-by: Francisco Jerez + +drm/nv50: fix RAMHT size + +Signed-off-by: Ben Skeggs + +drm/nv50: use correct PRAMIN flush register on original nv50 + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove quirk to fabricate DVI-A output on DCB 1.5 boards + +There's a report of this quirk breaking modesetting on at least one board. +After discussion with Francisco Jerez, we've decided to remove it: + + it's not worth limiting the quirk to just where we know it can + work? i'm happy either way really :) + hmm, don't think so, most if not all DCB15 cards have just one DAC + and with that quirk there's no way to tell if the load comes from + the VGA or DVI port + +Signed-off-by: Ben Skeggs +Acked-by: Francisco Jerez + +drm/nouveau: support fetching LVDS EDID from ACPI + +Based on a patch from Matthew Garrett. + +Signed-off-by: Ben Skeggs +Acked-by: Matthew Garrett + +drm/nv50: fix regression that break LVDS in some places + +A previous commit started additionally using the SOR link when trying to +match the correct output script. However, we never fill in this field +for LVDS so we can never match a script at all. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Fix a sparse warning. + +It doesn't like variable length arrays. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Don't pick an interlaced mode as the panel native mode. + +Rescaling interlaced modes isn't going to work correctly, and even if +it did, come on, interlaced flat panels? are you pulling my leg? + +Signed-off-by: Francisco Jerez + +drm/nouveau: Add another Zotac FX5200 TV-out quirk. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Add some PFB register defines. + +Also collect all the PFB registers in a single place and remove some +duplicated definitions. + +Signed-off-by: Francisco Jerez + +drm/nv04-nv3x: Implement init-compute-mem. + +Init-compute-mem was the last piece missing for nv0x-nv3x card +cold-booting. This implementation is somewhat lacking but it's been +reported to work on most chipsets it was tested in. Let me know if it +breaks suspend to RAM for you. + +Signed-off-by: Francisco Jerez +Tested-by: Patrice Mandin +Tested-by: Ben Skeggs +Tested-by: Xavier Chantry +Tested-by: Marcin KoÅ›cielnicki + +drm/i2c/ch7006: Don't assume that the specified config points to static memory. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Add some generic I2C gadget detection code. + +Clean up and move the external TV encoder detection code to +nouveau_i2c.c, it's also going to be useful for external TMDS and DDC +detection. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Remove useless CRTC_OWNER logging. + +Signed-off-by: Francisco Jerez + +drm/nouveau: No need to lock/unlock the VGA CRTC regs all the time. + +Locking only makes sense in the VBIOS parsing code as it's executed +before CRTC init. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Reset CRTC owner to 0 before BIOS init. + +Fixes suspend+multihead on some boards that also use BIOS scripts for +modesetting. + +Signed-off-by: Francisco Jerez + +drm/nouveau: fix build without CONFIG_ACPI + +Signed-off-by: Ben Skeggs + +drm/nouveau: add nv_mask register accessor + +Signed-off-by: Ben Skeggs + +drm/nv50: add function to control GPIO IRQ reporting + +Signed-off-by: Ben Skeggs + +drm/nouveau: disable hotplug detect around DP link training + +Signed-off-by: Ben Skeggs + +drm/nv30: Init the PFB+0x3xx memory timing regs. + +Fixes the randomly flashing vertical lines seen on some nv3x after a +cold-boot. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Reset AGP before running the init scripts. + +BIOS scripts usually make an attempt to reset the AGP controller, +however on some nv4x cards doing it properly involves switching FW off +and on: if we do that without updating the AGP bridge settings +accordingly (e.g. with the corresponding calls to agp_enable()) we +will be locking ourselves out of the card MMIO space. Do it from +nouveau_mem_reset_agp() before the init scripts are executed. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Put back the old 2-messages I2C slave test. + +I was hoping we could detect I2C devices at a given address without +actually writing data into them, but apparently some DDC slaves get +confused with 0-bytes transactions. Put the good old test back. + +Reported-by: Ben Skeggs +Signed-off-by: Francisco Jerez + +drm/nouveau: Move display init to a new nouveau_engine. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Get rid of the remaining VGA CRTC locking. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Fix TV-out detection on unposted cards lacking a usable DCB table. + +Signed-off-by: Francisco Jerez + +drm/nv50: correct wait condition for instmem flush + +Reported-by: Marcin KoÅ›cielnicki +Signed-off-by: Ben Skeggs + +drm/nouveau: introduce gpio engine + +Signed-off-by: Ben Skeggs + +drm/nv50: fix some not-error error messages + +Signed-off-by: Ben Skeggs + +drm/nv50: use custom i2c algo for dp auxch + +This makes it easier to see how this is working, and lets us transfer the +EDID in blocks of 16 bytes. + +The primary reason for this change is because debug logs are rather hard +to read with the hundreds of single-byte auxch transactions that occur. + +Signed-off-by: Ben Skeggs + +drm/nouveau: set TASK_(UN)INTERRUPTIBLE before schedule_timeout() + +set_current_state() is called only once before the first iteration. +After return from schedule_timeout() current state is TASK_RUNNING. If +we are going to wait again, set_current_state() must be called. + +Signed-off-by: Kulikov Vasiliy +Signed-off-by: Francisco Jerez + +drm/nouveau: remove unused ttm bo list + +Signed-off-by: Ben Skeggs + +drm/nouveau: Fix AGP reset when AGP FW is already enabled on init. + +Previously nouveau_mem_reset_agp() was only disabling AGP fast writes +when coming back from suspend. However, the "locked out of the card +because of FW" problem can also be reproduced on init if you +unload/reload nouveau.ko several times. This patch makes the AGP code +reset FW on init. + +Signed-off-by: Francisco Jerez + +drm/nouveau: unwind on load errors + +nouveau_load() just returned directly if there was an error instead of +releasing resources. + +Signed-off-by: Dan Carpenter +Reviewed-by: Marcin Slusarz +Signed-off-by: Francisco Jerez + +drm/nouveau: Don't pass misaligned offsets to io_mapping_map_atomic_wc(). + +Signed-off-by: Francisco Jerez + +drm/nouveau: Fix the INIT_CONFIGURE_PREINIT BIOS opcode. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Ack the context switch interrupt before switching contexts. + +Leaving the IRQ unack'ed while switching contexts makes the switch +fail randomly on some nv1x. + +Signed-off-by: Francisco Jerez + +drm/nv10: Fix up switching of NV10TCL_DMA_VTXBUF. + +Not very nice, but I don't think there's a simpler workaround. + +Signed-off-by: Francisco Jerez + +drm/nv17-nv4x: Attempt to init some external TMDS transmitters. + +sil164 and friends are the most common, usually they just need to be +poked once because a fixed configuration is enough for any modes and +clocks, so they worked without this patch if the BIOS had done a good +job on POST. Display couldn't survive a suspend/resume cycle though. +Unfortunately, BIOS scripts are useless here. + +Signed-off-by: Francisco Jerez + +drm/nouveau: No need to set slave TV encoder configs explicitly. + +Signed-off-by: Francisco Jerez + +drm/nv30: Workaround dual TMDS brain damage. + +Signed-off-by: Francisco Jerez + +drm/nvc0: starting point for GF100 support, everything stubbed + +Signed-off-by: Ben Skeggs + +drm/nvc0: allow INIT_GPIO + +Signed-off-by: Ben Skeggs + +drm/nvc0: implement memory detection + +Signed-off-by: Ben Skeggs + +drm/nvc0: rudimentary instmem support + +Signed-off-by: Ben Skeggs + +drm/nvc0: fix evo dma object so we display something + +Signed-off-by: Ben Skeggs + +drm/nvc0: implement crtc pll setting + +Signed-off-by: Ben Skeggs + +drm/nouveau: implement init table op 0x57, INIT_LTIME + +Signed-off-by: Ben Skeggs +Signed-off-by: Marcin KoÅ›cielnicki + +drm/nouveau: implement init table opcodex 0x5e and 0x9a + +Signed-off-by: Ben Skeggs +Signed-off-by: Marcin KoÅ›cielnicki + +drm/nvc0: backup bar3 channel on suspend + +Signed-off-by: Ben Skeggs + +drm/nouveau: reduce severity of some "error" messages + +There's some known configurations where the lack of these tables/scripts +is perfectly normal, reduce visibilty of complaint messages to debug. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Init dcb->or on cards that have no usable DCB table. + +We need a valid OR value because there're a few nv17 cards with DCB v1.4. + +Signed-off-by: Francisco Jerez + +drm/nv04: Fix up SGRAM density detection. + +Signed-off-by: Francisco Jerez + +drm/nv30: Fix PFB init for nv31. + +Fixes a regression introduced by 58bbb63720c8997e0136fe1884101e7ca40d68fd +(fdo bug 29324). + +Reported-by: Johannes Obermayr +Signed-off-by: Francisco Jerez + +drm/nouveau: Fix DCB TMDS config parsing. + +Thinko caused by 43bda05428a3d2021f3c12220073e0251c65df8b. + +Signed-off-by: Francisco Jerez + +drm/nvc0: fix typo in PRAMIN flush + +Signed-off-by: Ben Skeggs + +drm/nouveau: Don't try DDC on the dummy I2C channel. + +Signed-off-by: Francisco Jerez + +drm/nv50: fix minor thinko from nvc0 changes +--- drivers/gpu/drm/drm_crtc_helper.c | 22 +- drivers/gpu/drm/i2c/ch7006_drv.c | 22 +- drivers/gpu/drm/i2c/ch7006_priv.h | 2 +- - drivers/gpu/drm/nouveau/Makefile | 2 +- + drivers/gpu/drm/nouveau/Makefile | 12 +- drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 ++- - drivers/gpu/drm/nouveau/nouveau_bios.c | 636 +++++++++++++++++++++------ - drivers/gpu/drm/nouveau/nouveau_bios.h | 4 +- - drivers/gpu/drm/nouveau/nouveau_bo.c | 9 +- + drivers/gpu/drm/nouveau/nouveau_bios.c | 820 ++++++++++++++++++++++----- + drivers/gpu/drm/nouveau/nouveau_bios.h | 5 +- + drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +- drivers/gpu/drm/nouveau/nouveau_calc.c | 4 +- drivers/gpu/drm/nouveau/nouveau_channel.c | 5 - - drivers/gpu/drm/nouveau/nouveau_connector.c | 404 ++++++++---------- + drivers/gpu/drm/nouveau/nouveau_connector.c | 417 ++++++-------- drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +- drivers/gpu/drm/nouveau/nouveau_dma.c | 8 +- - drivers/gpu/drm/nouveau/nouveau_dp.c | 24 +- - drivers/gpu/drm/nouveau/nouveau_drv.c | 31 +- - drivers/gpu/drm/nouveau/nouveau_drv.h | 90 ++--- - drivers/gpu/drm/nouveau/nouveau_encoder.h | 10 +- - drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 +- - drivers/gpu/drm/nouveau/nouveau_fence.c | 31 +- + drivers/gpu/drm/nouveau/nouveau_dp.c | 128 +++-- + drivers/gpu/drm/nouveau/nouveau_drv.c | 39 +- + drivers/gpu/drm/nouveau/nouveau_drv.h | 178 ++++--- + drivers/gpu/drm/nouveau/nouveau_encoder.h | 16 +- + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- + drivers/gpu/drm/nouveau/nouveau_fence.c | 35 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +- - drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 ------- - drivers/gpu/drm/nouveau/nouveau_i2c.c | 34 ++ - drivers/gpu/drm/nouveau/nouveau_i2c.h | 3 + - drivers/gpu/drm/nouveau/nouveau_mem.c | 275 ++---------- + drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 ------ + drivers/gpu/drm/nouveau/nouveau_hw.c | 11 +- + drivers/gpu/drm/nouveau/nouveau_i2c.c | 83 ++- + drivers/gpu/drm/nouveau/nouveau_i2c.h | 11 +- + drivers/gpu/drm/nouveau/nouveau_irq.c | 6 +- + drivers/gpu/drm/nouveau/nouveau_mem.c | 327 +++--------- drivers/gpu/drm/nouveau/nouveau_notifier.c | 30 +- - drivers/gpu/drm/nouveau/nouveau_object.c | 105 ++--- - drivers/gpu/drm/nouveau/nouveau_reg.h | 91 +++-- + drivers/gpu/drm/nouveau/nouveau_object.c | 105 +--- + drivers/gpu/drm/nouveau/nouveau_reg.h | 109 +++-- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 46 +-- - drivers/gpu/drm/nouveau/nouveau_state.c | 172 +++----- - drivers/gpu/drm/nouveau/nv04_crtc.c | 5 + - drivers/gpu/drm/nouveau/nv04_dac.c | 37 ++- - drivers/gpu/drm/nouveau/nv04_dfp.c | 12 +- - drivers/gpu/drm/nouveau/nv04_display.c | 64 ++-- + drivers/gpu/drm/nouveau/nouveau_state.c | 340 +++++++---- + drivers/gpu/drm/nouveau/nv04_crtc.c | 8 + + drivers/gpu/drm/nouveau/nv04_dac.c | 50 ++- + drivers/gpu/drm/nouveau/nv04_dfp.c | 85 +++- + drivers/gpu/drm/nouveau/nv04_display.c | 90 ++-- drivers/gpu/drm/nouveau/nv04_fifo.c | 20 +- drivers/gpu/drm/nouveau/nv04_graph.c | 5 +- drivers/gpu/drm/nouveau/nv04_instmem.c | 21 +- drivers/gpu/drm/nouveau/nv04_mc.c | 4 + - drivers/gpu/drm/nouveau/nv04_tv.c | 125 ++---- + drivers/gpu/drm/nouveau/nv04_tv.c | 133 ++--- drivers/gpu/drm/nouveau/nv10_fifo.c | 10 - - drivers/gpu/drm/nouveau/nv17_tv.c | 46 ++- - drivers/gpu/drm/nouveau/nv20_graph.c | 96 +++-- + drivers/gpu/drm/nouveau/nv10_gpio.c | 92 +++ + drivers/gpu/drm/nouveau/nv10_graph.c | 175 ++++-- + drivers/gpu/drm/nouveau/nv17_gpio.c | 92 --- + drivers/gpu/drm/nouveau/nv17_tv.c | 65 ++- + drivers/gpu/drm/nouveau/nv20_graph.c | 96 ++-- + drivers/gpu/drm/nouveau/nv30_fb.c | 95 +++ drivers/gpu/drm/nouveau/nv40_fifo.c | 8 - drivers/gpu/drm/nouveau/nv40_graph.c | 58 +-- drivers/gpu/drm/nouveau/nv40_mc.c | 2 +- - drivers/gpu/drm/nouveau/nv50_crtc.c | 42 +-- - drivers/gpu/drm/nouveau/nv50_dac.c | 43 ++- - drivers/gpu/drm/nouveau/nv50_display.c | 385 ++++++++++------- - drivers/gpu/drm/nouveau/nv50_fifo.c | 126 ++---- - drivers/gpu/drm/nouveau/nv50_graph.c | 86 ++--- + drivers/gpu/drm/nouveau/nv50_crtc.c | 65 +-- + drivers/gpu/drm/nouveau/nv50_dac.c | 43 +- + drivers/gpu/drm/nouveau/nv50_display.c | 424 +++++++++------ + drivers/gpu/drm/nouveau/nv50_display.h | 6 +- + drivers/gpu/drm/nouveau/nv50_fifo.c | 126 ++--- + drivers/gpu/drm/nouveau/nv50_gpio.c | 35 ++ + drivers/gpu/drm/nouveau/nv50_graph.c | 86 ++-- drivers/gpu/drm/nouveau/nv50_instmem.c | 67 +-- - drivers/gpu/drm/nouveau/nv50_sor.c | 105 +++--- + drivers/gpu/drm/nouveau/nv50_sor.c | 105 ++-- + drivers/gpu/drm/nouveau/nvc0_fb.c | 38 ++ + drivers/gpu/drm/nouveau/nvc0_fifo.c | 95 +++ + drivers/gpu/drm/nouveau/nvc0_graph.c | 74 +++ + drivers/gpu/drm/nouveau/nvc0_instmem.c | 231 ++++++++ drivers/gpu/drm/nouveau/nvreg.h | 22 - - 52 files changed, 1748 insertions(+), 1919 deletions(-) + 64 files changed, 3285 insertions(+), 2257 deletions(-) + delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c + create mode 100644 drivers/gpu/drm/nouveau/nv10_gpio.c + delete mode 100644 drivers/gpu/drm/nouveau/nv17_gpio.c + create mode 100644 drivers/gpu/drm/nouveau/nv30_fb.c + create mode 100644 drivers/gpu/drm/nouveau/nvc0_fb.c + create mode 100644 drivers/gpu/drm/nouveau/nvc0_fifo.c + create mode 100644 drivers/gpu/drm/nouveau/nvc0_graph.c + create mode 100644 drivers/gpu/drm/nouveau/nvc0_instmem.c diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9b2a541..1eaa315 100644 @@ -111,7 +790,7 @@ index 9b2a541..1eaa315 100644 } diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c -index 81681a0..833b35f 100644 +index 8c760c7..08792a7 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder, @@ -155,7 +834,7 @@ index 81681a0..833b35f 100644 static int ch7006_encoder_init(struct i2c_client *client, struct drm_device *dev, struct drm_encoder_slave *encoder) -@@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = { +@@ -488,6 +504,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = { .i2c_driver = { .probe = ch7006_probe, .remove = ch7006_remove, @@ -165,7 +844,7 @@ index 81681a0..833b35f 100644 .driver = { .name = "ch7006", diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h -index b06d3d9..1c6d2e3 100644 +index 9487123..17667b7 100644 --- a/drivers/gpu/drm/i2c/ch7006_priv.h +++ b/drivers/gpu/drm/i2c/ch7006_priv.h @@ -77,7 +77,7 @@ struct ch7006_state { @@ -178,10 +857,10 @@ index b06d3d9..1c6d2e3 100644 struct ch7006_state state; diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile -index acd31ed..4a1db73 100644 +index acd31ed..e9b06e4 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile -@@ -9,7 +9,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ +@@ -9,20 +9,20 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.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 \ @@ -189,7 +868,25 @@ index acd31ed..4a1db73 100644 + nouveau_dp.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ +- nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ +- nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ ++ nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ ++ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \ + nv04_graph.o nv10_graph.o nv20_graph.o \ +- nv40_graph.o nv50_graph.o \ ++ nv40_graph.o nv50_graph.o nvc0_graph.o \ + nv40_grctx.o nv50_grctx.o \ +- nv04_instmem.o nv50_instmem.o \ ++ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ + nv50_crtc.o nv50_dac.o nv50_sor.o \ + nv50_cursor.o nv50_display.o nv50_fbcon.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 nv04_fbcon.o \ +- nv17_gpio.o nv50_gpio.o \ ++ nv10_gpio.o nv50_gpio.o \ + nv50_calc.o + + nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index d4bcca8..c17a055 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -258,7 +955,7 @@ index d4bcca8..c17a055 100644 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index e492919..aae29cc 100644 +index e492919..eb77710 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -28,6 +28,8 @@ @@ -543,7 +1240,104 @@ index e492919..aae29cc 100644 for (i = 0; i < count; i++) { uint8_t tmdsaddr = bios->data[offset + 3 + i * 2]; -@@ -2039,6 +2069,323 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -1898,6 +1928,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset, + } + + static int ++init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ++{ ++ /* ++ * INIT_LTIME opcode: 0x57 ('V') ++ * ++ * offset (8 bit): opcode ++ * offset + 1 (16 bit): time ++ * ++ * Sleep for "time" miliseconds. ++ */ ++ ++ unsigned time = ROM16(bios->data[offset + 1]); ++ ++ if (!iexec->execute) ++ return 3; ++ ++ BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n", ++ offset, time); ++ ++ msleep(time); ++ ++ return 3; ++} ++ ++static int + init_zm_reg_sequence(struct nvbios *bios, uint16_t offset, + struct init_exec *iexec) + { +@@ -1965,6 +2020,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + } + + static int ++init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ++{ ++ /* ++ * INIT_I2C_IF opcode: 0x5E ('^') ++ * ++ * offset (8 bit): opcode ++ * offset + 1 (8 bit): DCB I2C table entry index ++ * offset + 2 (8 bit): I2C slave address ++ * offset + 3 (8 bit): I2C register ++ * offset + 4 (8 bit): mask ++ * offset + 5 (8 bit): data ++ * ++ * Read the register given by "I2C register" on the device addressed ++ * by "I2C slave address" on the I2C bus given by "DCB I2C table ++ * entry index". Compare the result AND "mask" to "data". ++ * If they're not equal, skip subsequent opcodes until condition is ++ * inverted (INIT_NOT), or we hit INIT_RESUME ++ */ ++ ++ uint8_t i2c_index = bios->data[offset + 1]; ++ uint8_t i2c_address = bios->data[offset + 2] >> 1; ++ uint8_t reg = bios->data[offset + 3]; ++ uint8_t mask = bios->data[offset + 4]; ++ uint8_t data = bios->data[offset + 5]; ++ struct nouveau_i2c_chan *chan; ++ union i2c_smbus_data val; ++ int ret; ++ ++ /* no execute check by design */ ++ ++ BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", ++ offset, i2c_index, i2c_address); ++ ++ chan = init_i2c_device_find(bios->dev, i2c_index); ++ if (!chan) ++ return -ENODEV; ++ ++ ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, ++ I2C_SMBUS_READ, reg, ++ I2C_SMBUS_BYTE_DATA, &val); ++ if (ret < 0) { ++ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], " ++ "Mask: 0x%02X, Data: 0x%02X\n", ++ offset, reg, mask, data); ++ iexec->execute = 0; ++ return 6; ++ } ++ ++ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, " ++ "Mask: 0x%02X, Data: 0x%02X\n", ++ offset, reg, val.byte, mask, data); ++ ++ iexec->execute = ((val.byte & mask) == data); ++ ++ return 6; ++} ++ ++static int + init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + { + /* +@@ -2039,6 +2152,325 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) return 5; } @@ -561,9 +1355,10 @@ index e492919..aae29cc 100644 + uint32_t val = 0; + + if (off < pci_resource_len(dev->pdev, 1)) { -+ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off); ++ uint8_t __iomem *p = ++ io_mapping_map_atomic_wc(fb, off & PAGE_MASK); + -+ val = ioread32(p); ++ val = ioread32(p + (off & ~PAGE_MASK)); + + io_mapping_unmap_atomic(p); + } @@ -576,9 +1371,10 @@ index e492919..aae29cc 100644 + uint32_t off, uint32_t val) +{ + if (off < pci_resource_len(dev->pdev, 1)) { -+ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off); ++ uint8_t __iomem *p = ++ io_mapping_map_atomic_wc(fb, off & PAGE_MASK); + -+ iowrite32(val, p); ++ iowrite32(val, p + (off & ~PAGE_MASK)); + wmb(); + + io_mapping_unmap_atomic(p); @@ -643,7 +1439,7 @@ index e492919..aae29cc 100644 + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + -+ } else if (peek_fb(dev, fb, 0) == patt) { ++ } else if (peek_fb(dev, fb, 0) != patt) { + if (read_back_fb(dev, fb, 0x800000, patt)) + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_AMOUNT, @@ -867,7 +1663,7 @@ index e492919..aae29cc 100644 static int init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { -@@ -2047,64 +2394,57 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -2047,64 +2479,57 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * * offset (8 bit): opcode * @@ -970,7 +1766,7 @@ index e492919..aae29cc 100644 return 1; } -@@ -2131,7 +2471,8 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -2131,7 +2556,8 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) /* no iexec->execute check by design */ pci_nv_19 = bios_rd32(bios, NV_PBUS_PCI_NV_19); @@ -980,7 +1776,7 @@ index e492919..aae29cc 100644 bios_wr32(bios, reg, value1); udelay(10); -@@ -2167,7 +2508,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, +@@ -2167,7 +2593,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, uint32_t reg, data; if (bios->major_version > 2) @@ -989,7 +1785,7 @@ index e492919..aae29cc 100644 bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd( bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20); -@@ -2180,14 +2521,14 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, +@@ -2180,14 +2606,14 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, reg = ROM32(bios->data[seqtbloffs += 4])) { switch (reg) { @@ -1010,7 +1806,7 @@ index e492919..aae29cc 100644 break; default: data = ROM32(bios->data[meminitdata]); -@@ -2222,7 +2563,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset, +@@ -2222,7 +2648,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset, int clock; if (bios->major_version > 2) @@ -1019,8 +1815,12 @@ index e492919..aae29cc 100644 clock = ROM16(bios->data[meminitoffs + 4]) * 10; setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock); -@@ -2255,7 +2596,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset, - uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); +@@ -2252,10 +2678,10 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset, + /* no iexec->execute check by design */ + + uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0); +- uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); ++ uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6; if (bios->major_version > 2) - return -ENODEV; @@ -1028,7 +1828,7 @@ index e492919..aae29cc 100644 bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_SCRATCH4__INDEX, cr3c); -@@ -2389,7 +2730,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, +@@ -2389,7 +2815,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, * offset + 1 (8 bit): mask * offset + 2 (8 bit): cmpval * @@ -1037,7 +1837,7 @@ index e492919..aae29cc 100644 * If condition not met skip subsequent opcodes until condition is * inverted (INIT_NOT), or we hit INIT_RESUME */ -@@ -2401,7 +2742,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, +@@ -2401,7 +2827,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, if (!iexec->execute) return 3; @@ -1046,16 +1846,32 @@ index e492919..aae29cc 100644 BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n", offset, data, cmpval); -@@ -2800,7 +3141,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -2795,12 +3221,13 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + */ - if (dev_priv->card_type != NV_50) { + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; ++ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; + int i; + +- if (dev_priv->card_type != NV_50) { ++ if (dev_priv->card_type < NV_50) { NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); - return -ENODEV; + return 1; } if (!iexec->execute) -@@ -2872,10 +3213,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, +@@ -2815,7 +3242,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); + if (bios->execute) +- nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); ++ pgpio->set(bios->dev, gpio->tag, gpio->state_default); + + /* The NVIDIA binary driver doesn't appear to actually do + * any of this, my VBIOS does however. +@@ -2872,10 +3299,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, uint8_t index; int i; @@ -1067,7 +1883,7 @@ index e492919..aae29cc 100644 if (!blocklen) { NV_ERROR(bios->dev, "0x%04X: Zero block length - has the M table " -@@ -2883,6 +3221,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, +@@ -2883,6 +3307,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, return -EINVAL; } @@ -1077,7 +1893,7 @@ index e492919..aae29cc 100644 strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf; index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg]; -@@ -3064,14 +3405,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -3064,14 +3491,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!bios->display.output) { NV_ERROR(dev, "INIT_AUXCH: no active output\n"); @@ -1094,7 +1910,7 @@ index e492919..aae29cc 100644 } if (!iexec->execute) -@@ -3084,7 +3425,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -3084,7 +3511,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1); if (ret) { NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret); @@ -1103,7 +1919,7 @@ index e492919..aae29cc 100644 } data &= bios->data[offset + 0]; -@@ -3093,7 +3434,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -3093,7 +3520,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1); if (ret) { NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret); @@ -1112,7 +1928,7 @@ index e492919..aae29cc 100644 } } -@@ -3123,14 +3464,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -3123,14 +3550,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!bios->display.output) { NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n"); @@ -1129,7 +1945,7 @@ index e492919..aae29cc 100644 } if (!iexec->execute) -@@ -3141,7 +3482,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -3141,13 +3568,76 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1); if (ret) { NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret); @@ -1138,7 +1954,123 @@ index e492919..aae29cc 100644 } } -@@ -5151,10 +5492,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi + return len; + } + ++static int ++init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ++{ ++ /* ++ * INIT_I2C_LONG_IF opcode: 0x9A ('') ++ * ++ * offset (8 bit): opcode ++ * offset + 1 (8 bit): DCB I2C table entry index ++ * offset + 2 (8 bit): I2C slave address ++ * offset + 3 (16 bit): I2C register ++ * offset + 5 (8 bit): mask ++ * offset + 6 (8 bit): data ++ * ++ * Read the register given by "I2C register" on the device addressed ++ * by "I2C slave address" on the I2C bus given by "DCB I2C table ++ * entry index". Compare the result AND "mask" to "data". ++ * If they're not equal, skip subsequent opcodes until condition is ++ * inverted (INIT_NOT), or we hit INIT_RESUME ++ */ ++ ++ uint8_t i2c_index = bios->data[offset + 1]; ++ uint8_t i2c_address = bios->data[offset + 2] >> 1; ++ uint8_t reglo = bios->data[offset + 3]; ++ uint8_t reghi = bios->data[offset + 4]; ++ uint8_t mask = bios->data[offset + 5]; ++ uint8_t data = bios->data[offset + 6]; ++ struct nouveau_i2c_chan *chan; ++ uint8_t buf0[2] = { reghi, reglo }; ++ uint8_t buf1[1]; ++ struct i2c_msg msg[2] = { ++ { i2c_address, 0, 1, buf0 }, ++ { i2c_address, I2C_M_RD, 1, buf1 }, ++ }; ++ int ret; ++ ++ /* no execute check by design */ ++ ++ BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", ++ offset, i2c_index, i2c_address); ++ ++ chan = init_i2c_device_find(bios->dev, i2c_index); ++ if (!chan) ++ return -ENODEV; ++ ++ ++ ret = i2c_transfer(&chan->adapter, msg, 2); ++ if (ret < 0) { ++ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], " ++ "Mask: 0x%02X, Data: 0x%02X\n", ++ offset, reghi, reglo, mask, data); ++ iexec->execute = 0; ++ return 7; ++ } ++ ++ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, " ++ "Mask: 0x%02X, Data: 0x%02X\n", ++ offset, reghi, reglo, buf1[0], mask, data); ++ ++ iexec->execute = ((buf1[0] & mask) == data); ++ ++ return 7; ++} ++ + static struct init_tbl_entry itbl_entry[] = { + /* command name , id , length , offset , mult , command handler */ + /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */ +@@ -3174,9 +3664,11 @@ static struct init_tbl_entry itbl_entry[] = { + { "INIT_ZM_CR" , 0x53, init_zm_cr }, + { "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group }, + { "INIT_CONDITION_TIME" , 0x56, init_condition_time }, ++ { "INIT_LTIME" , 0x57, init_ltime }, + { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, + /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ + { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, ++ { "INIT_I2C_IF" , 0x5E, init_i2c_if }, + { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, + { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, + { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem }, +@@ -3210,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = { + { "INIT_97" , 0x97, init_97 }, + { "INIT_AUXCH" , 0x98, init_auxch }, + { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch }, ++ { "INIT_I2C_LONG_IF" , 0x9A, init_i2c_long_if }, + { NULL , 0 , NULL } + }; + +@@ -4068,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + bios->display.script_table_ptr, + table[2], table[3], table[0] >= 0x21); + if (!otable) { +- NV_ERROR(dev, "Couldn't find matching output script table\n"); ++ NV_DEBUG_KMS(dev, "failed to match any output table\n"); + return 1; + } + +@@ -4125,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + if (script) + script = clkcmptable(bios, script, pxclk); + if (!script) { +- NV_ERROR(dev, "clock script 0 not found\n"); ++ NV_DEBUG_KMS(dev, "clock script 0 not found\n"); + return 1; + } + +@@ -4484,7 +4977,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims + pll_lim->min_p = record[12]; + pll_lim->max_p = record[13]; + /* where did this go to?? */ +- if (limit_match == 0x00614100 || limit_match == 0x00614900) ++ if ((entry[0] & 0xf0) == 0x80) + pll_lim->refclk = 27000; + else + pll_lim->refclk = 100000; +@@ -5151,10 +5644,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; @@ -1157,7 +2089,16 @@ index e492919..aae29cc 100644 if (bmplength > 74) { bios->fmaxvco = ROM32(bmp[67]); -@@ -5589,9 +5934,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, +@@ -5506,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) + entry->i2c_index = i2c; + entry->heads = heads; + entry->location = DCB_LOC_ON_CHIP; +- /* "or" mostly unused in early gen crt modesetting, 0 is fine */ ++ entry->or = 1; + } + + static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) +@@ -5589,9 +6086,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x4 || conf & 0x8) entry->lvdsconf.use_power_scripts = true; } else { @@ -1171,7 +2112,22 @@ index e492919..aae29cc 100644 } if (conf & mask) { /* -@@ -5706,13 +6054,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, +@@ -5631,7 +6131,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, + } + break; + case OUTPUT_TMDS: +- entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; ++ if (dcb->version >= 0x40) ++ entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; ++ else if (dcb->version >= 0x30) ++ entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; ++ else if (dcb->version >= 0x22) ++ entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; ++ + break; + case 0xe: + /* weird g80 mobile type that "nv" treats as a terminator */ +@@ -5706,13 +6212,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, case OUTPUT_TV: entry->tvconf.has_component_output = false; break; @@ -1185,7 +2141,7 @@ index e492919..aae29cc 100644 case OUTPUT_LVDS: if ((conn & 0x00003f00) != 0x10) entry->lvdsconf.use_straps_for_mode = true; -@@ -5793,6 +6134,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) +@@ -5793,6 +6292,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) dcb->entries = newentries; } @@ -1217,7 +2173,27 @@ index e492919..aae29cc 100644 static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) { -@@ -5926,6 +6292,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +@@ -5903,6 +6427,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) + dcb->i2c_table = &bios->data[i2ctabptr]; + if (dcb->version >= 0x30) + dcb->i2c_default_indices = dcb->i2c_table[4]; ++ ++ /* ++ * Parse the "management" I2C bus, used for hardware ++ * monitoring and some external TMDS transmitters. ++ */ ++ if (dcb->version >= 0x22) { ++ int idx = (dcb->version >= 0x40 ? ++ dcb->i2c_default_indices & 0xf : ++ 2); ++ ++ read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, ++ idx, &dcb->i2c[idx]); ++ } + } + + if (entries > DCB_MAX_NUM_ENTRIES) +@@ -5926,6 +6463,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) if ((connection & 0x0000000f) == 0x0000000f) continue; @@ -1227,20 +2203,28 @@ index e492919..aae29cc 100644 NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", dcb->entries, connection, config); -@@ -6182,8 +6551,10 @@ nouveau_run_vbios_init(struct drm_device *dev) +@@ -6181,9 +6721,8 @@ nouveau_run_vbios_init(struct drm_device *dev) + struct nvbios *bios = &dev_priv->vbios; int i, ret = 0; - NVLockVgaCrtcs(dev, false); +- NVLockVgaCrtcs(dev, false); - if (nv_two_heads(dev)) - NVSetOwner(dev, bios->state.crtchead); -+ if (nv_two_heads(dev)) { -+ bios->state.crtchead = 0; -+ NVSetOwner(dev, 0); -+ } ++ /* Reset the BIOS head to 0. */ ++ bios->state.crtchead = 0; if (bios->major_version < 5) /* BMP only */ load_nv17_hw_sequencer_ucode(dev, bios); -@@ -6238,7 +6609,6 @@ static bool +@@ -6216,8 +6755,6 @@ nouveau_run_vbios_init(struct drm_device *dev) + } + } + +- NVLockVgaCrtcs(dev, true); +- + return ret; + } + +@@ -6238,7 +6775,6 @@ static bool nouveau_bios_posted(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -1248,24 +2232,22 @@ index e492919..aae29cc 100644 unsigned htotal; if (dev_priv->chipset >= NV_50) { -@@ -6248,13 +6618,14 @@ nouveau_bios_posted(struct drm_device *dev) +@@ -6248,13 +6784,12 @@ nouveau_bios_posted(struct drm_device *dev) return true; } - was_locked = NVLockVgaCrtcs(dev, false); -+ NVLockVgaCrtcs(dev, false); htotal = NVReadVgaCrtc(dev, 0, 0x06); htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; - NVLockVgaCrtcs(dev, was_locked); -+ NVLockVgaCrtcs(dev, true); + return (htotal != 0); } -@@ -6263,8 +6634,6 @@ nouveau_bios_init(struct drm_device *dev) +@@ -6263,8 +6798,6 @@ nouveau_bios_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; @@ -1274,7 +2256,7 @@ index e492919..aae29cc 100644 int ret; if (!NVInitVBIOS(dev)) -@@ -6284,40 +6653,29 @@ nouveau_bios_init(struct drm_device *dev) +@@ -6284,40 +6817,27 @@ nouveau_bios_init(struct drm_device *dev) if (!bios->major_version) /* we don't run version 0 bios */ return 0; @@ -1307,7 +2289,6 @@ index e492919..aae29cc 100644 /* feature_byte on BMP is poor, but init always sets CR4B */ - was_locked = NVLockVgaCrtcs(dev, false); -+ NVLockVgaCrtcs(dev, false); if (bios->major_version < 5) bios->is_mobile = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_4B) & 0x40; @@ -1315,12 +2296,11 @@ index e492919..aae29cc 100644 if (bios->is_mobile || bios->major_version >= 5) ret = parse_fp_mode_table(dev, bios); - NVLockVgaCrtcs(dev, was_locked); -+ NVLockVgaCrtcs(dev, true); /* allow subsequent scripts to execute */ bios->execute = true; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h -index adf4ec2..024458a 100644 +index adf4ec2..fd14dfd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -81,6 +81,7 @@ struct dcb_connector_table_entry { @@ -1339,7 +2319,15 @@ index adf4ec2..024458a 100644 bool use_power_scripts; } lvdsconf; struct { -@@ -249,8 +251,6 @@ struct nvbios { +@@ -129,6 +131,7 @@ struct dcb_entry { + } dpconf; + struct { + struct sor_conf sor; ++ int slave_addr; + } tmdsconf; + }; + bool i2c_upper_default; +@@ -249,8 +252,6 @@ struct nvbios { struct { int crtchead; @@ -1349,10 +2337,30 @@ index adf4ec2..024458a 100644 struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index 6f3c195..d8c341d 100644 +index 6f3c195..f1357f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c -@@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, +@@ -51,9 +51,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) + if (nvbo->tile) + nv10_mem_expire_tiling(dev, nvbo->tile, NULL); + +- spin_lock(&dev_priv->ttm.bo_list_lock); +- list_del(&nvbo->head); +- spin_unlock(&dev_priv->ttm.bo_list_lock); + kfree(nvbo); + } + +@@ -166,9 +163,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, + } + nvbo->channel = NULL; + +- spin_lock(&dev_priv->ttm.bo_list_lock); +- list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list); +- spin_unlock(&dev_priv->ttm.bo_list_lock); + *pnvbo = nvbo; + return 0; + } +@@ -461,9 +455,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, @@ -1365,7 +2373,7 @@ index 6f3c195..d8c341d 100644 nouveau_fence_unref((void *)&fence); return ret; } -@@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, +@@ -711,8 +705,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, return ret; /* Software copy if the card isn't up and running yet. */ @@ -1429,10 +2437,23 @@ index 1fc57ef..e952c3b 100644 nouveau_channel_free(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c -index 149ed22..734e926 100644 +index 149ed22..a1473ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c -@@ -102,63 +102,15 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) +@@ -37,12 +37,6 @@ + #include "nouveau_connector.h" + #include "nouveau_hw.h" + +-static inline struct drm_encoder_slave_funcs * +-get_slave_funcs(struct nouveau_encoder *enc) +-{ +- return to_encoder_slave(to_drm_encoder(enc))->slave_funcs; +-} +- + static struct nouveau_encoder * + find_encoder_by_type(struct drm_connector *connector, int type) + { +@@ -102,60 +96,12 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) kfree(drm_connector); } @@ -1493,32 +2514,24 @@ index 149ed22..734e926 100644 + int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { -- struct nouveau_i2c_chan *i2c = NULL; -+ struct nouveau_i2c_chan *i2c; - struct nouveau_encoder *nv_encoder; - struct drm_mode_object *obj; - int id; -@@ -171,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, - if (!obj) - continue; - nv_encoder = nouveau_encoder(obj_to_encoder(obj)); -+ i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + struct nouveau_i2c_chan *i2c = NULL; +@@ -174,14 +120,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, -- if (nv_encoder->dcb->i2c_index < 0xf) -- i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + if (nv_encoder->dcb->i2c_index < 0xf) + i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (!i2c) - continue; - - nouveau_connector_ddc_prepare(connector, &flags); - ret = i2c_transfer(&i2c->adapter, msgs, 2); - nouveau_connector_ddc_finish(connector, flags); -- + - if (ret == 2) { + if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { *pnv_encoder = nv_encoder; return i2c; } -@@ -234,21 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector) +@@ -234,21 +174,7 @@ nouveau_connector_detect(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_i2c_chan *i2c; @@ -1541,7 +2554,7 @@ index 149ed22..734e926 100644 /* Cleanup the previous EDID block. */ if (nv_connector->edid) { -@@ -259,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector) +@@ -259,9 +185,7 @@ nouveau_connector_detect(struct drm_connector *connector) i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { @@ -1551,7 +2564,7 @@ index 149ed22..734e926 100644 drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { -@@ -321,6 +249,85 @@ detect_analog: +@@ -321,6 +245,85 @@ detect_analog: return connector_status_disconnected; } @@ -1637,7 +2650,26 @@ index 149ed22..734e926 100644 static void nouveau_connector_force(struct drm_connector *connector) { -@@ -441,7 +448,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) +@@ -353,6 +356,7 @@ nouveau_connector_set_property(struct drm_connector *connector, + { + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; ++ struct drm_encoder *encoder = to_drm_encoder(nv_encoder); + struct drm_device *dev = connector->dev; + int ret; + +@@ -425,8 +429,8 @@ nouveau_connector_set_property(struct drm_connector *connector, + } + + if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) +- return get_slave_funcs(nv_encoder)-> +- set_property(to_drm_encoder(nv_encoder), connector, property, value); ++ return get_slave_funcs(encoder)->set_property( ++ encoder, connector, property, value); + + return -EINVAL; + } +@@ -441,7 +445,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) int high_w = 0, high_h = 0, high_v = 0; list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { @@ -1647,13 +2679,14 @@ index 149ed22..734e926 100644 continue; /* Use preferred mode if there is one.. */ -@@ -534,21 +542,27 @@ static int +@@ -534,21 +539,28 @@ static int nouveau_connector_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; ++ struct drm_encoder *encoder = to_drm_encoder(nv_encoder); int ret = 0; - /* If we're not LVDS, destroy the previous native mode, the attached @@ -1679,9 +2712,13 @@ index 149ed22..734e926 100644 /* Find the native mode if this is a digital panel, if we didn't * find any modes through DDC previously add the native mode to -@@ -569,7 +583,8 @@ nouveau_connector_get_modes(struct drm_connector *connector) - ret = get_slave_funcs(nv_encoder)-> - get_modes(to_drm_encoder(nv_encoder), connector); +@@ -566,10 +578,10 @@ nouveau_connector_get_modes(struct drm_connector *connector) + } + + if (nv_encoder->dcb->type == OUTPUT_TV) +- ret = get_slave_funcs(nv_encoder)-> +- get_modes(to_drm_encoder(nv_encoder), connector); ++ ret = get_slave_funcs(encoder)->get_modes(encoder, connector); - if (nv_encoder->dcb->type == OUTPUT_LVDS) + if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || @@ -1689,7 +2726,25 @@ index 149ed22..734e926 100644 ret += nouveau_connector_scaler_modes_add(connector); return ret; -@@ -643,6 +658,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) +@@ -582,6 +594,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; ++ struct drm_encoder *encoder = to_drm_encoder(nv_encoder); + unsigned min_clock = 25000, max_clock = min_clock; + unsigned clock = mode->clock; + +@@ -608,8 +621,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, + max_clock = 350000; + break; + case OUTPUT_TV: +- return get_slave_funcs(nv_encoder)-> +- mode_valid(to_drm_encoder(nv_encoder), mode); ++ return get_slave_funcs(encoder)->mode_valid(encoder, mode); + case OUTPUT_DP: + if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) + max_clock = nv_encoder->dp.link_nr * 270000; +@@ -643,6 +655,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } @@ -1734,7 +2789,7 @@ index 149ed22..734e926 100644 static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, -@@ -662,148 +715,74 @@ nouveau_connector_funcs = { +@@ -662,148 +712,74 @@ nouveau_connector_funcs = { .force = nouveau_connector_force }; @@ -1909,7 +2964,7 @@ index 149ed22..734e926 100644 nv_connector->dcb = dcb; connector = &nv_connector->base; -@@ -811,27 +790,21 @@ nouveau_connector_create(struct drm_device *dev, +@@ -811,27 +787,21 @@ nouveau_connector_create(struct drm_device *dev, connector->interlace_allowed = false; connector->doublescan_allowed = false; @@ -1948,7 +3003,7 @@ index 149ed22..734e926 100644 } /* Init DVI-I specific properties */ -@@ -841,12 +814,8 @@ nouveau_connector_create(struct drm_device *dev, +@@ -841,12 +811,8 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0); } @@ -1961,7 +3016,7 @@ index 149ed22..734e926 100644 if (dev_priv->card_type >= NV_50) { drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, -@@ -858,17 +827,6 @@ nouveau_connector_create(struct drm_device *dev, +@@ -858,17 +824,6 @@ nouveau_connector_create(struct drm_device *dev, case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; break; @@ -1979,7 +3034,7 @@ index 149ed22..734e926 100644 default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; -@@ -882,15 +840,15 @@ nouveau_connector_create(struct drm_device *dev, +@@ -882,15 +837,15 @@ nouveau_connector_create(struct drm_device *dev, break; } @@ -2040,15 +3095,30 @@ index 65c441a..2e3c6ca 100644 /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c -index deeb21c..184bc95 100644 +index deeb21c..8a1b188 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c -@@ -271,12 +271,26 @@ nouveau_dp_link_train(struct drm_encoder *encoder) +@@ -23,8 +23,10 @@ + */ + + #include "drmP.h" ++ + #include "nouveau_drv.h" + #include "nouveau_i2c.h" ++#include "nouveau_connector.h" + #include "nouveau_encoder.h" + + static int +@@ -270,13 +272,39 @@ bool + nouveau_dp_link_train(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - uint8_t config[4]; - uint8_t status[3]; ++ struct nouveau_connector *nv_connector; + struct bit_displayport_encoder_table *dpe; + int dpe_headerlen; + uint8_t config[4], status[3]; @@ -2057,12 +3127,21 @@ index deeb21c..184bc95 100644 NV_DEBUG_KMS(dev, "link training!!\n"); + ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (!nv_connector) ++ return false; ++ + dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); + if (!dpe) { + NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); + return false; + } + ++ /* disable hotplug detect, this flips around on some panels during ++ * link training. ++ */ ++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); ++ + if (dpe->script0) { + NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), @@ -2072,7 +3151,7 @@ index deeb21c..184bc95 100644 train: cr_done = eq_done = false; -@@ -403,6 +417,12 @@ stop: +@@ -403,6 +431,15 @@ stop: } } @@ -2081,12 +3160,115 @@ index deeb21c..184bc95 100644 + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), + nv_encoder->dcb); + } ++ ++ /* re-enable hotplug detect */ ++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); + return eq_done; } +@@ -535,47 +572,64 @@ out: + return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); + } + +-int +-nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, +- uint8_t write_byte, uint8_t *read_byte) ++static int ++nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + { +- struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; +- struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter; ++ struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; + struct drm_device *dev = auxch->dev; +- int ret = 0, cmd, addr = algo_data->address; +- uint8_t *buf; +- +- if (mode == MODE_I2C_READ) { +- cmd = AUX_I2C_READ; +- buf = read_byte; +- } else { +- cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE; +- buf = &write_byte; +- } ++ struct i2c_msg *msg = msgs; ++ int ret, mcnt = num; + +- if (!(mode & MODE_I2C_STOP)) +- cmd |= AUX_I2C_MOT; ++ while (mcnt--) { ++ u8 remaining = msg->len; ++ u8 *ptr = msg->buf; + +- if (mode & MODE_I2C_START) +- return 1; ++ while (remaining) { ++ u8 cnt = (remaining > 16) ? 16 : remaining; ++ u8 cmd; + +- for (;;) { +- ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1); +- if (ret < 0) +- return ret; +- +- switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { +- case NV50_AUXCH_STAT_REPLY_I2C_ACK: +- return 1; +- case NV50_AUXCH_STAT_REPLY_I2C_NACK: +- return -EREMOTEIO; +- case NV50_AUXCH_STAT_REPLY_I2C_DEFER: +- udelay(100); +- break; +- default: +- NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret); +- return -EREMOTEIO; ++ if (msg->flags & I2C_M_RD) ++ cmd = AUX_I2C_READ; ++ else ++ cmd = AUX_I2C_WRITE; ++ ++ if (mcnt || remaining > 16) ++ cmd |= AUX_I2C_MOT; ++ ++ ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt); ++ if (ret < 0) ++ return ret; ++ ++ switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { ++ case NV50_AUXCH_STAT_REPLY_I2C_ACK: ++ break; ++ case NV50_AUXCH_STAT_REPLY_I2C_NACK: ++ return -EREMOTEIO; ++ case NV50_AUXCH_STAT_REPLY_I2C_DEFER: ++ udelay(100); ++ continue; ++ default: ++ NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); ++ return -EREMOTEIO; ++ } ++ ++ ptr += cnt; ++ remaining -= cnt; + } ++ ++ msg++; + } ++ ++ return num; ++} ++ ++static u32 ++nouveau_dp_i2c_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + } + ++const struct i2c_algorithm nouveau_dp_i2c_algo = { ++ .master_xfer = nouveau_dp_i2c_xfer, ++ .functionality = nouveau_dp_i2c_func ++}; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c -index 2737704..203d0b6 100644 +index 2737704..a8d3d17 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -35,10 +35,6 @@ @@ -2129,7 +3311,21 @@ index 2737704..203d0b6 100644 nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "We're back, enabling device...\n"); -@@ -323,7 +313,6 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev) + return -1; + pci_set_master(dev->pdev); + ++ /* Make sure the AGP controller is in a consistent state */ ++ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) ++ nouveau_mem_reset_agp(dev); ++ ++ /* Make the CRTCs accessible */ ++ engine->display.early_init(dev); ++ + NV_INFO(dev, "POSTing device...\n"); + ret = nouveau_run_vbios_init(dev); + if (ret) +@@ -323,7 +320,6 @@ nouveau_pci_resume(struct pci_dev *pdev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); @@ -2137,20 +3333,20 @@ index 2737704..203d0b6 100644 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) -@@ -332,10 +321,9 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -332,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev) NV_ERROR(dev, "Could not pin/map cursor.\n"); } - if (dev_priv->card_type < NV_50) { -+ if (dev_priv->card_type < NV_50) - nv04_display_restore(dev); +- nv04_display_restore(dev); - NVLockVgaCrtcs(dev, false); - } else -+ else - nv50_display_init(dev); +- nv50_display_init(dev); ++ engine->display.init(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -@@ -371,7 +359,8 @@ nouveau_pci_resume(struct pci_dev *pdev) + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); +@@ -371,7 +363,8 @@ nouveau_pci_resume(struct pci_dev *pdev) static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | @@ -2160,7 +3356,7 @@ index 2737704..203d0b6 100644 .load = nouveau_load, .firstopen = nouveau_firstopen, .lastclose = nouveau_lastclose, -@@ -438,16 +427,18 @@ static int __init nouveau_init(void) +@@ -438,16 +431,18 @@ static int __init nouveau_init(void) nouveau_modeset = 1; } @@ -2184,7 +3380,7 @@ index 2737704..203d0b6 100644 nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index c697191..20ca5b8 100644 +index c697191..c001574 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) @@ -2276,7 +3472,55 @@ index c697191..20ca5b8 100644 int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); -@@ -500,11 +493,6 @@ enum nouveau_card_type { +@@ -358,6 +351,24 @@ struct nouveau_pgraph_engine { + uint32_t size, uint32_t pitch); + }; + ++struct nouveau_display_engine { ++ int (*early_init)(struct drm_device *); ++ void (*late_takedown)(struct drm_device *); ++ int (*create)(struct drm_device *); ++ int (*init)(struct drm_device *); ++ void (*destroy)(struct drm_device *); ++}; ++ ++struct nouveau_gpio_engine { ++ int (*init)(struct drm_device *); ++ void (*takedown)(struct drm_device *); ++ ++ int (*get)(struct drm_device *, enum dcb_gpio_tag); ++ int (*set)(struct drm_device *, enum dcb_gpio_tag, int state); ++ ++ void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); ++}; ++ + struct nouveau_engine { + struct nouveau_instmem_engine instmem; + struct nouveau_mc_engine mc; +@@ -365,6 +376,8 @@ struct nouveau_engine { + struct nouveau_fb_engine fb; + struct nouveau_pgraph_engine graph; + struct nouveau_fifo_engine fifo; ++ struct nouveau_display_engine display; ++ struct nouveau_gpio_engine gpio; + }; + + struct nouveau_pll_vals { +@@ -397,7 +410,7 @@ enum nv04_fp_display_regs { + + struct nv04_crtc_reg { + unsigned char MiscOutReg; /* */ +- uint8_t CRTC[0x9f]; ++ uint8_t CRTC[0xa0]; + uint8_t CR58[0x10]; + uint8_t Sequencer[5]; + uint8_t Graphics[9]; +@@ -496,15 +509,11 @@ enum nouveau_card_type { + NV_30 = 0x30, + NV_40 = 0x40, + NV_50 = 0x50, ++ NV_C0 = 0xc0, + }; struct drm_nouveau_private { struct drm_device *dev; @@ -2288,7 +3532,12 @@ index c697191..20ca5b8 100644 /* the card type, takes NV_* as values */ enum nouveau_card_type card_type; -@@ -533,8 +521,6 @@ struct drm_nouveau_private { +@@ -528,13 +537,9 @@ struct drm_nouveau_private { + struct ttm_global_reference mem_global_ref; + struct ttm_bo_global_ref bo_global_ref; + struct ttm_bo_device bdev; +- spinlock_t bo_list_lock; +- struct list_head bo_list; atomic_t validate_sequence; } ttm; @@ -2297,7 +3546,7 @@ index c697191..20ca5b8 100644 int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; -@@ -595,11 +581,7 @@ struct drm_nouveau_private { +@@ -595,11 +600,7 @@ struct drm_nouveau_private { struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; @@ -2310,7 +3559,7 @@ index c697191..20ca5b8 100644 struct list_head gpuobj_list; -@@ -618,6 +600,11 @@ struct drm_nouveau_private { +@@ -618,6 +619,11 @@ struct drm_nouveau_private { struct backlight_device *backlight; struct nouveau_channel *evo; @@ -2322,7 +3571,7 @@ index c697191..20ca5b8 100644 struct { struct dentry *channel_root; -@@ -652,14 +639,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) +@@ -652,14 +658,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) return 0; } @@ -2337,7 +3586,7 @@ index c697191..20ca5b8 100644 #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (!nouveau_channel_owner(dev, (cl), (id))) { \ -@@ -682,7 +661,6 @@ extern int nouveau_tv_disable; +@@ -682,7 +680,6 @@ extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; @@ -2345,7 +3594,7 @@ index c697191..20ca5b8 100644 extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; -@@ -707,15 +685,7 @@ extern bool nouveau_wait_for_idle(struct drm_device *); +@@ -707,17 +704,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ @@ -2360,8 +3609,11 @@ index c697191..20ca5b8 100644 -extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); ++extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); -@@ -857,11 +827,13 @@ void nouveau_register_dsm_handler(void); + extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, + uint32_t addr, +@@ -857,11 +847,13 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); @@ -2371,11 +3623,54 @@ index c697191..20ca5b8 100644 static inline void nouveau_unregister_dsm_handler(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } -+static inline int nouveau_acpi_edid(struct drm_device *, struct drm_connector *) { return -EINVAL; } ++static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } #endif /* nouveau_backlight.c */ -@@ -1035,12 +1007,6 @@ extern int nv50_graph_unload_context(struct drm_device *); +@@ -924,6 +916,10 @@ extern void nv10_fb_takedown(struct drm_device *); + extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); + ++/* nv30_fb.c */ ++extern int nv30_fb_init(struct drm_device *); ++extern void nv30_fb_takedown(struct drm_device *); ++ + /* nv40_fb.c */ + extern int nv40_fb_init(struct drm_device *); + extern void nv40_fb_takedown(struct drm_device *); +@@ -934,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, + extern int nv50_fb_init(struct drm_device *); + extern void nv50_fb_takedown(struct drm_device *); + ++/* nvc0_fb.c */ ++extern int nvc0_fb_init(struct drm_device *); ++extern void nvc0_fb_takedown(struct drm_device *); ++ + /* nv04_fifo.c */ + extern int nv04_fifo_init(struct drm_device *); + extern void nv04_fifo_disable(struct drm_device *); +@@ -971,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); + extern int nv50_fifo_load_context(struct nouveau_channel *); + extern int nv50_fifo_unload_context(struct drm_device *); + ++/* nvc0_fifo.c */ ++extern int nvc0_fifo_init(struct drm_device *); ++extern void nvc0_fifo_takedown(struct drm_device *); ++extern void nvc0_fifo_disable(struct drm_device *); ++extern void nvc0_fifo_enable(struct drm_device *); ++extern bool nvc0_fifo_reassign(struct drm_device *, bool); ++extern bool nvc0_fifo_cache_flush(struct drm_device *); ++extern bool nvc0_fifo_cache_pull(struct drm_device *, bool); ++extern int nvc0_fifo_channel_id(struct drm_device *); ++extern int nvc0_fifo_create_context(struct nouveau_channel *); ++extern void nvc0_fifo_destroy_context(struct nouveau_channel *); ++extern int nvc0_fifo_load_context(struct nouveau_channel *); ++extern int nvc0_fifo_unload_context(struct drm_device *); ++ + /* nv04_graph.c */ + extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; + extern int nv04_graph_init(struct drm_device *); +@@ -1035,11 +1049,15 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); @@ -2384,11 +3679,19 @@ index c697191..20ca5b8 100644 -extern void nouveau_grctx_vals_load(struct drm_device *, - struct nouveau_gpuobj *); -extern void nouveau_grctx_fini(struct drm_device *); -- ++/* nvc0_graph.c */ ++extern int nvc0_graph_init(struct drm_device *); ++extern void nvc0_graph_takedown(struct drm_device *); ++extern void nvc0_graph_fifo_access(struct drm_device *, bool); ++extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *); ++extern int nvc0_graph_create_context(struct nouveau_channel *); ++extern void nvc0_graph_destroy_context(struct nouveau_channel *); ++extern int nvc0_graph_load_context(struct nouveau_channel *); ++extern int nvc0_graph_unload_context(struct drm_device *); + /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); - extern void nv04_instmem_takedown(struct drm_device *); -@@ -1051,8 +1017,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1051,8 +1069,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -2398,7 +3701,7 @@ index c697191..20ca5b8 100644 /* nv50_instmem.c */ extern int nv50_instmem_init(struct drm_device *); -@@ -1064,8 +1029,9 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1064,8 +1081,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -2407,10 +3710,22 @@ index c697191..20ca5b8 100644 +extern void nv50_instmem_flush(struct drm_device *); +extern void nv84_instmem_flush(struct drm_device *); +extern void nv50_vm_flush(struct drm_device *, int engine); ++ ++/* nvc0_instmem.c */ ++extern int nvc0_instmem_init(struct drm_device *); ++extern void nvc0_instmem_takedown(struct drm_device *); ++extern int nvc0_instmem_suspend(struct drm_device *); ++extern void nvc0_instmem_resume(struct drm_device *); ++extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, ++ uint32_t *size); ++extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); ++extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); ++extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); ++extern void nvc0_instmem_flush(struct drm_device *); /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); -@@ -1088,13 +1054,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, +@@ -1088,13 +1118,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nv04_dac.c */ @@ -2427,7 +3742,7 @@ index c697191..20ca5b8 100644 extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, int head, bool dl); -@@ -1103,10 +1070,10 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); +@@ -1103,15 +1134,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); /* nv04_tv.c */ extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); @@ -2439,8 +3754,16 @@ index c697191..20ca5b8 100644 +extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *); /* nv04_display.c */ ++extern int nv04_display_early_init(struct drm_device *); ++extern void nv04_display_late_takedown(struct drm_device *); extern int nv04_display_create(struct drm_device *); -@@ -1147,7 +1114,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); ++extern int nv04_display_init(struct drm_device *); + extern void nv04_display_destroy(struct drm_device *); +-extern void nv04_display_restore(struct drm_device *); + + /* nv04_crtc.c */ + extern int nv04_crtc_create(struct drm_device *, int index); +@@ -1147,7 +1180,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); extern int nouveau_fence_flush(void *obj, void *arg); extern void nouveau_fence_unref(void **obj); extern void *nouveau_fence_ref(void *obj); @@ -2448,8 +3771,42 @@ index c697191..20ca5b8 100644 /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, +@@ -1167,13 +1199,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, + extern int nouveau_gem_ioctl_info(struct drm_device *, void *, + struct drm_file *); + +-/* nv17_gpio.c */ +-int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); +-int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); ++/* nv10_gpio.c */ ++int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); ++int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); + + /* nv50_gpio.c */ ++int nv50_gpio_init(struct drm_device *dev); + int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); + int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); ++void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); + + /* nv50_calc. */ + int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, +@@ -1220,6 +1254,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) + iowrite32_native(val, dev_priv->mmio + reg); + } + ++static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val) ++{ ++ u32 tmp = nv_rd32(dev, reg); ++ tmp &= ~mask; ++ tmp |= val; ++ nv_wr32(dev, reg, tmp); ++} ++ + static inline u8 nv_rd08(struct drm_device *dev, unsigned reg) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h -index e1df820..a1a0d48 100644 +index e1df820..7c82d68 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -38,13 +38,15 @@ struct nouveau_encoder { @@ -2470,8 +3827,16 @@ index e1df820..a1a0d48 100644 union { struct { int mc_unknown; -@@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) +@@ -69,10 +71,16 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) + return &enc->base.base; + } ++static inline struct drm_encoder_slave_funcs * ++get_slave_funcs(struct drm_encoder *enc) ++{ ++ return to_encoder_slave(enc)->slave_funcs; ++} ++ struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); -int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry); @@ -2482,10 +3847,19 @@ index e1df820..a1a0d48 100644 struct bit_displayport_encoder_table { uint32_t match; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c -index 257ea13..2fb2444 100644 +index 257ea13..11f13fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c -@@ -333,7 +333,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) +@@ -280,6 +280,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, + + if (dev_priv->channel && !nouveau_nofbaccel) { + switch (dev_priv->card_type) { ++ case NV_C0: ++ break; + case NV_50: + nv50_fbcon_accel_init(info); + info->fbops = &nv50_fbcon_ops; +@@ -333,7 +335,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper); } @@ -2495,7 +3869,7 @@ index 257ea13..2fb2444 100644 { struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c -index faddf53..813d853 100644 +index faddf53..6b208ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan) @@ -2566,6 +3940,24 @@ index faddf53..813d853 100644 return fence->signalled; } +@@ -190,8 +186,6 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) + unsigned long timeout = jiffies + (3 * DRM_HZ); + int ret = 0; + +- __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); +- + while (1) { + if (nouveau_fence_signalled(sync_obj, sync_arg)) + break; +@@ -201,6 +195,8 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) + break; + } + ++ __set_current_state(intr ? TASK_INTERRUPTIBLE ++ : TASK_UNINTERRUPTIBLE); + if (lazy) + schedule_timeout(1); + @@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg) return 0; } @@ -2813,23 +4205,137 @@ index f731c5f..0000000 - nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset), - le32_to_cpu(cv->data[i].value)); -} +diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c +index 7855b35..7b61368 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_hw.c ++++ b/drivers/gpu/drm/nouveau/nouveau_hw.c +@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head, + rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); + rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); + rd_cio_state(dev, head, regp, NV_CIO_CRE_21); +- if (dev_priv->card_type >= NV_30) ++ ++ if (dev_priv->card_type >= NV_30) { + rd_cio_state(dev, head, regp, NV_CIO_CRE_47); ++ rd_cio_state(dev, head, regp, 0x9f); ++ } ++ + rd_cio_state(dev, head, regp, NV_CIO_CRE_49); + rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); + rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); +@@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head, + wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); + wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); + wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); +- if (dev_priv->card_type >= NV_30) ++ ++ if (dev_priv->card_type >= NV_30) { + wr_cio_state(dev, head, regp, NV_CIO_CRE_47); ++ wr_cio_state(dev, head, regp, 0x9f); ++ } + + wr_cio_state(dev, head, regp, NV_CIO_CRE_49); + wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c -index 316a3c7..97ba89e 100644 +index 316a3c7..8461485 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c -@@ -278,3 +278,37 @@ nouveau_i2c_find(struct drm_device *dev, int index) +@@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) + if (entry->chan) + return -EEXIST; + +- if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) { ++ if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { + NV_ERROR(dev, "unknown i2c port %d\n", entry->read); + return -EINVAL; + } +@@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) + + switch (entry->port_type) { + case 0: +- i2c->algo.bit.setsda = nv04_i2c_setsda; +- i2c->algo.bit.setscl = nv04_i2c_setscl; +- i2c->algo.bit.getsda = nv04_i2c_getsda; +- i2c->algo.bit.getscl = nv04_i2c_getscl; ++ i2c->bit.setsda = nv04_i2c_setsda; ++ i2c->bit.setscl = nv04_i2c_setscl; ++ i2c->bit.getsda = nv04_i2c_getsda; ++ i2c->bit.getscl = nv04_i2c_getscl; + i2c->rd = entry->read; + i2c->wr = entry->write; + break; + case 4: +- i2c->algo.bit.setsda = nv4e_i2c_setsda; +- i2c->algo.bit.setscl = nv4e_i2c_setscl; +- i2c->algo.bit.getsda = nv4e_i2c_getsda; +- i2c->algo.bit.getscl = nv4e_i2c_getscl; ++ i2c->bit.setsda = nv4e_i2c_setsda; ++ i2c->bit.setscl = nv4e_i2c_setscl; ++ i2c->bit.getsda = nv4e_i2c_getsda; ++ i2c->bit.getscl = nv4e_i2c_getscl; + i2c->rd = 0x600800 + entry->read; + i2c->wr = 0x600800 + entry->write; + break; + case 5: +- i2c->algo.bit.setsda = nv50_i2c_setsda; +- i2c->algo.bit.setscl = nv50_i2c_setscl; +- i2c->algo.bit.getsda = nv50_i2c_getsda; +- i2c->algo.bit.getscl = nv50_i2c_getscl; ++ i2c->bit.setsda = nv50_i2c_setsda; ++ i2c->bit.setscl = nv50_i2c_setscl; ++ i2c->bit.getsda = nv50_i2c_getsda; ++ i2c->bit.getscl = nv50_i2c_getscl; + i2c->rd = nv50_i2c_port[entry->read]; + i2c->wr = i2c->rd; + break; +@@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) + i2c_set_adapdata(&i2c->adapter, i2c); + + if (entry->port_type < 6) { +- i2c->adapter.algo_data = &i2c->algo.bit; +- i2c->algo.bit.udelay = 40; +- i2c->algo.bit.timeout = usecs_to_jiffies(5000); +- i2c->algo.bit.data = i2c; ++ i2c->adapter.algo_data = &i2c->bit; ++ i2c->bit.udelay = 40; ++ i2c->bit.timeout = usecs_to_jiffies(5000); ++ i2c->bit.data = i2c; + ret = i2c_bit_add_bus(&i2c->adapter); + } else { +- i2c->adapter.algo_data = &i2c->algo.dp; +- i2c->algo.dp.running = false; +- i2c->algo.dp.address = 0; +- i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch; +- ret = i2c_dp_aux_add_bus(&i2c->adapter); ++ i2c->adapter.algo = &nouveau_dp_i2c_algo; ++ ret = i2c_add_adapter(&i2c->adapter); + } + + if (ret) { +@@ -278,3 +275,45 @@ nouveau_i2c_find(struct drm_device *dev, int index) return i2c->chan; } +bool +nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr) +{ -+ struct i2c_msg msg = { -+ .addr = addr, -+ .len = 0, ++ uint8_t buf[] = { 0 }; ++ struct i2c_msg msgs[] = { ++ { ++ .addr = addr, ++ .flags = 0, ++ .len = 1, ++ .buf = buf, ++ }, ++ { ++ .addr = addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = buf, ++ } + }; + -+ return i2c_transfer(&i2c->adapter, &msg, 1) == 1; ++ return i2c_transfer(&i2c->adapter, msgs, 2) == 2; +} + +int @@ -2837,29 +4343,38 @@ index 316a3c7..97ba89e 100644 + struct i2c_board_info *info, int index) +{ + struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index); -+ int was_locked, i; ++ int i; + -+ was_locked = NVLockVgaCrtcs(dev, false); + NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); + + for (i = 0; info[i].addr; i++) { + if (nouveau_probe_i2c_addr(i2c, info[i].addr)) { + NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); -+ goto out; ++ return i; + } + } + + NV_DEBUG(dev, "No devices found.\n"); -+out: -+ NVLockVgaCrtcs(dev, was_locked); + -+ return info[i].addr ? i : -ENODEV; ++ return -ENODEV; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h -index c8eaf7a..6dd2f87 100644 +index c8eaf7a..f71cb32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h -@@ -45,6 +45,9 @@ struct nouveau_i2c_chan { +@@ -33,10 +33,7 @@ struct dcb_i2c_entry; + struct nouveau_i2c_chan { + struct i2c_adapter adapter; + struct drm_device *dev; +- union { +- struct i2c_algo_bit_data bit; +- struct i2c_algo_dp_aux_data dp; +- } algo; ++ struct i2c_algo_bit_data bit; + unsigned rd; + unsigned wr; + unsigned data; +@@ -45,8 +42,10 @@ struct nouveau_i2c_chan { int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); @@ -2867,10 +4382,40 @@ index c8eaf7a..6dd2f87 100644 +int nouveau_i2c_identify(struct drm_device *dev, const char *what, + struct i2c_board_info *info, int index); - int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, - uint8_t *read_byte); +-int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, +- uint8_t *read_byte); ++extern const struct i2c_algorithm nouveau_dp_i2c_algo; + + #endif /* __NOUVEAU_I2C_H__ */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c +index 53360f1..794b0ee 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_irq.c ++++ b/drivers/gpu/drm/nouveau/nouveau_irq.c +@@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev) + /* Master disable */ + nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); + +- if (dev_priv->card_type == NV_50) { ++ if (dev_priv->card_type >= NV_50) { + INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); + INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); + INIT_LIST_HEAD(&dev_priv->vbl_waiting); +@@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) + } + + if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { +- nouveau_pgraph_intr_context_switch(dev); +- + status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + nv_wr32(dev, NV03_PGRAPH_INTR, + NV_PGRAPH_INTR_CONTEXT_SWITCH); ++ ++ nouveau_pgraph_intr_context_switch(dev); + } + + if (status) { diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c -index c1fd42b..adf5ac4 100644 +index c1fd42b..db442c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -35,162 +35,6 @@ @@ -3207,18 +4752,20 @@ index c1fd42b..adf5ac4 100644 return 4 * 1024 * 1024; } -@@ -536,12 +315,18 @@ nouveau_mem_detect(struct drm_device *dev) +@@ -536,12 +315,22 @@ nouveau_mem_detect(struct drm_device *dev) } else if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { dev_priv->vram_size = nouveau_mem_detect_nforce(dev); +- } else { +- dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); +- dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; +- if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) + } else + if (dev_priv->card_type < NV_50) { + dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); + dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; - } else { -- dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); -- dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; -- if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) ++ } else ++ if (dev_priv->card_type < NV_C0) { + dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); + dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; + dev_priv->vram_size &= 0xffffffff00ll; @@ -3226,9 +4773,109 @@ index c1fd42b..adf5ac4 100644 dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); dev_priv->vram_sys_base <<= 12; + } ++ } else { ++ dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; ++ dev_priv->vram_size *= nv_rd32(dev, 0x121c74); } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); +@@ -555,18 +344,36 @@ nouveau_mem_detect(struct drm_device *dev) + return -ENOMEM; + } + +-#if __OS_HAS_AGP +-static void nouveau_mem_reset_agp(struct drm_device *dev) ++int ++nouveau_mem_reset_agp(struct drm_device *dev) + { +- uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable; ++#if __OS_HAS_AGP ++ uint32_t saved_pci_nv_1, pmc_enable; ++ int ret; ++ ++ /* First of all, disable fast writes, otherwise if it's ++ * already enabled in the AGP bridge and we disable the card's ++ * AGP controller we might be locking ourselves out of it. */ ++ if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) { ++ struct drm_agp_info info; ++ struct drm_agp_mode mode; ++ ++ ret = drm_agp_info(dev, &info); ++ if (ret) ++ return ret; ++ ++ mode.mode = info.mode & ~PCI_AGP_COMMAND_FW; ++ ret = drm_agp_enable(dev, mode); ++ if (ret) ++ return ret; ++ } + + saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1); +- saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19); + + /* clear busmaster bit */ + nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4); +- /* clear SBA and AGP bits */ +- nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff); ++ /* disable AGP */ ++ nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0); + + /* power cycle pgraph, if enabled */ + pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); +@@ -578,11 +385,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) + } + + /* and restore (gives effect of resetting AGP) */ +- nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19); + nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1); +-} + #endif + ++ return 0; ++} ++ + int + nouveau_mem_init_agp(struct drm_device *dev) + { +@@ -592,11 +400,6 @@ nouveau_mem_init_agp(struct drm_device *dev) + struct drm_agp_mode mode; + int ret; + +- if (nouveau_noagp) +- return 0; +- +- nouveau_mem_reset_agp(dev); +- + if (!dev->agp->acquired) { + ret = drm_agp_acquire(dev); + if (ret) { +@@ -605,6 +408,8 @@ nouveau_mem_init_agp(struct drm_device *dev) + } + } + ++ nouveau_mem_reset_agp(dev); ++ + ret = drm_agp_info(dev, &info); + if (ret) { + NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); +@@ -659,8 +464,6 @@ nouveau_mem_init(struct drm_device *dev) + return ret; + } + +- INIT_LIST_HEAD(&dev_priv->ttm.bo_list); +- spin_lock_init(&dev_priv->ttm.bo_list_lock); + spin_lock_init(&dev_priv->tile.lock); + + dev_priv->fb_available_size = dev_priv->vram_size; +@@ -692,7 +495,7 @@ nouveau_mem_init(struct drm_device *dev) + + /* GART */ + #if !defined(__powerpc__) && !defined(__ia64__) +- if (drm_device_is_agp(dev) && dev->agp) { ++ if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { + ret = nouveau_mem_init_agp(dev); + if (ret) + NV_ERROR(dev, "Error initialising AGP: %d\n", ret); diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 9537f3e..3ec181f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -3671,7 +5318,7 @@ index e7c100b..4bf6b33 100644 ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h -index 6ca80a3..9c1056c 100644 +index 6ca80a3..21a6e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -1,19 +1,64 @@ @@ -3777,7 +5424,53 @@ index 6ca80a3..9c1056c 100644 #define NV04_PGRAPH_DEBUG_0 0x00400080 #define NV04_PGRAPH_DEBUG_1 0x00400084 #define NV04_PGRAPH_DEBUG_2 0x00400088 -@@ -814,6 +842,7 @@ +@@ -192,28 +220,21 @@ + # define NV_PGRAPH_INTR_ERROR (1<<20) + #define NV10_PGRAPH_CTX_CONTROL 0x00400144 + #define NV10_PGRAPH_CTX_USER 0x00400148 +-#define NV10_PGRAPH_CTX_SWITCH1 0x0040014C +-#define NV10_PGRAPH_CTX_SWITCH2 0x00400150 +-#define NV10_PGRAPH_CTX_SWITCH3 0x00400154 +-#define NV10_PGRAPH_CTX_SWITCH4 0x00400158 +-#define NV10_PGRAPH_CTX_SWITCH5 0x0040015C ++#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i)) + #define NV04_PGRAPH_CTX_SWITCH1 0x00400160 +-#define NV10_PGRAPH_CTX_CACHE1 0x00400160 ++#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \ ++ + 0x4*(i) + 0x20*(j)) + #define NV04_PGRAPH_CTX_SWITCH2 0x00400164 + #define NV04_PGRAPH_CTX_SWITCH3 0x00400168 + #define NV04_PGRAPH_CTX_SWITCH4 0x0040016C + #define NV04_PGRAPH_CTX_CONTROL 0x00400170 + #define NV04_PGRAPH_CTX_USER 0x00400174 + #define NV04_PGRAPH_CTX_CACHE1 0x00400180 +-#define NV10_PGRAPH_CTX_CACHE2 0x00400180 + #define NV03_PGRAPH_CTX_CONTROL 0x00400190 + #define NV03_PGRAPH_CTX_USER 0x00400194 + #define NV04_PGRAPH_CTX_CACHE2 0x004001A0 +-#define NV10_PGRAPH_CTX_CACHE3 0x004001A0 + #define NV04_PGRAPH_CTX_CACHE3 0x004001C0 +-#define NV10_PGRAPH_CTX_CACHE4 0x004001C0 + #define NV04_PGRAPH_CTX_CACHE4 0x004001E0 +-#define NV10_PGRAPH_CTX_CACHE5 0x004001E0 + #define NV40_PGRAPH_CTXCTL_0304 0x00400304 + #define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001 + #define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308 +@@ -328,9 +349,12 @@ + #define NV04_PGRAPH_FFINTFC_ST2 0x00400754 + #define NV10_PGRAPH_RDI_DATA 0x00400754 + #define NV04_PGRAPH_DMA_PITCH 0x00400760 +-#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 ++#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760 + #define NV04_PGRAPH_DVD_COLORFMT 0x00400764 ++#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 + #define NV04_PGRAPH_SCALED_FORMAT 0x00400768 ++#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768 ++#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c + #define NV10_PGRAPH_DMA_PITCH 0x00400770 + #define NV10_PGRAPH_DVD_COLORFMT 0x00400774 + #define NV10_PGRAPH_SCALED_FORMAT 0x00400778 +@@ -814,6 +838,7 @@ #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff #define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) @@ -3894,10 +5587,18 @@ index 1d6ee8b..491767f 100644 } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c -index b02a231..621e080 100644 +index b02a231..989322b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c -@@ -54,8 +54,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -38,6 +38,7 @@ + #include "nv50_display.h" + + static void nouveau_stub_takedown(struct drm_device *dev) {} ++static int nouveau_stub_init(struct drm_device *dev) { return 0; } + + static int nouveau_init_engine_ptrs(struct drm_device *dev) + { +@@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -3907,7 +5608,24 @@ index b02a231..621e080 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -95,8 +94,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv04_fifo_destroy_context; + engine->fifo.load_context = nv04_fifo_load_context; + engine->fifo.unload_context = nv04_fifo_unload_context; ++ engine->display.early_init = nv04_display_early_init; ++ engine->display.late_takedown = nv04_display_late_takedown; ++ engine->display.create = nv04_display_create; ++ engine->display.init = nv04_display_init; ++ engine->display.destroy = nv04_display_destroy; ++ engine->gpio.init = nouveau_stub_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = NULL; ++ engine->gpio.set = NULL; ++ engine->gpio.irq_enable = NULL; + break; + case 0x10: + engine->instmem.init = nv04_instmem_init; +@@ -95,8 +105,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -3917,7 +5635,24 @@ index b02a231..621e080 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -138,8 +136,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.unload_context = nv10_fifo_unload_context; ++ engine->display.early_init = nv04_display_early_init; ++ engine->display.late_takedown = nv04_display_late_takedown; ++ engine->display.create = nv04_display_create; ++ engine->display.init = nv04_display_init; ++ engine->display.destroy = nv04_display_destroy; ++ engine->gpio.init = nouveau_stub_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv10_gpio_get; ++ engine->gpio.set = nv10_gpio_set; ++ engine->gpio.irq_enable = NULL; + break; + case 0x20: + engine->instmem.init = nv04_instmem_init; +@@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -3927,7 +5662,24 @@ index b02a231..621e080 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -181,8 +178,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.unload_context = nv10_fifo_unload_context; ++ engine->display.early_init = nv04_display_early_init; ++ engine->display.late_takedown = nv04_display_late_takedown; ++ engine->display.create = nv04_display_create; ++ engine->display.init = nv04_display_init; ++ engine->display.destroy = nv04_display_destroy; ++ engine->gpio.init = nouveau_stub_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv10_gpio_get; ++ engine->gpio.set = nv10_gpio_set; ++ engine->gpio.irq_enable = NULL; + break; + case 0x30: + engine->instmem.init = nv04_instmem_init; +@@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -3937,7 +5689,33 @@ index b02a231..621e080 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -225,8 +221,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->timer.read = nv04_timer_read; + engine->timer.takedown = nv04_timer_takedown; +- engine->fb.init = nv10_fb_init; +- engine->fb.takedown = nv10_fb_takedown; ++ engine->fb.init = nv30_fb_init; ++ engine->fb.takedown = nv30_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; + engine->graph.grclass = nv30_graph_grclass; + engine->graph.init = nv30_graph_init; +@@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.unload_context = nv10_fifo_unload_context; ++ engine->display.early_init = nv04_display_early_init; ++ engine->display.late_takedown = nv04_display_late_takedown; ++ engine->display.create = nv04_display_create; ++ engine->display.init = nv04_display_init; ++ engine->display.destroy = nv04_display_destroy; ++ engine->gpio.init = nouveau_stub_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv10_gpio_get; ++ engine->gpio.set = nv10_gpio_set; ++ engine->gpio.irq_enable = NULL; + break; + case 0x40: + case 0x60: +@@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -3947,7 +5725,24 @@ index b02a231..621e080 100644 engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -271,8 +266,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv40_fifo_destroy_context; + engine->fifo.load_context = nv40_fifo_load_context; + engine->fifo.unload_context = nv40_fifo_unload_context; ++ engine->display.early_init = nv04_display_early_init; ++ engine->display.late_takedown = nv04_display_late_takedown; ++ engine->display.create = nv04_display_create; ++ engine->display.init = nv04_display_init; ++ engine->display.destroy = nv04_display_destroy; ++ engine->gpio.init = nouveau_stub_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv10_gpio_get; ++ engine->gpio.set = nv10_gpio_set; ++ engine->gpio.irq_enable = NULL; + break; + case 0x50: + case 0x80: /* gotta love NVIDIA's consistency.. */ +@@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv50_instmem_clear; engine->instmem.bind = nv50_instmem_bind; engine->instmem.unbind = nv50_instmem_unbind; @@ -3960,7 +5755,72 @@ index b02a231..621e080 100644 engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -407,11 +404,6 @@ nouveau_card_init(struct drm_device *dev) +@@ -300,6 +348,64 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv50_fifo_destroy_context; + engine->fifo.load_context = nv50_fifo_load_context; + engine->fifo.unload_context = nv50_fifo_unload_context; ++ engine->display.early_init = nv50_display_early_init; ++ engine->display.late_takedown = nv50_display_late_takedown; ++ engine->display.create = nv50_display_create; ++ engine->display.init = nv50_display_init; ++ engine->display.destroy = nv50_display_destroy; ++ engine->gpio.init = nv50_gpio_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv50_gpio_get; ++ engine->gpio.set = nv50_gpio_set; ++ engine->gpio.irq_enable = nv50_gpio_irq_enable; ++ break; ++ case 0xC0: ++ engine->instmem.init = nvc0_instmem_init; ++ engine->instmem.takedown = nvc0_instmem_takedown; ++ engine->instmem.suspend = nvc0_instmem_suspend; ++ engine->instmem.resume = nvc0_instmem_resume; ++ engine->instmem.populate = nvc0_instmem_populate; ++ engine->instmem.clear = nvc0_instmem_clear; ++ engine->instmem.bind = nvc0_instmem_bind; ++ engine->instmem.unbind = nvc0_instmem_unbind; ++ engine->instmem.flush = nvc0_instmem_flush; ++ engine->mc.init = nv50_mc_init; ++ engine->mc.takedown = nv50_mc_takedown; ++ engine->timer.init = nv04_timer_init; ++ engine->timer.read = nv04_timer_read; ++ engine->timer.takedown = nv04_timer_takedown; ++ engine->fb.init = nvc0_fb_init; ++ engine->fb.takedown = nvc0_fb_takedown; ++ engine->graph.grclass = NULL; //nvc0_graph_grclass; ++ engine->graph.init = nvc0_graph_init; ++ engine->graph.takedown = nvc0_graph_takedown; ++ engine->graph.fifo_access = nvc0_graph_fifo_access; ++ engine->graph.channel = nvc0_graph_channel; ++ engine->graph.create_context = nvc0_graph_create_context; ++ engine->graph.destroy_context = nvc0_graph_destroy_context; ++ engine->graph.load_context = nvc0_graph_load_context; ++ engine->graph.unload_context = nvc0_graph_unload_context; ++ engine->fifo.channels = 128; ++ engine->fifo.init = nvc0_fifo_init; ++ engine->fifo.takedown = nvc0_fifo_takedown; ++ engine->fifo.disable = nvc0_fifo_disable; ++ engine->fifo.enable = nvc0_fifo_enable; ++ engine->fifo.reassign = nvc0_fifo_reassign; ++ engine->fifo.channel_id = nvc0_fifo_channel_id; ++ engine->fifo.create_context = nvc0_fifo_create_context; ++ engine->fifo.destroy_context = nvc0_fifo_destroy_context; ++ engine->fifo.load_context = nvc0_fifo_load_context; ++ engine->fifo.unload_context = nvc0_fifo_unload_context; ++ engine->display.early_init = nv50_display_early_init; ++ engine->display.late_takedown = nv50_display_late_takedown; ++ engine->display.create = nv50_display_create; ++ engine->display.init = nv50_display_init; ++ engine->display.destroy = nv50_display_destroy; ++ engine->gpio.init = nv50_gpio_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nv50_gpio_get; ++ engine->gpio.set = nv50_gpio_set; ++ engine->gpio.irq_enable = nv50_gpio_irq_enable; + break; + default: + NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); +@@ -407,11 +513,6 @@ nouveau_card_init(struct drm_device *dev) struct nouveau_engine *engine; int ret; @@ -3972,13 +5832,18 @@ index b02a231..621e080 100644 vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, nouveau_switcheroo_can_switch); -@@ -421,15 +413,12 @@ nouveau_card_init(struct drm_device *dev) +@@ -421,15 +522,17 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out; engine = &dev_priv->engine; - dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; spin_lock_init(&dev_priv->context_switch_lock); ++ /* Make the CRTCs and I2C buses accessible */ ++ ret = engine->display.early_init(dev); ++ if (ret) ++ goto out; ++ /* Parse BIOS tables / Run init tables if card not POSTed */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = nouveau_bios_init(dev); @@ -3987,18 +5852,32 @@ index b02a231..621e080 100644 - } + ret = nouveau_bios_init(dev); + if (ret) -+ goto out; ++ goto out_display_early; ret = nouveau_mem_detect(dev); if (ret) -@@ -485,12 +474,19 @@ nouveau_card_init(struct drm_device *dev) +@@ -461,10 +564,15 @@ nouveau_card_init(struct drm_device *dev) + if (ret) + goto out_gpuobj; + ++ /* PGPIO */ ++ ret = engine->gpio.init(dev); ++ if (ret) ++ goto out_mc; ++ + /* PTIMER */ + ret = engine->timer.init(dev); + if (ret) +- goto out_mc; ++ goto out_gpio; + + /* PFB */ + ret = engine->fb.init(dev); +@@ -485,12 +593,16 @@ nouveau_card_init(struct drm_device *dev) goto out_graph; } -+ if (dev_priv->card_type >= NV_50) -+ ret = nv50_display_create(dev); -+ else -+ ret = nv04_display_create(dev); ++ ret = engine->display.create(dev); + if (ret) + goto out_fifo; + @@ -4012,7 +5891,7 @@ index b02a231..621e080 100644 ret = drm_vblank_init(dev, 0); if (ret) -@@ -504,35 +500,21 @@ nouveau_card_init(struct drm_device *dev) +@@ -504,35 +616,18 @@ nouveau_card_init(struct drm_device *dev) goto out_irq; } @@ -4048,20 +5927,34 @@ index b02a231..621e080 100644 out_irq: drm_irq_uninstall(dev); +out_display: -+ if (dev_priv->card_type >= NV_50) -+ nv50_display_destroy(dev); -+ else -+ nv04_display_destroy(dev); ++ engine->display.destroy(dev); out_fifo: if (!nouveau_noaccel) engine->fifo.takedown(dev); -@@ -566,45 +548,37 @@ static void nouveau_card_takedown(struct drm_device *dev) +@@ -543,6 +638,8 @@ out_fb: + engine->fb.takedown(dev); + out_timer: + engine->timer.takedown(dev); ++out_gpio: ++ engine->gpio.takedown(dev); + out_mc: + engine->mc.takedown(dev); + out_gpuobj: +@@ -556,6 +653,8 @@ out_gpuobj_early: + nouveau_gpuobj_late_takedown(dev); + out_bios: + nouveau_bios_takedown(dev); ++out_display_early: ++ engine->display.late_takedown(dev); + out: + vga_client_register(dev->pdev, NULL, NULL, NULL); + return ret; +@@ -566,45 +665,39 @@ static void nouveau_card_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; - NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); -+ nouveau_backlight_exit(dev); - +- - if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { - - nouveau_backlight_exit(dev); @@ -4070,7 +5963,8 @@ index b02a231..621e080 100644 - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; - } -- ++ nouveau_backlight_exit(dev); + - if (!nouveau_noaccel) { - engine->fifo.takedown(dev); - engine->graph.takedown(dev); @@ -4094,7 +5988,9 @@ index b02a231..621e080 100644 + } + engine->fb.takedown(dev); + engine->timer.takedown(dev); ++ engine->gpio.takedown(dev); + engine->mc.takedown(dev); ++ engine->display.late_takedown(dev); - nouveau_gpuobj_takedown(dev); - nouveau_mem_close(dev); @@ -4125,15 +6021,20 @@ index b02a231..621e080 100644 } /* here a client dies, release the stuff that was allocated for its -@@ -691,6 +665,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -691,22 +784,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) struct drm_nouveau_private *dev_priv; uint32_t reg0; resource_size_t mmio_start_offs; + int ret; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); - if (!dev_priv) -@@ -699,7 +674,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +- if (!dev_priv) +- return -ENOMEM; ++ if (!dev_priv) { ++ ret = -ENOMEM; ++ goto err_out; ++ } + dev->dev_private = dev_priv; dev_priv->dev = dev; dev_priv->flags = flags & NOUVEAU_FLAGS; @@ -4141,7 +6042,76 @@ index b02a231..621e080 100644 NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", dev->pci_vendor, dev->pci_device, dev->pdev->class); -@@ -812,46 +786,28 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + + dev_priv->wq = create_workqueue("nouveau"); +- if (!dev_priv->wq) +- return -EINVAL; ++ if (!dev_priv->wq) { ++ ret = -EINVAL; ++ goto err_priv; ++ } + + /* resource 0 is mmio regs */ + /* resource 1 is linear FB */ +@@ -719,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + if (!dev_priv->mmio) { + NV_ERROR(dev, "Unable to initialize the mmio mapping. " + "Please report your setup to " DRIVER_EMAIL "\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_wq; + } + NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", + (unsigned long long)mmio_start_offs); +@@ -765,19 +863,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + case 0xa0: + dev_priv->card_type = NV_50; + break; ++ case 0xc0: ++ dev_priv->card_type = NV_C0; ++ break; + default: + NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_mmio; + } + + NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", + dev_priv->card_type, reg0); + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- int ret = nouveau_remove_conflicting_drivers(dev); +- if (ret) +- return ret; +- } ++ ret = nouveau_remove_conflicting_drivers(dev); ++ if (ret) ++ goto err_mmio; + + /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ + if (dev_priv->card_type >= NV_40) { +@@ -791,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + dev_priv->ramin_size); + if (!dev_priv->ramin) { + NV_ERROR(dev, "Failed to PRAMIN BAR"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_mmio; + } + } else { + dev_priv->ramin_size = 1 * 1024 * 1024; +@@ -799,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + dev_priv->ramin_size); + if (!dev_priv->ramin) { + NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_mmio; + } + } + +@@ -812,46 +914,38 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->flags |= NV_NFORCE2; /* For kernel modesetting, init card now and bring up fbcon */ @@ -4152,20 +6122,31 @@ index b02a231..621e080 100644 - } + ret = nouveau_card_init(dev); + if (ret) -+ return ret; ++ goto err_ramin; return 0; - } - +-} +- -static void nouveau_close(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; -- + - /* In the case of an error dev_priv may not be allocated yet */ - if (dev_priv) - nouveau_card_takedown(dev); --} -- ++err_ramin: ++ iounmap(dev_priv->ramin); ++err_mmio: ++ iounmap(dev_priv->mmio); ++err_wq: ++ destroy_workqueue(dev_priv->wq); ++err_priv: ++ kfree(dev_priv); ++ dev->dev_private = NULL; ++err_out: ++ return ret; + } + -/* KMS: we need mmio at load time, not when the first drm client opens. */ void nouveau_lastclose(struct drm_device *dev) { @@ -4178,6 +6159,7 @@ index b02a231..621e080 100644 int nouveau_unload(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_engine *engine = &dev_priv->engine; - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_kms_helper_poll_fini(dev); @@ -4190,15 +6172,12 @@ index b02a231..621e080 100644 - } + drm_kms_helper_poll_fini(dev); + nouveau_fbcon_fini(dev); -+ if (dev_priv->card_type >= NV_50) -+ nv50_display_destroy(dev); -+ else -+ nv04_display_destroy(dev); ++ engine->display.destroy(dev); + nouveau_card_takedown(dev); iounmap(dev_priv->mmio); iounmap(dev_priv->ramin); -@@ -867,8 +823,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, +@@ -867,8 +961,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_getparam *getparam = data; @@ -4207,7 +6186,7 @@ index b02a231..621e080 100644 switch (getparam->param) { case NOUVEAU_GETPARAM_CHIPSET_ID: getparam->value = dev_priv->chipset; -@@ -937,8 +891,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, +@@ -937,8 +1029,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, { struct drm_nouveau_setparam *setparam = data; @@ -4217,7 +6196,7 @@ index b02a231..621e080 100644 default: NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c -index eba687f..1c20c08 100644 +index eba687f..08c7e07 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -4239,11 +6218,43 @@ index eba687f..1c20c08 100644 } static bool +@@ -537,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) + * 1 << 30 on 0x60.830), for no apparent reason */ + regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; + ++ if (dev_priv->card_type >= NV_30) ++ regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1; ++ + regp->crtc_830 = mode->crtc_vdisplay - 3; + regp->crtc_834 = mode->crtc_vdisplay - 1; + diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c -index 1cb19e3..2d0fee5 100644 +index 1cb19e3..ea36270 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c -@@ -261,12 +261,11 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) +@@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) + { + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, +@@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) + nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); + } + +- saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); +- saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); ++ saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); ++ saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); + +- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); ++ gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); ++ gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); + + msleep(4); saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); head = (saved_routput & 0x100) >> 8; @@ -4260,7 +6271,18 @@ index 1cb19e3..2d0fee5 100644 /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ routput = (saved_routput & 0xfffffece) | head << 8; -@@ -315,9 +314,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) + nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); + nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); + +- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); ++ gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1); ++ gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0); + + return sample; + } +@@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; @@ -4275,7 +6297,7 @@ index 1cb19e3..2d0fee5 100644 NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; -@@ -330,6 +332,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, +@@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -4285,7 +6307,7 @@ index 1cb19e3..2d0fee5 100644 return true; } -@@ -428,6 +433,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) +@@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) } } @@ -4303,7 +6325,7 @@ index 1cb19e3..2d0fee5 100644 static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; -@@ -501,11 +517,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { +@@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { .destroy = nv04_dac_destroy, }; @@ -4319,7 +6341,7 @@ index 1cb19e3..2d0fee5 100644 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); if (!nv_encoder) -@@ -527,5 +545,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -4327,10 +6349,56 @@ index 1cb19e3..2d0fee5 100644 return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c -index 41634d4..3311f3a 100644 +index 41634d4..a5dcf76 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c -@@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -34,6 +34,8 @@ + #include "nouveau_hw.h" + #include "nvreg.h" + ++#include "i2c/sil164.h" ++ + #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ + NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ + NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) +@@ -144,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) + } + } + ++static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; ++ struct drm_encoder *slave; ++ ++ if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP) ++ return NULL; ++ ++ /* Some BIOSes (e.g. the one in a Quadro FX1000) report several ++ * TMDS transmitters at the same I2C address, in the same I2C ++ * bus. This can still work because in that case one of them is ++ * always hard-wired to a reasonable configuration using straps, ++ * and the other one needs to be programmed. ++ * ++ * I don't think there's a way to know which is which, even the ++ * blob programs the one exposed via I2C for *both* heads, so ++ * let's do the same. ++ */ ++ list_for_each_entry(slave, &dev->mode_config.encoder_list, head) { ++ struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb; ++ ++ if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) && ++ slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr) ++ return slave; ++ } ++ ++ return NULL; ++} ++ + static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +@@ -413,10 +445,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) struct dcb_entry *dcbe = nv_encoder->dcb; int head = nouveau_crtc(encoder->crtc)->index; @@ -4341,7 +6409,62 @@ index 41634d4..3311f3a 100644 if (dcbe->type == OUTPUT_TMDS) run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); else if (dcbe->type == OUTPUT_LVDS) -@@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { +@@ -433,6 +461,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) + else + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); + ++ /* Init external transmitters */ ++ if (get_tmds_slave(encoder)) ++ get_slave_funcs(get_tmds_slave(encoder))->mode_set( ++ encoder, &nv_encoder->mode, &nv_encoder->mode); ++ + helper->dpms(encoder, DRM_MODE_DPMS_ON); + + NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", +@@ -554,10 +587,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) + + NV_DEBUG_KMS(encoder->dev, "\n"); + ++ if (get_slave_funcs(encoder)) ++ get_slave_funcs(encoder)->destroy(encoder); ++ + drm_encoder_cleanup(encoder); + kfree(nv_encoder); + } + ++static void nv04_tmds_slave_init(struct drm_encoder *encoder) ++{ ++ struct drm_device *dev = encoder->dev; ++ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; ++ struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2); ++ struct i2c_board_info info[] = { ++ { ++ .type = "sil164", ++ .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), ++ .platform_data = &(struct sil164_encoder_params) { ++ SIL164_INPUT_EDGE_RISING ++ } ++ }, ++ { } ++ }; ++ int type; ++ ++ if (!nv_gf4_disp_arch(dev) || !i2c || ++ get_tmds_slave(encoder)) ++ return; ++ ++ type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); ++ if (type < 0) ++ return; ++ ++ drm_i2c_encoder_init(dev, to_encoder_slave(encoder), ++ &i2c->adapter, &info[type]); ++} ++ + static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { + .dpms = nv04_lvds_dpms, + .save = nv04_dfp_save, +@@ -584,11 +649,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { .destroy = nv04_dfp_destroy, }; @@ -4356,7 +6479,7 @@ index 41634d4..3311f3a 100644 int type; switch (entry->type) { -@@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -613,11 +679,16 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; @@ -4367,11 +6490,15 @@ index 41634d4..3311f3a 100644 encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; ++ if (entry->type == OUTPUT_TMDS && ++ entry->location != DCB_LOC_ON_CHIP) ++ nv04_tmds_slave_init(encoder); ++ + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c -index c7898b4..c6df391 100644 +index c7898b4..9e28cf7 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -32,8 +32,6 @@ @@ -4410,22 +6537,54 @@ index c7898b4..c6df391 100644 if (slaved_on_A && !tvA) dev_priv->crtc_owner = 0x0; else if (slaved_on_B && !tvB) -@@ -79,14 +73,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) +@@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) else dev_priv->crtc_owner = 0x0; } -- ++} ++ ++int ++nv04_display_early_init(struct drm_device *dev) ++{ ++ /* Make the I2C buses accessible. */ ++ if (!nv_gf4_disp_arch(dev)) { ++ uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); ++ ++ if (!(pmc_enable & 1)) ++ nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1); ++ } + -ownerknown: - NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner); -- ++ /* Unlock the VGA CRTCs. */ ++ NVLockVgaCrtcs(dev, false); ++ ++ /* Make sure the CRTCs aren't in slaved mode. */ ++ if (nv_two_heads(dev)) { ++ nv04_display_store_initial_head_owner(dev); ++ NVSetOwner(dev, 0); ++ } ++ ++ return 0; ++} ++ ++void ++nv04_display_late_takedown(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ if (nv_two_heads(dev)) ++ NVSetOwner(dev, dev_priv->crtc_owner); + - /* we need to ensure the heads are not tied henceforth, or reading any - * 8 bit reg on head B will fail - * setting a single arbitrary head solves that */ - NVSetOwner(dev, 0); ++ NVLockVgaCrtcs(dev, true); } int -@@ -94,14 +80,20 @@ nv04_display_create(struct drm_device *dev) +@@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; @@ -4437,17 +6596,11 @@ index c7898b4..c6df391 100644 NV_DEBUG_KMS(dev, "\n"); - if (nv_two_heads(dev)) -+ NVLockVgaCrtcs(dev, false); -+ -+ if (nv_two_heads(dev)) { - nv04_display_store_initial_head_owner(dev); -+ NVSetOwner(dev, 0); -+ } -+ +- nv04_display_store_initial_head_owner(dev); nouveau_hw_save_vga_fonts(dev, 1); drm_mode_config_init(dev); -@@ -132,19 +124,23 @@ nv04_display_create(struct drm_device *dev) +@@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev) for (i = 0; i < dcb->entries; i++) { struct dcb_entry *dcbent = &dcb->entry[i]; @@ -4475,7 +6628,7 @@ index c7898b4..c6df391 100644 break; default: NV_WARN(dev, "DCB type %d not known\n", dcbent->type); -@@ -155,12 +151,16 @@ nv04_display_create(struct drm_device *dev) +@@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev) continue; } @@ -4496,15 +6649,7 @@ index c7898b4..c6df391 100644 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->save(crtc); -@@ -176,6 +176,7 @@ nv04_display_create(struct drm_device *dev) - void - nv04_display_destroy(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_encoder *encoder; - struct drm_crtc *crtc; - -@@ -191,8 +192,6 @@ nv04_display_destroy(struct drm_device *dev) +@@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev) } /* Restore state */ @@ -4513,28 +6658,28 @@ index c7898b4..c6df391 100644 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct drm_encoder_helper_funcs *func = encoder->helper_private; -@@ -205,12 +204,15 @@ nv04_display_destroy(struct drm_device *dev) - drm_mode_config_cleanup(dev); - +@@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); -+ -+ if (nv_two_heads(dev)) -+ NVSetOwner(dev, dev_priv->crtc_owner); -+ NVLockVgaCrtcs(dev, true); } - void - nv04_display_restore(struct drm_device *dev) +-void +-nv04_display_restore(struct drm_device *dev) ++int ++nv04_display_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; struct drm_crtc *crtc; -@@ -232,13 +234,5 @@ nv04_display_restore(struct drm_device *dev) - +- NVLockVgaCrtcs(dev, false); +- + /* meh.. modeset apparently doesn't setup all the regs and depends + * on pre-existing state, for now load the state of the card *before* + * nouveau was loaded, and then do a modeset. +@@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->restore(crtc); -- + - if (nv_two_heads(dev)) { - NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n", - dev_priv->crtc_owner); @@ -4542,6 +6687,7 @@ index c7898b4..c6df391 100644 - } - - NVLockVgaCrtcs(dev, true); ++ return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -4720,7 +6866,7 @@ index 617ed1e..2af43a1 100644 } diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c -index c4e3404..94e299c 100644 +index c4e3404..0b5d012 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -34,69 +34,26 @@ @@ -4801,14 +6947,33 @@ index c4e3404..94e299c 100644 #define PLLSEL_TV_CRTC1_MASK \ (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1) -@@ -214,30 +171,32 @@ static void nv04_tv_commit(struct drm_encoder *encoder) +@@ -132,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) + + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); + +- to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode); ++ get_slave_funcs(encoder)->dpms(encoder, mode); + } + + static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) +@@ -195,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder, + regp->tv_vskew = 1; + regp->tv_vsync_delay = 1; + +- to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode); ++ get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode); + } + + static void nv04_tv_commit(struct drm_encoder *encoder) +@@ -214,30 +171,31 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - - to_encoder_slave(encoder)->slave_funcs->destroy(encoder); - +- to_encoder_slave(encoder)->slave_funcs->destroy(encoder); +- ++ get_slave_funcs(encoder)->destroy(encoder); drm_encoder_cleanup(encoder); - kfree(nv_encoder); @@ -4846,7 +7011,7 @@ index c4e3404..94e299c 100644 if (type < 0) return type; -@@ -246,41 +205,32 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -246,40 +204,31 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) if (!nv_encoder) return -ENOMEM; @@ -4889,23 +7054,22 @@ index c4e3404..94e299c 100644 + goto fail_cleanup; /* Fill the function pointers */ - sfuncs = to_encoder_slave(encoder)->slave_funcs; - +- sfuncs = to_encoder_slave(encoder)->slave_funcs; +- - *funcs = (struct drm_encoder_funcs) { - .destroy = nv04_tv_destroy, - }; -- ++ sfuncs = get_slave_funcs(encoder); + *hfuncs = (struct drm_encoder_helper_funcs) { .dpms = nv04_tv_dpms, - .save = sfuncs->save, -@@ -292,14 +242,17 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -292,14 +241,16 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) .detect = sfuncs->detect, }; - /* Set the slave encoder configuration */ - sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); + /* Attach it to the specified connector. */ -+ sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data); + sfuncs->create_resources(encoder, connector); + drm_mode_connector_attach_encoder(connector, encoder); @@ -4976,11 +7140,452 @@ index 7aeabf2..7a4069c 100644 nv10_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); return 0; +diff --git a/drivers/gpu/drm/nouveau/nv10_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c +new file mode 100644 +index 0000000..007fc29 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nv10_gpio.c +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (C) 2009 Francisco Jerez. ++ * All Rights Reserved. ++ * ++ * 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 (including the ++ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_hw.h" ++ ++static bool ++get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift, ++ uint32_t *mask) ++{ ++ if (ent->line < 2) { ++ *reg = NV_PCRTC_GPIO; ++ *shift = ent->line * 16; ++ *mask = 0x11; ++ ++ } else if (ent->line < 10) { ++ *reg = NV_PCRTC_GPIO_EXT; ++ *shift = (ent->line - 2) * 4; ++ *mask = 0x3; ++ ++ } else if (ent->line < 14) { ++ *reg = NV_PCRTC_850; ++ *shift = (ent->line - 10) * 4; ++ *mask = 0x3; ++ ++ } else { ++ return false; ++ } ++ ++ return true; ++} ++ ++int ++nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) ++{ ++ struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); ++ uint32_t reg, shift, mask, value; ++ ++ if (!ent) ++ return -ENODEV; ++ ++ if (!get_gpio_location(ent, ®, &shift, &mask)) ++ return -ENODEV; ++ ++ value = NVReadCRTC(dev, 0, reg) >> shift; ++ ++ return (ent->invert ? 1 : 0) ^ (value & 1); ++} ++ ++int ++nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) ++{ ++ struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); ++ uint32_t reg, shift, mask, value; ++ ++ if (!ent) ++ return -ENODEV; ++ ++ if (!get_gpio_location(ent, ®, &shift, &mask)) ++ return -ENODEV; ++ ++ value = ((ent->invert ? 1 : 0) ^ (state ? 1 : 0)) << shift; ++ mask = ~(mask << shift); ++ ++ NVWriteCRTC(dev, 0, reg, value | (NVReadCRTC(dev, 0, reg) & mask)); ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c +index fcf2cdd..b2f6a57 100644 +--- a/drivers/gpu/drm/nouveau/nv10_graph.c ++++ b/drivers/gpu/drm/nouveau/nv10_graph.c +@@ -43,51 +43,51 @@ struct pipe_state { + }; + + static int nv10_graph_ctx_regs[] = { +- NV10_PGRAPH_CTX_SWITCH1, +- NV10_PGRAPH_CTX_SWITCH2, +- NV10_PGRAPH_CTX_SWITCH3, +- NV10_PGRAPH_CTX_SWITCH4, +- NV10_PGRAPH_CTX_SWITCH5, +- NV10_PGRAPH_CTX_CACHE1, /* 8 values from 0x400160 to 0x40017c */ +- NV10_PGRAPH_CTX_CACHE2, /* 8 values from 0x400180 to 0x40019c */ +- NV10_PGRAPH_CTX_CACHE3, /* 8 values from 0x4001a0 to 0x4001bc */ +- NV10_PGRAPH_CTX_CACHE4, /* 8 values from 0x4001c0 to 0x4001dc */ +- NV10_PGRAPH_CTX_CACHE5, /* 8 values from 0x4001e0 to 0x4001fc */ +- 0x00400164, +- 0x00400184, +- 0x004001a4, +- 0x004001c4, +- 0x004001e4, +- 0x00400168, +- 0x00400188, +- 0x004001a8, +- 0x004001c8, +- 0x004001e8, +- 0x0040016c, +- 0x0040018c, +- 0x004001ac, +- 0x004001cc, +- 0x004001ec, +- 0x00400170, +- 0x00400190, +- 0x004001b0, +- 0x004001d0, +- 0x004001f0, +- 0x00400174, +- 0x00400194, +- 0x004001b4, +- 0x004001d4, +- 0x004001f4, +- 0x00400178, +- 0x00400198, +- 0x004001b8, +- 0x004001d8, +- 0x004001f8, +- 0x0040017c, +- 0x0040019c, +- 0x004001bc, +- 0x004001dc, +- 0x004001fc, ++ NV10_PGRAPH_CTX_SWITCH(0), ++ NV10_PGRAPH_CTX_SWITCH(1), ++ NV10_PGRAPH_CTX_SWITCH(2), ++ NV10_PGRAPH_CTX_SWITCH(3), ++ NV10_PGRAPH_CTX_SWITCH(4), ++ NV10_PGRAPH_CTX_CACHE(0, 0), ++ NV10_PGRAPH_CTX_CACHE(0, 1), ++ NV10_PGRAPH_CTX_CACHE(0, 2), ++ NV10_PGRAPH_CTX_CACHE(0, 3), ++ NV10_PGRAPH_CTX_CACHE(0, 4), ++ NV10_PGRAPH_CTX_CACHE(1, 0), ++ NV10_PGRAPH_CTX_CACHE(1, 1), ++ NV10_PGRAPH_CTX_CACHE(1, 2), ++ NV10_PGRAPH_CTX_CACHE(1, 3), ++ NV10_PGRAPH_CTX_CACHE(1, 4), ++ NV10_PGRAPH_CTX_CACHE(2, 0), ++ NV10_PGRAPH_CTX_CACHE(2, 1), ++ NV10_PGRAPH_CTX_CACHE(2, 2), ++ NV10_PGRAPH_CTX_CACHE(2, 3), ++ NV10_PGRAPH_CTX_CACHE(2, 4), ++ NV10_PGRAPH_CTX_CACHE(3, 0), ++ NV10_PGRAPH_CTX_CACHE(3, 1), ++ NV10_PGRAPH_CTX_CACHE(3, 2), ++ NV10_PGRAPH_CTX_CACHE(3, 3), ++ NV10_PGRAPH_CTX_CACHE(3, 4), ++ NV10_PGRAPH_CTX_CACHE(4, 0), ++ NV10_PGRAPH_CTX_CACHE(4, 1), ++ NV10_PGRAPH_CTX_CACHE(4, 2), ++ NV10_PGRAPH_CTX_CACHE(4, 3), ++ NV10_PGRAPH_CTX_CACHE(4, 4), ++ NV10_PGRAPH_CTX_CACHE(5, 0), ++ NV10_PGRAPH_CTX_CACHE(5, 1), ++ NV10_PGRAPH_CTX_CACHE(5, 2), ++ NV10_PGRAPH_CTX_CACHE(5, 3), ++ NV10_PGRAPH_CTX_CACHE(5, 4), ++ NV10_PGRAPH_CTX_CACHE(6, 0), ++ NV10_PGRAPH_CTX_CACHE(6, 1), ++ NV10_PGRAPH_CTX_CACHE(6, 2), ++ NV10_PGRAPH_CTX_CACHE(6, 3), ++ NV10_PGRAPH_CTX_CACHE(6, 4), ++ NV10_PGRAPH_CTX_CACHE(7, 0), ++ NV10_PGRAPH_CTX_CACHE(7, 1), ++ NV10_PGRAPH_CTX_CACHE(7, 2), ++ NV10_PGRAPH_CTX_CACHE(7, 3), ++ NV10_PGRAPH_CTX_CACHE(7, 4), + NV10_PGRAPH_CTX_USER, + NV04_PGRAPH_DMA_START_0, + NV04_PGRAPH_DMA_START_1, +@@ -653,6 +653,78 @@ static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg) + return -1; + } + ++static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan, ++ uint32_t inst) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; ++ uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; ++ uint32_t ctx_user, ctx_switch[5]; ++ int i, subchan = -1; ++ ++ /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state ++ * that cannot be restored via MMIO. Do it through the FIFO ++ * instead. ++ */ ++ ++ /* Look for a celsius object */ ++ for (i = 0; i < 8; i++) { ++ int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; ++ ++ if (class == 0x56 || class == 0x96 || class == 0x99) { ++ subchan = i; ++ break; ++ } ++ } ++ ++ if (subchan < 0 || !inst) ++ return; ++ ++ /* Save the current ctx object */ ++ ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER); ++ for (i = 0; i < 5; i++) ++ ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i)); ++ ++ /* Save the FIFO state */ ++ st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2); ++ st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL); ++ st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH); ++ fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR); ++ ++ for (i = 0; i < ARRAY_SIZE(fifo); i++) ++ fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i); ++ ++ /* Switch to the celsius subchannel */ ++ for (i = 0; i < 5; i++) ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ++ nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i))); ++ nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); ++ ++ /* Inject NV10TCL_DMA_VTXBUF */ ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, ++ 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); ++ nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); ++ pgraph->fifo_access(dev, true); ++ pgraph->fifo_access(dev, false); ++ ++ /* Restore the FIFO state */ ++ for (i = 0; i < ARRAY_SIZE(fifo); i++) ++ nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]); ++ ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2); ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); ++ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); ++ ++ /* Restore the current ctx object */ ++ for (i = 0; i < 5; i++) ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); ++ nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user); ++} ++ + int nv10_graph_load_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; +@@ -670,6 +742,8 @@ int nv10_graph_load_context(struct nouveau_channel *chan) + } + + nv10_graph_load_pipe(chan); ++ nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1) ++ & 0xffff)); + + nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER); +@@ -856,11 +930,12 @@ int nv10_graph_init(struct drm_device *dev) + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv10_graph_set_region_tiling(dev, i, 0, 0, 0); + +- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000); +- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000); +- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000); +- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000); +- nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); ++ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); ++ nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF); + + tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; + tmp |= (dev_priv->engine.fifo.channels - 1) << 24; +diff --git a/drivers/gpu/drm/nouveau/nv17_gpio.c b/drivers/gpu/drm/nouveau/nv17_gpio.c +deleted file mode 100644 +index 2e58c33..0000000 +--- a/drivers/gpu/drm/nouveau/nv17_gpio.c ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* +- * Copyright (C) 2009 Francisco Jerez. +- * All Rights Reserved. +- * +- * 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 (including the +- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h" +-#include "nouveau_drv.h" +-#include "nouveau_hw.h" +- +-static bool +-get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift, +- uint32_t *mask) +-{ +- if (ent->line < 2) { +- *reg = NV_PCRTC_GPIO; +- *shift = ent->line * 16; +- *mask = 0x11; +- +- } else if (ent->line < 10) { +- *reg = NV_PCRTC_GPIO_EXT; +- *shift = (ent->line - 2) * 4; +- *mask = 0x3; +- +- } else if (ent->line < 14) { +- *reg = NV_PCRTC_850; +- *shift = (ent->line - 10) * 4; +- *mask = 0x3; +- +- } else { +- return false; +- } +- +- return true; +-} +- +-int +-nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) +-{ +- struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); +- uint32_t reg, shift, mask, value; +- +- if (!ent) +- return -ENODEV; +- +- if (!get_gpio_location(ent, ®, &shift, &mask)) +- return -ENODEV; +- +- value = NVReadCRTC(dev, 0, reg) >> shift; +- +- return (ent->invert ? 1 : 0) ^ (value & 1); +-} +- +-int +-nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) +-{ +- struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); +- uint32_t reg, shift, mask, value; +- +- if (!ent) +- return -ENODEV; +- +- if (!get_gpio_location(ent, ®, &shift, &mask)) +- return -ENODEV; +- +- value = ((ent->invert ? 1 : 0) ^ (state ? 1 : 0)) << shift; +- mask = ~(mask << shift); +- +- NVWriteCRTC(dev, 0, reg, value | (NVReadCRTC(dev, 0, reg) & mask)); +- +- return 0; +-} diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c -index 74c8803..bb3a284 100644 +index 74c8803..44fefb0 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c -@@ -116,6 +116,21 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) +@@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) + { + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; + uint32_t testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, + fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; +@@ -52,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) + head = (dacclk & 0x100) >> 8; + + /* Save the previous state. */ +- gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); +- gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); ++ gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); ++ gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); + fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); + fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); + fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); +@@ -64,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) + ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); + + /* Prepare the DAC for load detection. */ +- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true); ++ gpio->set(dev, DCB_GPIO_TVDAC1, true); ++ gpio->set(dev, DCB_GPIO_TVDAC0, true); + + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); +@@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0); ++ gpio->set(dev, DCB_GPIO_TVDAC1, gpio1); ++ gpio->set(dev, DCB_GPIO_TVDAC0, gpio0); + return sample; } @@ -5002,7 +7607,7 @@ index 74c8803..bb3a284 100644 static enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { -@@ -124,12 +139,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -124,12 +140,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); struct dcb_entry *dcb = tv_enc->base.dcb; @@ -5028,7 +7633,7 @@ index 74c8803..bb3a284 100644 switch (tv_enc->pin_mask) { case 0x2: -@@ -154,7 +177,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -154,7 +178,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) conf->tv_subconnector_property, tv_enc->subconnector); @@ -5039,7 +7644,7 @@ index 74c8803..bb3a284 100644 NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; -@@ -296,6 +321,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, +@@ -296,6 +322,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, { struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); @@ -5049,7 +7654,27 @@ index 74c8803..bb3a284 100644 if (tv_norm->kind == CTV_ENC_MODE) adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock; else -@@ -744,8 +772,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { +@@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, + static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) + { + struct drm_device *dev = encoder->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; + struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; + struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); + +@@ -331,8 +362,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) + + nv_load_ptv(dev, regs, 200); + +- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); +- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); ++ gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); ++ gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); + + nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); + } +@@ -744,8 +775,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { .destroy = nv17_tv_destroy, }; @@ -5061,7 +7686,7 @@ index 74c8803..bb3a284 100644 struct drm_encoder *encoder; struct nv17_tv_encoder *tv_enc = NULL; -@@ -774,5 +804,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -774,5 +807,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -5278,6 +7903,107 @@ index d6fc0a8..191c15c 100644 nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); +diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c +new file mode 100644 +index 0000000..4a3f2f0 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nv30_fb.c +@@ -0,0 +1,95 @@ ++/* ++ * Copyright (C) 2010 Francisco Jerez. ++ * All Rights Reserved. ++ * ++ * 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 (including the ++ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h" ++#include "drm.h" ++#include "nouveau_drv.h" ++#include "nouveau_drm.h" ++ ++static int ++calc_bias(struct drm_device *dev, int k, int i, int j) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int b = (dev_priv->chipset > 0x30 ? ++ nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : ++ 0) & 0xf; ++ ++ return 2 * (b & 0x8 ? b - 0x10 : b); ++} ++ ++static int ++calc_ref(struct drm_device *dev, int l, int k, int i) ++{ ++ int j, x = 0; ++ ++ for (j = 0; j < 4; j++) { ++ int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j); ++ ++ x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); ++ } ++ ++ return x; ++} ++ ++int ++nv30_fb_init(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; ++ int i, j; ++ ++ pfb->num_tiles = NV10_PFB_TILE__SIZE; ++ ++ /* Turn all the tiling regions off. */ ++ for (i = 0; i < pfb->num_tiles; i++) ++ pfb->set_region_tiling(dev, i, 0, 0, 0); ++ ++ /* Init the memory timing regs at 0x10037c/0x1003ac */ ++ if (dev_priv->chipset == 0x30 || ++ dev_priv->chipset == 0x31 || ++ dev_priv->chipset == 0x35) { ++ /* Related to ROP count */ ++ int n = (dev_priv->chipset == 0x31 ? 2 : 4); ++ int l = nv_rd32(dev, 0x1003d0); ++ ++ for (i = 0; i < n; i++) { ++ for (j = 0; j < 3; j++) ++ nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j, ++ calc_ref(dev, l, 0, j)); ++ ++ for (j = 0; j < 2; j++) ++ nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j, ++ calc_ref(dev, l, 1, j)); ++ } ++ } ++ ++ return 0; ++} ++ ++void ++nv30_fb_takedown(struct drm_device *dev) ++{ ++} diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 500ccfd..2b67f18 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -5448,10 +8174,57 @@ index 2a3495e..e4e72c1 100644 nv_wr32(dev, NV40_PMC_1704, 0); nv_wr32(dev, NV40_PMC_1708, 0); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c -index b4e4a3b..5d11ea1 100644 +index b4e4a3b..a438e56 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c -@@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) +@@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update) + int + nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) + { +- uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct pll_lims pll; +- uint32_t reg1, reg2; ++ uint32_t reg, reg1, reg2; + int ret, N1, M1, N2, M2, P; + ++ if (dev_priv->chipset < NV_C0) ++ reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); ++ else ++ reg = 0x614140 + (head * 0x800); ++ + ret = get_pll_limits(dev, reg, &pll); + if (ret) + return ret; +@@ -286,7 +291,8 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) + nv_wr32(dev, reg, 0x10000611); + nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1); + nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2); +- } else { ++ } else ++ if (dev_priv->chipset < NV_C0) { + ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); + if (ret <= 0) + return 0; +@@ -298,6 +304,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) + nv_wr32(dev, reg, 0x50000610); + nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1); + nv_wr32(dev, reg + 8, N2); ++ } else { ++ ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); ++ if (ret <= 0) ++ return 0; ++ ++ NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n", ++ pclk, ret, N1, N2, M1, P); ++ ++ nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100); ++ nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1); ++ nv_wr32(dev, reg + 0x10, N2 << 16); + } + + return 0; +@@ -440,47 +457,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -5499,7 +8272,7 @@ index b4e4a3b..5d11ea1 100644 struct drm_device *dev = crtc->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; -@@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) +@@ -491,20 +476,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) nv50_crtc_blank(nv_crtc, false); @@ -5633,10 +8406,10 @@ index 1fd9537..1bc0859 100644 } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c -index 580a5d1..c19ed8c 100644 +index 580a5d1..612fa6d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c -@@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, +@@ -71,14 +71,16 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, return ret; } @@ -5646,13 +8419,17 @@ index 580a5d1..c19ed8c 100644 nv_wo32(dev, obj, 2, offset); nv_wo32(dev, obj, 3, 0x00000000); nv_wo32(dev, obj, 4, 0x00000000); - nv_wo32(dev, obj, 5, 0x00010000); +- nv_wo32(dev, obj, 5, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); ++ if (dev_priv->card_type < NV_C0) ++ nv_wo32(dev, obj, 5, 0x00010000); ++ else ++ nv_wo32(dev, obj, 5, 0x00020000); + dev_priv->engine.instmem.flush(dev); return 0; } -@@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) +@@ -110,8 +112,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) return ret; } @@ -5663,7 +8440,62 @@ index 580a5d1..c19ed8c 100644 if (ret) { NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); nv50_evo_channel_del(pchan); -@@ -465,6 +464,7 @@ int nv50_display_create(struct drm_device *dev) +@@ -179,13 +181,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + } + + int ++nv50_display_early_init(struct drm_device *dev) ++{ ++ return 0; ++} ++ ++void ++nv50_display_late_takedown(struct drm_device *dev) ++{ ++} ++ ++int + nv50_display_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; ++ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nouveau_channel *evo = dev_priv->evo; + struct drm_connector *connector; +- uint32_t val, ram_amount, hpd_en[2]; ++ uint32_t val, ram_amount; + uint64_t start; + int ret, i; + +@@ -366,26 +380,13 @@ nv50_display_init(struct drm_device *dev) + NV50_PDISPLAY_INTR_EN_CLK_UNK40)); + + /* enable hotplug interrupts */ +- hpd_en[0] = hpd_en[1] = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct nouveau_connector *conn = nouveau_connector(connector); +- struct dcb_gpio_entry *gpio; + + if (conn->dcb->gpio_tag == 0xff) + continue; + +- gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag); +- if (!gpio) +- continue; +- +- hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf)); +- } +- +- nv_wr32(dev, 0xe054, 0xffffffff); +- nv_wr32(dev, 0xe050, hpd_en[0]); +- if (dev_priv->chipset >= 0x90) { +- nv_wr32(dev, 0xe074, 0xffffffff); +- nv_wr32(dev, 0xe070, hpd_en[1]); ++ pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); + } + + return 0; +@@ -465,6 +466,7 @@ int nv50_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; @@ -5671,7 +8503,7 @@ index 580a5d1..c19ed8c 100644 int ret, i; NV_DEBUG_KMS(dev, "\n"); -@@ -507,14 +507,18 @@ int nv50_display_create(struct drm_device *dev) +@@ -507,14 +509,18 @@ int nv50_display_create(struct drm_device *dev) continue; } @@ -5692,7 +8524,7 @@ index 580a5d1..c19ed8c 100644 break; default: NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); -@@ -522,11 +526,13 @@ int nv50_display_create(struct drm_device *dev) +@@ -522,11 +528,13 @@ int nv50_display_create(struct drm_device *dev) } } @@ -5711,10 +8543,24 @@ index 580a5d1..c19ed8c 100644 } ret = nv50_display_init(dev); -@@ -552,131 +558,28 @@ int nv50_display_destroy(struct drm_device *dev) +@@ -538,7 +546,8 @@ int nv50_display_create(struct drm_device *dev) return 0; } +-int nv50_display_destroy(struct drm_device *dev) ++void ++nv50_display_destroy(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +@@ -548,135 +557,30 @@ int nv50_display_destroy(struct drm_device *dev) + + nv50_display_disable(dev); + nv50_evo_channel_del(&dev_priv->evo); +- +- return 0; +-} +- -static inline uint32_t -nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or) -{ @@ -5815,8 +8661,8 @@ index 580a5d1..c19ed8c 100644 - - NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or); - return 0; --} -- + } + -static uint32_t -nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, - int pxclk) @@ -5850,7 +8696,7 @@ index 580a5d1..c19ed8c 100644 case OUTPUT_LVDS: script = (mc >> 8) & 0xf; if (bios->fp_no_ddc) { -@@ -767,17 +670,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) +@@ -767,17 +671,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) static void nv50_display_unk10_handler(struct drm_device *dev) { @@ -5880,7 +8726,7 @@ index 580a5d1..c19ed8c 100644 + crtc = ffs((unk30 & 0x00000180) >> 7) - 1; + if (crtc < 0) + goto ack; -+ + + /* Find which encoder was connected to the CRTC */ + for (i = 0; type == OUTPUT_ANY && i < 3; i++) { + mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i)); @@ -5906,7 +8752,7 @@ index 580a5d1..c19ed8c 100644 + mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i)); + else + mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i)); - ++ + NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; @@ -5945,7 +8791,7 @@ index 580a5d1..c19ed8c 100644 ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); nv_wr32(dev, 0x610030, 0x80000000); -@@ -817,33 +791,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) +@@ -817,33 +792,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) static void nv50_display_unk20_handler(struct drm_device *dev) { @@ -6023,10 +8869,7 @@ index 580a5d1..c19ed8c 100644 + NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; - -- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); -- tmp &= ~0x000000f; -- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); ++ + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_LVDS; break; + case 1: type = OUTPUT_TMDS; break; @@ -6056,18 +8899,21 @@ index 580a5d1..c19ed8c 100644 + NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); + goto ack; + } -+ + +- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); +- tmp &= ~0x000000f; +- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); + script = nv50_display_script_select(dev, dcb, mc, pclk); + nouveau_bios_run_display_table(dev, dcb, script, pclk); -+ -+ nv50_display_unk20_dp_hack(dev, dcb); - if (dcbent->type != OUTPUT_ANALOG) { ++ nv50_display_unk20_dp_hack(dev, dcb); ++ + if (dcb->type != OUTPUT_ANALOG) { tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); tmp &= ~0x00000f0f; if (script & 0x0100) -@@ -853,24 +897,61 @@ nv50_display_unk20_handler(struct drm_device *dev) +@@ -853,24 +898,61 @@ nv50_display_unk20_handler(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); } @@ -6136,6 +8982,24 @@ index 580a5d1..c19ed8c 100644 ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); +diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h +index 581d405..c551f0b 100644 +--- a/drivers/gpu/drm/nouveau/nv50_display.h ++++ b/drivers/gpu/drm/nouveau/nv50_display.h +@@ -38,9 +38,11 @@ + void nv50_display_irq_handler(struct drm_device *dev); + void nv50_display_irq_handler_bh(struct work_struct *work); + void nv50_display_irq_hotplug_bh(struct work_struct *work); +-int nv50_display_init(struct drm_device *dev); ++int nv50_display_early_init(struct drm_device *dev); ++void nv50_display_late_takedown(struct drm_device *dev); + int nv50_display_create(struct drm_device *dev); +-int nv50_display_destroy(struct drm_device *dev); ++int nv50_display_init(struct drm_device *dev); ++void nv50_display_destroy(struct drm_device *dev); + int nv50_crtc_blank(struct nouveau_crtc *, bool blank); + int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); + diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index e20c0e2..fb0281a 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -6447,6 +9311,49 @@ index e20c0e2..fb0281a 100644 /*XXX: probably reload ch127 (NULL) state back too */ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127); +diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c +index bb47ad7..b2fab2b 100644 +--- a/drivers/gpu/drm/nouveau/nv50_gpio.c ++++ b/drivers/gpu/drm/nouveau/nv50_gpio.c +@@ -74,3 +74,38 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) + nv_wr32(dev, r, v); + return 0; + } ++ ++void ++nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) ++{ ++ struct dcb_gpio_entry *gpio; ++ u32 reg, mask; ++ ++ gpio = nouveau_bios_gpio_entry(dev, tag); ++ if (!gpio) { ++ NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag); ++ return; ++ } ++ ++ reg = gpio->line < 16 ? 0xe050 : 0xe070; ++ mask = 0x00010001 << (gpio->line & 0xf); ++ ++ nv_wr32(dev, reg + 4, mask); ++ nv_mask(dev, reg + 0, mask, on ? mask : 0); ++} ++ ++int ++nv50_gpio_init(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ /* disable, and ack any pending gpio interrupts */ ++ nv_wr32(dev, 0xe050, 0x00000000); ++ nv_wr32(dev, 0xe054, 0xffffffff); ++ if (dev_priv->chipset >= 0x90) { ++ nv_wr32(dev, 0xe070, 0x00000000); ++ nv_wr32(dev, 0xe074, 0xffffffff); ++ } ++ ++ return 0; ++} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index b203d06..1413028 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c @@ -6603,7 +9510,7 @@ index b203d06..1413028 100644 nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c -index 5f21df3..b7ad258 100644 +index 5f21df3..1fd5207 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -35,8 +35,6 @@ struct nv50_instmem_priv { @@ -6731,7 +9638,7 @@ index 5f21df3..b7ad258 100644 - - priv->last_access_wr = write; + nv_wr32(dev, 0x00330c, 0x00000001); -+ if (!nv_wait(0x00330c, 0x00000001, 0x00000000)) ++ if (!nv_wait(0x00330c, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } @@ -6748,7 +9655,7 @@ index 5f21df3..b7ad258 100644 - NV_ERROR(dev, "PRAMIN flush timeout\n"); - } + nv_wr32(dev, 0x070000, 0x00000001); -+ if (!nv_wait(0x070000, 0x00000001, 0x00000000)) ++ if (!nv_wait(0x070000, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } @@ -6962,6 +9869,468 @@ index 812778d..bcd4cf8 100644 + drm_mode_connector_attach_encoder(connector, encoder); return 0; } +diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c +new file mode 100644 +index 0000000..26a9960 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvc0_fb.c +@@ -0,0 +1,38 @@ ++/* ++ * Copyright 2010 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 "drmP.h" ++ ++#include "nouveau_drv.h" ++ ++int ++nvc0_fb_init(struct drm_device *dev) ++{ ++ return 0; ++} ++ ++void ++nvc0_fb_takedown(struct drm_device *dev) ++{ ++} +diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c +new file mode 100644 +index 0000000..45ca994 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c +@@ -0,0 +1,95 @@ ++/* ++ * Copyright 2010 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 "drmP.h" ++ ++#include "nouveau_drv.h" ++ ++void ++nvc0_fifo_disable(struct drm_device *dev) ++{ ++} ++ ++void ++nvc0_fifo_enable(struct drm_device *dev) ++{ ++} ++ ++bool ++nvc0_fifo_reassign(struct drm_device *dev, bool enable) ++{ ++ return false; ++} ++ ++bool ++nvc0_fifo_cache_flush(struct drm_device *dev) ++{ ++ return true; ++} ++ ++bool ++nvc0_fifo_cache_pull(struct drm_device *dev, bool enable) ++{ ++ return false; ++} ++ ++int ++nvc0_fifo_channel_id(struct drm_device *dev) ++{ ++ return 127; ++} ++ ++int ++nvc0_fifo_create_context(struct nouveau_channel *chan) ++{ ++ return 0; ++} ++ ++void ++nvc0_fifo_destroy_context(struct nouveau_channel *chan) ++{ ++} ++ ++int ++nvc0_fifo_load_context(struct nouveau_channel *chan) ++{ ++ return 0; ++} ++ ++int ++nvc0_fifo_unload_context(struct drm_device *dev) ++{ ++ return 0; ++} ++ ++void ++nvc0_fifo_takedown(struct drm_device *dev) ++{ ++} ++ ++int ++nvc0_fifo_init(struct drm_device *dev) ++{ ++ return 0; ++} +diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c +new file mode 100644 +index 0000000..edf2b21 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvc0_graph.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright 2010 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 "drmP.h" ++ ++#include "nouveau_drv.h" ++ ++void ++nvc0_graph_fifo_access(struct drm_device *dev, bool enabled) ++{ ++} ++ ++struct nouveau_channel * ++nvc0_graph_channel(struct drm_device *dev) ++{ ++ return NULL; ++} ++ ++int ++nvc0_graph_create_context(struct nouveau_channel *chan) ++{ ++ return 0; ++} ++ ++void ++nvc0_graph_destroy_context(struct nouveau_channel *chan) ++{ ++} ++ ++int ++nvc0_graph_load_context(struct nouveau_channel *chan) ++{ ++ return 0; ++} ++ ++int ++nvc0_graph_unload_context(struct drm_device *dev) ++{ ++ return 0; ++} ++ ++void ++nvc0_graph_takedown(struct drm_device *dev) ++{ ++} ++ ++int ++nvc0_graph_init(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ dev_priv->engine.graph.accel_blocked = true; ++ return 0; ++} +diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c +new file mode 100644 +index 0000000..b66c913 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c +@@ -0,0 +1,231 @@ ++/* ++ * Copyright 2010 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 "drmP.h" ++ ++#include "nouveau_drv.h" ++ ++int ++nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, ++ uint32_t *size) ++{ ++ int ret; ++ ++ *size = ALIGN(*size, 4096); ++ if (*size == 0) ++ return -EINVAL; ++ ++ ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, ++ true, false, &gpuobj->im_backing); ++ if (ret) { ++ NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); ++ return ret; ++ } ++ ++ ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); ++ if (ret) { ++ NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); ++ nouveau_bo_ref(NULL, &gpuobj->im_backing); ++ return ret; ++ } ++ ++ gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; ++ gpuobj->im_backing_start <<= PAGE_SHIFT; ++ return 0; ++} ++ ++void ++nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ if (gpuobj && gpuobj->im_backing) { ++ if (gpuobj->im_bound) ++ dev_priv->engine.instmem.unbind(dev, gpuobj); ++ nouveau_bo_unpin(gpuobj->im_backing); ++ nouveau_bo_ref(NULL, &gpuobj->im_backing); ++ gpuobj->im_backing = NULL; ++ } ++} ++ ++int ++nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t pte, pte_end; ++ uint64_t vram; ++ ++ if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) ++ return -EINVAL; ++ ++ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", ++ gpuobj->im_pramin->start, gpuobj->im_pramin->size); ++ ++ pte = gpuobj->im_pramin->start >> 12; ++ pte_end = (gpuobj->im_pramin->size >> 12) + pte; ++ vram = gpuobj->im_backing_start; ++ ++ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", ++ gpuobj->im_pramin->start, pte, pte_end); ++ NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); ++ ++ while (pte < pte_end) { ++ nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); ++ nv_wr32(dev, 0x702004 + (pte * 8), 0); ++ vram += 4096; ++ pte++; ++ } ++ dev_priv->engine.instmem.flush(dev); ++ ++ if (1) { ++ u32 chan = nv_rd32(dev, 0x1700) << 16; ++ nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); ++ nv_wr32(dev, 0x100cbc, 0x80000005); ++ } ++ ++ gpuobj->im_bound = 1; ++ return 0; ++} ++ ++int ++nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t pte, pte_end; ++ ++ if (gpuobj->im_bound == 0) ++ return -EINVAL; ++ ++ pte = gpuobj->im_pramin->start >> 12; ++ pte_end = (gpuobj->im_pramin->size >> 12) + pte; ++ while (pte < pte_end) { ++ nv_wr32(dev, 0x702000 + (pte * 8), 0); ++ nv_wr32(dev, 0x702004 + (pte * 8), 0); ++ pte++; ++ } ++ dev_priv->engine.instmem.flush(dev); ++ ++ gpuobj->im_bound = 0; ++ return 0; ++} ++ ++void ++nvc0_instmem_flush(struct drm_device *dev) ++{ ++ nv_wr32(dev, 0x070000, 1); ++ if (!nv_wait(0x070000, 0x00000002, 0x00000000)) ++ NV_ERROR(dev, "PRAMIN flush timeout\n"); ++} ++ ++int ++nvc0_instmem_suspend(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int i; ++ ++ dev_priv->susres.ramin_copy = vmalloc(65536); ++ if (!dev_priv->susres.ramin_copy) ++ return -ENOMEM; ++ ++ for (i = 0x700000; i < 0x710000; i += 4) ++ dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); ++ return 0; ++} ++ ++void ++nvc0_instmem_resume(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u64 chan; ++ int i; ++ ++ chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; ++ nv_wr32(dev, 0x001700, chan >> 16); ++ ++ for (i = 0x700000; i < 0x710000; i += 4) ++ nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); ++ vfree(dev_priv->susres.ramin_copy); ++ dev_priv->susres.ramin_copy = NULL; ++ ++ nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); ++} ++ ++int ++nvc0_instmem_init(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; ++ int ret, i; ++ ++ dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; ++ chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; ++ imem = 4096 + 4096 + 32768; ++ ++ nv_wr32(dev, 0x001700, chan >> 16); ++ ++ /* channel setup */ ++ nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); ++ nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); ++ nv_wr32(dev, 0x700208, lower_32_bits(lim3)); ++ nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); ++ ++ /* point pgd -> pgt */ ++ nv_wr32(dev, 0x701000, 0); ++ nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); ++ ++ /* point pgt -> physical vram for channel */ ++ pgt3 = 0x2000; ++ for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { ++ nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); ++ nv_wr32(dev, 0x700004 + pgt3, 0); ++ } ++ ++ /* clear rest of pgt */ ++ for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { ++ nv_wr32(dev, 0x700000 + pgt3, 0); ++ nv_wr32(dev, 0x700004 + pgt3, 0); ++ } ++ ++ /* point bar3 at the channel */ ++ nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); ++ ++ /* Global PRAMIN heap */ ++ ret = drm_mm_init(&dev_priv->ramin_heap, imem, ++ dev_priv->ramin_size - imem); ++ if (ret) { ++ NV_ERROR(dev, "Failed to init RAMIN heap\n"); ++ return -ENOMEM; ++ } ++ ++ /*XXX: incorrect, but needed to make hash func "work" */ ++ dev_priv->ramht_offset = 0x10000; ++ dev_priv->ramht_bits = 9; ++ dev_priv->ramht_size = (1 << dev_priv->ramht_bits); ++ return 0; ++} ++ ++void ++nvc0_instmem_takedown(struct drm_device *dev) ++{ ++} diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h index 5998c35..ad64673 100644 --- a/drivers/gpu/drm/nouveau/nvreg.h @@ -6995,3 +10364,6 @@ index 5998c35..ad64673 100644 #define NV_PCRTC_INTR_0 0x00600100 # define NV_PCRTC_INTR_0_VBLANK (1 << 0) #define NV_PCRTC_INTR_EN_0 0x00600140 +-- +1.7.2 + diff --git a/drm-sil164-module.patch b/drm-sil164-module.patch new file mode 100644 index 000000000..06194e6a1 --- /dev/null +++ b/drm-sil164-module.patch @@ -0,0 +1,592 @@ +From f1719f0dcd68ca4de42c7b00ef2b37658007dda7 Mon Sep 17 00:00:00 2001 +From: Francisco Jerez +Date: Thu, 22 Jul 2010 17:06:18 +0200 +Subject: [PATCH 2/5] drm-sil164-module + +drm: Import driver for the sil164 I2C TMDS transmitter. + +sil164 transmitters are used for DVI outputs on Intel/nvidia and ATI setups. + +So far only nouveau can use this driver. + +Signed-off-by: Francisco Jerez +Tested-by: Patrice Mandin +Signed-off-by: Dave Airlie +--- + drivers/gpu/drm/i2c/Makefile | 3 + + drivers/gpu/drm/i2c/sil164_drv.c | 462 ++++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/nouveau/Kconfig | 9 + + include/drm/i2c/sil164.h | 63 +++++ + 4 files changed, 537 insertions(+), 0 deletions(-) + create mode 100644 drivers/gpu/drm/i2c/sil164_drv.c + create mode 100644 include/drm/i2c/sil164.h + +diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile +index 6d2abaf..9286256 100644 +--- a/drivers/gpu/drm/i2c/Makefile ++++ b/drivers/gpu/drm/i2c/Makefile +@@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm + + ch7006-y := ch7006_drv.o ch7006_mode.o + obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o ++ ++sil164-y := sil164_drv.o ++obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o +diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c +new file mode 100644 +index 0000000..0b67732 +--- /dev/null ++++ b/drivers/gpu/drm/i2c/sil164_drv.c +@@ -0,0 +1,462 @@ ++/* ++ * Copyright (C) 2010 Francisco Jerez. ++ * All Rights Reserved. ++ * ++ * 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 (including the ++ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h" ++#include "drm_crtc_helper.h" ++#include "drm_encoder_slave.h" ++#include "i2c/sil164.h" ++ ++struct sil164_priv { ++ struct sil164_encoder_params config; ++ struct i2c_client *duallink_slave; ++ ++ uint8_t saved_state[0x10]; ++ uint8_t saved_slave_state[0x10]; ++}; ++ ++#define to_sil164_priv(x) \ ++ ((struct sil164_priv *)to_encoder_slave(x)->slave_priv) ++ ++#define sil164_dbg(client, format, ...) do { \ ++ if (drm_debug & DRM_UT_KMS) \ ++ dev_printk(KERN_DEBUG, &client->dev, \ ++ "%s: " format, __func__, ## __VA_ARGS__); \ ++ } while (0) ++#define sil164_info(client, format, ...) \ ++ dev_info(&client->dev, format, __VA_ARGS__) ++#define sil164_err(client, format, ...) \ ++ dev_err(&client->dev, format, __VA_ARGS__) ++ ++#define SIL164_I2C_ADDR_MASTER 0x38 ++#define SIL164_I2C_ADDR_SLAVE 0x39 ++ ++/* HW register definitions */ ++ ++#define SIL164_VENDOR_LO 0x0 ++#define SIL164_VENDOR_HI 0x1 ++#define SIL164_DEVICE_LO 0x2 ++#define SIL164_DEVICE_HI 0x3 ++#define SIL164_REVISION 0x4 ++#define SIL164_FREQ_MIN 0x6 ++#define SIL164_FREQ_MAX 0x7 ++#define SIL164_CONTROL0 0x8 ++# define SIL164_CONTROL0_POWER_ON 0x01 ++# define SIL164_CONTROL0_EDGE_RISING 0x02 ++# define SIL164_CONTROL0_INPUT_24BIT 0x04 ++# define SIL164_CONTROL0_DUAL_EDGE 0x08 ++# define SIL164_CONTROL0_HSYNC_ON 0x10 ++# define SIL164_CONTROL0_VSYNC_ON 0x20 ++#define SIL164_DETECT 0x9 ++# define SIL164_DETECT_INTR_STAT 0x01 ++# define SIL164_DETECT_HOTPLUG_STAT 0x02 ++# define SIL164_DETECT_RECEIVER_STAT 0x04 ++# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00 ++# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08 ++# define SIL164_DETECT_OUT_MODE_HIGH 0x00 ++# define SIL164_DETECT_OUT_MODE_INTR 0x10 ++# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20 ++# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30 ++# define SIL164_DETECT_VSWING_STAT 0x80 ++#define SIL164_CONTROL1 0xa ++# define SIL164_CONTROL1_DESKEW_ENABLE 0x10 ++# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5 ++#define SIL164_GPIO 0xb ++#define SIL164_CONTROL2 0xc ++# define SIL164_CONTROL2_FILTER_ENABLE 0x01 ++# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1 ++# define SIL164_CONTROL2_DUALLINK_MASTER 0x40 ++# define SIL164_CONTROL2_SYNC_CONT 0x80 ++#define SIL164_DUALLINK 0xd ++# define SIL164_DUALLINK_ENABLE 0x10 ++# define SIL164_DUALLINK_SKEW_SHIFT 5 ++#define SIL164_PLLZONE 0xe ++# define SIL164_PLLZONE_STAT 0x08 ++# define SIL164_PLLZONE_FORCE_ON 0x10 ++# define SIL164_PLLZONE_FORCE_HIGH 0x20 ++ ++/* HW access functions */ ++ ++static void ++sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val) ++{ ++ uint8_t buf[] = {addr, val}; ++ int ret; ++ ++ ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); ++ if (ret < 0) ++ sil164_err(client, "Error %d writing to subaddress 0x%x\n", ++ ret, addr); ++} ++ ++static uint8_t ++sil164_read(struct i2c_client *client, uint8_t addr) ++{ ++ uint8_t val; ++ int ret; ++ ++ ret = i2c_master_send(client, &addr, sizeof(addr)); ++ if (ret < 0) ++ goto fail; ++ ++ ret = i2c_master_recv(client, &val, sizeof(val)); ++ if (ret < 0) ++ goto fail; ++ ++ return val; ++ ++fail: ++ sil164_err(client, "Error %d reading from subaddress 0x%x\n", ++ ret, addr); ++ return 0; ++} ++ ++static void ++sil164_save_state(struct i2c_client *client, uint8_t *state) ++{ ++ int i; ++ ++ for (i = 0x8; i <= 0xe; i++) ++ state[i] = sil164_read(client, i); ++} ++ ++static void ++sil164_restore_state(struct i2c_client *client, uint8_t *state) ++{ ++ int i; ++ ++ for (i = 0x8; i <= 0xe; i++) ++ sil164_write(client, i, state[i]); ++} ++ ++static void ++sil164_set_power_state(struct i2c_client *client, bool on) ++{ ++ uint8_t control0 = sil164_read(client, SIL164_CONTROL0); ++ ++ if (on) ++ control0 |= SIL164_CONTROL0_POWER_ON; ++ else ++ control0 &= ~SIL164_CONTROL0_POWER_ON; ++ ++ sil164_write(client, SIL164_CONTROL0, control0); ++} ++ ++static void ++sil164_init_state(struct i2c_client *client, ++ struct sil164_encoder_params *config, ++ bool duallink) ++{ ++ sil164_write(client, SIL164_CONTROL0, ++ SIL164_CONTROL0_HSYNC_ON | ++ SIL164_CONTROL0_VSYNC_ON | ++ (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) | ++ (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) | ++ (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0)); ++ ++ sil164_write(client, SIL164_DETECT, ++ SIL164_DETECT_INTR_STAT | ++ SIL164_DETECT_OUT_MODE_RECEIVER); ++ ++ sil164_write(client, SIL164_CONTROL1, ++ (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) | ++ (((config->input_skew + 4) & 0x7) ++ << SIL164_CONTROL1_DESKEW_INCR_SHIFT)); ++ ++ sil164_write(client, SIL164_CONTROL2, ++ SIL164_CONTROL2_SYNC_CONT | ++ (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) | ++ (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT)); ++ ++ sil164_write(client, SIL164_PLLZONE, 0); ++ ++ if (duallink) ++ sil164_write(client, SIL164_DUALLINK, ++ SIL164_DUALLINK_ENABLE | ++ (((config->duallink_skew + 4) & 0x7) ++ << SIL164_DUALLINK_SKEW_SHIFT)); ++ else ++ sil164_write(client, SIL164_DUALLINK, 0); ++} ++ ++/* DRM encoder functions */ ++ ++static void ++sil164_encoder_set_config(struct drm_encoder *encoder, void *params) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ ++ priv->config = *(struct sil164_encoder_params *)params; ++} ++ ++static void ++sil164_encoder_dpms(struct drm_encoder *encoder, int mode) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ bool on = (mode == DRM_MODE_DPMS_ON); ++ bool duallink = (on && encoder->crtc->mode.clock > 165000); ++ ++ sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on); ++ ++ if (priv->duallink_slave) ++ sil164_set_power_state(priv->duallink_slave, duallink); ++} ++ ++static void ++sil164_encoder_save(struct drm_encoder *encoder) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ ++ sil164_save_state(drm_i2c_encoder_get_client(encoder), ++ priv->saved_state); ++ ++ if (priv->duallink_slave) ++ sil164_save_state(priv->duallink_slave, ++ priv->saved_slave_state); ++} ++ ++static void ++sil164_encoder_restore(struct drm_encoder *encoder) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ ++ sil164_restore_state(drm_i2c_encoder_get_client(encoder), ++ priv->saved_state); ++ ++ if (priv->duallink_slave) ++ sil164_restore_state(priv->duallink_slave, ++ priv->saved_slave_state); ++} ++ ++static bool ++sil164_encoder_mode_fixup(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++static int ++sil164_encoder_mode_valid(struct drm_encoder *encoder, ++ struct drm_display_mode *mode) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ ++ if (mode->clock < 32000) ++ return MODE_CLOCK_LOW; ++ ++ if (mode->clock > 330000 || ++ (mode->clock > 165000 && !priv->duallink_slave)) ++ return MODE_CLOCK_HIGH; ++ ++ return MODE_OK; ++} ++ ++static void ++sil164_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ bool duallink = adjusted_mode->clock > 165000; ++ ++ sil164_init_state(drm_i2c_encoder_get_client(encoder), ++ &priv->config, duallink); ++ ++ if (priv->duallink_slave) ++ sil164_init_state(priv->duallink_slave, ++ &priv->config, duallink); ++ ++ sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON); ++} ++ ++static enum drm_connector_status ++sil164_encoder_detect(struct drm_encoder *encoder, ++ struct drm_connector *connector) ++{ ++ struct i2c_client *client = drm_i2c_encoder_get_client(encoder); ++ ++ if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT) ++ return connector_status_connected; ++ else ++ return connector_status_disconnected; ++} ++ ++static int ++sil164_encoder_get_modes(struct drm_encoder *encoder, ++ struct drm_connector *connector) ++{ ++ return 0; ++} ++ ++static int ++sil164_encoder_create_resources(struct drm_encoder *encoder, ++ struct drm_connector *connector) ++{ ++ return 0; ++} ++ ++static int ++sil164_encoder_set_property(struct drm_encoder *encoder, ++ struct drm_connector *connector, ++ struct drm_property *property, ++ uint64_t val) ++{ ++ return 0; ++} ++ ++static void ++sil164_encoder_destroy(struct drm_encoder *encoder) ++{ ++ struct sil164_priv *priv = to_sil164_priv(encoder); ++ ++ if (priv->duallink_slave) ++ i2c_unregister_device(priv->duallink_slave); ++ ++ kfree(priv); ++ drm_i2c_encoder_destroy(encoder); ++} ++ ++static struct drm_encoder_slave_funcs sil164_encoder_funcs = { ++ .set_config = sil164_encoder_set_config, ++ .destroy = sil164_encoder_destroy, ++ .dpms = sil164_encoder_dpms, ++ .save = sil164_encoder_save, ++ .restore = sil164_encoder_restore, ++ .mode_fixup = sil164_encoder_mode_fixup, ++ .mode_valid = sil164_encoder_mode_valid, ++ .mode_set = sil164_encoder_mode_set, ++ .detect = sil164_encoder_detect, ++ .get_modes = sil164_encoder_get_modes, ++ .create_resources = sil164_encoder_create_resources, ++ .set_property = sil164_encoder_set_property, ++}; ++ ++/* I2C driver functions */ ++ ++static int ++sil164_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 | ++ sil164_read(client, SIL164_VENDOR_LO); ++ int device = sil164_read(client, SIL164_DEVICE_HI) << 8 | ++ sil164_read(client, SIL164_DEVICE_LO); ++ int rev = sil164_read(client, SIL164_REVISION); ++ ++ if (vendor != 0x1 || device != 0x6) { ++ sil164_dbg(client, "Unknown device %x:%x.%x\n", ++ vendor, device, rev); ++ return -ENODEV; ++ } ++ ++ sil164_info(client, "Detected device %x:%x.%x\n", ++ vendor, device, rev); ++ ++ return 0; ++} ++ ++static int ++sil164_remove(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static struct i2c_client * ++sil164_detect_slave(struct i2c_client *client) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_msg msg = { ++ .addr = SIL164_I2C_ADDR_SLAVE, ++ .len = 0, ++ }; ++ const struct i2c_board_info info = { ++ I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE) ++ }; ++ ++ if (i2c_transfer(adap, &msg, 1) != 1) { ++ sil164_dbg(adap, "No dual-link slave found."); ++ return NULL; ++ } ++ ++ return i2c_new_device(adap, &info); ++} ++ ++static int ++sil164_encoder_init(struct i2c_client *client, ++ struct drm_device *dev, ++ struct drm_encoder_slave *encoder) ++{ ++ struct sil164_priv *priv; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ encoder->slave_priv = priv; ++ encoder->slave_funcs = &sil164_encoder_funcs; ++ ++ priv->duallink_slave = sil164_detect_slave(client); ++ ++ return 0; ++} ++ ++static struct i2c_device_id sil164_ids[] = { ++ { "sil164", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sil164_ids); ++ ++static struct drm_i2c_encoder_driver sil164_driver = { ++ .i2c_driver = { ++ .probe = sil164_probe, ++ .remove = sil164_remove, ++ .driver = { ++ .name = "sil164", ++ }, ++ .id_table = sil164_ids, ++ }, ++ .encoder_init = sil164_encoder_init, ++}; ++ ++/* Module initialization */ ++ ++static int __init ++sil164_init(void) ++{ ++ return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver); ++} ++ ++static void __exit ++sil164_exit(void) ++{ ++ drm_i2c_encoder_unregister(&sil164_driver); ++} ++ ++MODULE_AUTHOR("Francisco Jerez "); ++MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver"); ++MODULE_LICENSE("GPL and additional rights"); ++ ++module_init(sil164_init); ++module_exit(sil164_exit); +diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig +index 1175429..6b8967a 100644 +--- a/drivers/gpu/drm/nouveau/Kconfig ++++ b/drivers/gpu/drm/nouveau/Kconfig +@@ -41,4 +41,13 @@ config DRM_I2C_CH7006 + + This driver is currently only useful if you're also using + the nouveau driver. ++ ++config DRM_I2C_SIL164 ++ tristate "Silicon Image sil164 TMDS transmitter" ++ default m if DRM_NOUVEAU ++ help ++ Support for sil164 and similar single-link (or dual-link ++ when used in pairs) TMDS transmitters, used in some nVidia ++ video cards. ++ + endmenu +diff --git a/include/drm/i2c/sil164.h b/include/drm/i2c/sil164.h +new file mode 100644 +index 0000000..205e273 +--- /dev/null ++++ b/include/drm/i2c/sil164.h +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (C) 2010 Francisco Jerez. ++ * All Rights Reserved. ++ * ++ * 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 (including the ++ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. ++ * ++ */ ++ ++#ifndef __DRM_I2C_SIL164_H__ ++#define __DRM_I2C_SIL164_H__ ++ ++/** ++ * struct sil164_encoder_params ++ * ++ * Describes how the sil164 is connected to the GPU. It should be used ++ * as the @params parameter of its @set_config method. ++ * ++ * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf". ++ */ ++struct sil164_encoder_params { ++ enum { ++ SIL164_INPUT_EDGE_FALLING = 0, ++ SIL164_INPUT_EDGE_RISING ++ } input_edge; ++ ++ enum { ++ SIL164_INPUT_WIDTH_12BIT = 0, ++ SIL164_INPUT_WIDTH_24BIT ++ } input_width; ++ ++ enum { ++ SIL164_INPUT_SINGLE_EDGE = 0, ++ SIL164_INPUT_DUAL_EDGE ++ } input_dual; ++ ++ enum { ++ SIL164_PLL_FILTER_ON = 0, ++ SIL164_PLL_FILTER_OFF, ++ } pll_filter; ++ ++ int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */ ++ int duallink_skew; /** < Allowed range [-4, 3]. */ ++}; ++ ++#endif +-- +1.7.2 + diff --git a/drm-simplify-i2c-config.patch b/drm-simplify-i2c-config.patch new file mode 100644 index 000000000..c1fed73d7 --- /dev/null +++ b/drm-simplify-i2c-config.patch @@ -0,0 +1,45 @@ +From 74ef65374ae6d0eead4a631aea3aca80d016ff0f Mon Sep 17 00:00:00 2001 +From: Francisco Jerez +Date: Thu, 22 Jul 2010 17:07:38 +0200 +Subject: [PATCH 1/5] drm-simplify-i2c-config + +drm/kms: Simplify setup of the initial I2C encoder config. + +In most use cases the driver will be using the same static config all +the time: interpreting i2c_board_info::platform_data as the default +config we can can save the GPU driver a redundant set_config() call. + +Signed-off-by: Francisco Jerez +Signed-off-by: Dave Airlie +--- + drivers/gpu/drm/drm_encoder_slave.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c +index f018469..d62c064 100644 +--- a/drivers/gpu/drm/drm_encoder_slave.c ++++ b/drivers/gpu/drm/drm_encoder_slave.c +@@ -41,6 +41,9 @@ + * &drm_encoder_slave. The @slave_funcs field will be initialized with + * the hooks provided by the slave driver. + * ++ * If @info->platform_data is non-NULL it will be used as the initial ++ * slave config. ++ * + * Returns 0 on success or a negative errno on failure, in particular, + * -ENODEV is returned when no matching driver is found. + */ +@@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev, + if (err) + goto fail_unregister; + ++ if (info->platform_data) ++ encoder->slave_funcs->set_config(&encoder->base, ++ info->platform_data); ++ + return 0; + + fail_unregister: +-- +1.7.2 + diff --git a/kernel.spec b/kernel.spec index fa52cd6fb..d7fc01754 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 4 +%global baserelease 5 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -649,8 +649,13 @@ Patch1555: fix_xen_guest_on_old_EC2.patch # DRM Patch1801: drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch Patch1802: revert-drm-kms-toggle-poll-around-switcheroo.patch +# drm fixes nouveau depends on +Patch1805: drm-simplify-i2c-config.patch +Patch1806: drm-sil164-module.patch +Patch1807: drm-i2c-ch7006-fix.patch # nouveau + drm fixes Patch1810: drm-nouveau-updates.patch +Patch1811: drm-nouveau-race-fix.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1250,8 +1255,12 @@ ApplyPatch fix_xen_guest_on_old_EC2.patch #ApplyPatch drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch #ApplyPatch revert-drm-kms-toggle-poll-around-switcheroo.patch +ApplyPatch drm-simplify-i2c-config.patch +ApplyPatch drm-sil164-module.patch +ApplyPatch drm-i2c-ch7006-fix.patch # Nouveau DRM + drm fixes ApplyPatch drm-nouveau-updates.patch +ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch ApplyPatch drm-intel-make-lvds-work.patch @@ -1881,6 +1890,9 @@ fi # and build. %changelog +* Tue Aug 10 2010 Ben Skeggs 2.6.35.1-5.rc1 +- nouveau: bring in patches up to what will be in 2.6.36 + * Sat Aug 07 2010 Chuck Ebbert 2.6.35.1-4.rc1 - Linux 2.6.35.1-rc1 From 4ed348073c35c746e2d7dd4a4a8aa280cad356d4 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 10 Aug 2010 16:35:19 -0400 Subject: [PATCH 010/277] - Linux 2.6.35.1 --- kernel.spec | 7 +++++-- sources | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel.spec b/kernel.spec index d7fc01754..ae8ecdc15 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 5 +%global baserelease 6 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -62,7 +62,7 @@ Summary: The Linux kernel # Do we have a -stable update to apply? %define stable_update 1 # Is it a -stable RC? -%define stable_rc 1 +%define stable_rc 0 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1890,6 +1890,9 @@ fi # and build. %changelog +* Tue Aug 10 2010 Chuck Ebbert 2.6.35.1-6 +- Linux 2.6.35.1 + * Tue Aug 10 2010 Ben Skeggs 2.6.35.1-5.rc1 - nouveau: bring in patches up to what will be in 2.6.36 diff --git a/sources b/sources index ac901c98a..272eb45fc 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -58fd95172e18ed00310ec8b2f625f38f patch-2.6.35.1-rc1.bz2 +3b9d79bebb2e022c0906ca1cd54bd970 patch-2.6.35.1.bz2 From d6d51a1a425c1f4be8167dfd866e7fbd9d3c9d67 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 13 Aug 2010 07:47:42 -0400 Subject: [PATCH 011/277] - Linux 2.6.35.2-rc1 - Comment out patches merged in -stable: linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch linux-2.6-ext4-fix-freeze-deadlock.patch - New config option: CONFIG_CRYPTO_MANAGER_TESTS=y --- config-generic | 1 + kernel.spec | 18 +++++++++++++----- sources | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/config-generic b/config-generic index 7cc1a746b..a6719bf98 100644 --- a/config-generic +++ b/config-generic @@ -3602,6 +3602,7 @@ CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_MANAGER_TESTS=y # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ARC4=m diff --git a/kernel.spec b/kernel.spec index ae8ecdc15..d8b034b99 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 6 +%global baserelease 7 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,9 +60,9 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 1 +%define stable_update 2 # Is it a -stable RC? -%define stable_rc 0 +%define stable_rc 1 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1130,7 +1130,7 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R ApplyPatch linux-2.6-hotfixes.patch -ApplyPatch linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch +#ApplyPatch linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch # Roland's utrace ptrace replacement. ApplyPatch git-utrace.patch @@ -1164,7 +1164,7 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # # ext4 -ApplyPatch linux-2.6-ext4-fix-freeze-deadlock.patch +#ApplyPatch linux-2.6-ext4-fix-freeze-deadlock.patch # xfs @@ -1890,6 +1890,14 @@ fi # and build. %changelog +* Fri Aug 13 2010 Chuck Ebbert 2.6.35.2-7.rc1 +- Linux 2.6.35.2-rc1 +- Comment out patches merged in -stable: + linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch + linux-2.6-ext4-fix-freeze-deadlock.patch +- New config option: + CONFIG_CRYPTO_MANAGER_TESTS=y + * Tue Aug 10 2010 Chuck Ebbert 2.6.35.1-6 - Linux 2.6.35.1 diff --git a/sources b/sources index 272eb45fc..26e3dd113 100644 --- a/sources +++ b/sources @@ -1,2 +1,3 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 3b9d79bebb2e022c0906ca1cd54bd970 patch-2.6.35.1.bz2 +b930a0ff7060566bb2f91755c86de196 patch-2.6.35.2-rc1.bz2 From e1151597d511df4ef41ee0aa3252e9d357c9008f Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sun, 15 Aug 2010 04:26:48 -0400 Subject: [PATCH 012/277] Linux 2.6.35.2 --- kernel.spec | 13 ++-- linux-2.6-ext4-fix-freeze-deadlock.patch | 46 ------------ ...894d289d69bacf5acd983c97cd6e21a14c08.patch | 75 ------------------- sources | 3 +- 4 files changed, 6 insertions(+), 131 deletions(-) delete mode 100644 linux-2.6-ext4-fix-freeze-deadlock.patch delete mode 100644 linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch diff --git a/kernel.spec b/kernel.spec index d8b034b99..3b299f93a 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 7 +%global baserelease 8 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -62,7 +62,7 @@ Summary: The Linux kernel # Do we have a -stable update to apply? %define stable_update 2 # Is it a -stable RC? -%define stable_rc 1 +%define stable_rc 0 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -597,8 +597,6 @@ Patch09: linux-2.6-upstream-reverts.patch # Standalone patches Patch20: linux-2.6-hotfixes.patch -Patch21: linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch - Patch30: git-utrace.patch Patch31: utrace-ptrace-fix-build.patch Patch32: utrace-remove-use-of-kref_set.patch @@ -687,7 +685,6 @@ Patch2915: lirc-staging-2.6.36.patch Patch2917: hdpvr-ir-enable.patch # fs fixes -Patch3000: linux-2.6-ext4-fix-freeze-deadlock.patch # NFSv4 @@ -1130,8 +1127,6 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R ApplyPatch linux-2.6-hotfixes.patch -#ApplyPatch linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch - # Roland's utrace ptrace replacement. ApplyPatch git-utrace.patch ApplyPatch utrace-ptrace-fix-build.patch @@ -1164,7 +1159,6 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # # ext4 -#ApplyPatch linux-2.6-ext4-fix-freeze-deadlock.patch # xfs @@ -1890,6 +1884,9 @@ fi # and build. %changelog +* Sun Aug 15 2010 Chuck Ebbert 2.6.35.2-8 +- Linux 2.6.35.2 + * Fri Aug 13 2010 Chuck Ebbert 2.6.35.2-7.rc1 - Linux 2.6.35.2-rc1 - Comment out patches merged in -stable: diff --git a/linux-2.6-ext4-fix-freeze-deadlock.patch b/linux-2.6-ext4-fix-freeze-deadlock.patch deleted file mode 100644 index e7eb817af..000000000 --- a/linux-2.6-ext4-fix-freeze-deadlock.patch +++ /dev/null @@ -1,46 +0,0 @@ -[PATCH] ext4: fix freeze deadlock under IO - -Commit 6b0310fbf087ad6 caused a regression resulting in deadlocks -when freezing a filesystem which had active IO; the vfs_check_frozen -level (SB_FREEZE_WRITE) did not let the freeze-related IO syncing -through. Duh. - -Changing the test to FREEZE_TRANS should let the normal freeze -syncing get through the fs, but still block any transactions from -starting once the fs is completely frozen. - -I tested this by running fsstress in the background while periodically -snapshotting the fs and running fsck on the result. I ran into -occasional deadlocks, but different ones. I think this is a -fine fix for the problem at hand, and the other deadlocky things -will need more investigation. - -Reported-by: Phillip Susi -Signed-off-by: Eric Sandeen ---- - -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 4e8983a..a45ced9 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -241,7 +241,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) - if (sb->s_flags & MS_RDONLY) - return ERR_PTR(-EROFS); - -- vfs_check_frozen(sb, SB_FREEZE_WRITE); -+ vfs_check_frozen(sb, SB_FREEZE_TRANS); - /* Special case here: if the journal has aborted behind our - * backs (eg. EIO in the commit thread), then we still need to - * take the FS itself readonly cleanly. */ -@@ -3491,7 +3491,7 @@ int ext4_force_commit(struct super_block *sb) - - journal = EXT4_SB(sb)->s_journal; - if (journal) { -- vfs_check_frozen(sb, SB_FREEZE_WRITE); -+ vfs_check_frozen(sb, SB_FREEZE_TRANS); - ret = ext4_journal_force_commit(journal); - } - - - - diff --git a/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch b/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch deleted file mode 100644 index c13d98776..000000000 --- a/linux-2.6-tip.git-396e894d289d69bacf5acd983c97cd6e21a14c08.patch +++ /dev/null @@ -1,75 +0,0 @@ -From: Peter Zijlstra -Date: Fri, 9 Jul 2010 13:12:27 +0000 (+0200) -Subject: sched: Revert nohz_ratelimit() for now -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fx86%2Flinux-2.6-tip.git;a=commitdiff_plain;h=396e894d289d69bacf5acd983c97cd6e21a14c08 - -sched: Revert nohz_ratelimit() for now - -Norbert reported that nohz_ratelimit() causes his laptop to burn about -4W (40%) extra. For now back out the change and see if we can adjust -the power management code to make better decisions. - -Reported-by: Norbert Preining -Signed-off-by: Peter Zijlstra -Acked-by: Mike Galbraith -Cc: Arjan van de Ven -LKML-Reference: -Signed-off-by: Ingo Molnar ---- - -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 747fcae..6e0bb86 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -273,17 +273,11 @@ extern cpumask_var_t nohz_cpu_mask; - #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ) - extern int select_nohz_load_balancer(int cpu); - extern int get_nohz_load_balancer(void); --extern int nohz_ratelimit(int cpu); - #else - static inline int select_nohz_load_balancer(int cpu) - { - return 0; - } -- --static inline int nohz_ratelimit(int cpu) --{ -- return 0; --} - #endif - - /* -diff --git a/kernel/sched.c b/kernel/sched.c -index f52a880..63b4a14 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -1232,16 +1232,6 @@ void wake_up_idle_cpu(int cpu) - smp_send_reschedule(cpu); - } - --int nohz_ratelimit(int cpu) --{ -- struct rq *rq = cpu_rq(cpu); -- u64 diff = rq->clock - rq->nohz_stamp; -- -- rq->nohz_stamp = rq->clock; -- -- return diff < (NSEC_PER_SEC / HZ) >> 1; --} -- - #endif /* CONFIG_NO_HZ */ - - static u64 sched_avg_period(void) -diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c -index 813993b..f898af6 100644 ---- a/kernel/time/tick-sched.c -+++ b/kernel/time/tick-sched.c -@@ -325,7 +325,7 @@ void tick_nohz_stop_sched_tick(int inidle) - } while (read_seqretry(&xtime_lock, seq)); - - if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) || -- arch_needs_cpu(cpu) || nohz_ratelimit(cpu)) { -+ arch_needs_cpu(cpu)) { - next_jiffies = last_jiffies + 1; - delta_jiffies = 1; - } else { diff --git a/sources b/sources index 26e3dd113..824148714 100644 --- a/sources +++ b/sources @@ -1,3 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -3b9d79bebb2e022c0906ca1cd54bd970 patch-2.6.35.1.bz2 -b930a0ff7060566bb2f91755c86de196 patch-2.6.35.2-rc1.bz2 +c0d9ece021feaf0b86c031ab59840ea8 patch-2.6.35.2.bz2 From b9878dcfec74417c805c6dbd21a6cdd13f2deb2a Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 16 Aug 2010 11:57:58 -0400 Subject: [PATCH 013/277] Add ir-core streamzap driver, drop lirc_streamzap Signed-off-by: Jarod Wilson --- config-generic | 4 +- kernel.spec | 7 +- linux-2.6-v4l-dvb-ir-core-streamzap.patch | 944 ++++++++++++++++++++++ lirc-staging-2.6.36.patch | 845 +------------------ 4 files changed, 958 insertions(+), 842 deletions(-) create mode 100644 linux-2.6-v4l-dvb-ir-core-streamzap.patch diff --git a/config-generic b/config-generic index a6719bf98..d61368e37 100644 --- a/config-generic +++ b/config-generic @@ -2587,9 +2587,11 @@ CONFIG_IR_RC5_DECODER=m CONFIG_IR_RC6_DECODER=m CONFIG_IR_JVC_DECODER=m CONFIG_IR_SONY_DECODER=m +CONFIG_IR_RC5_SZ_DECODER=m CONFIG_IR_LIRC_CODEC=m CONFIG_IR_IMON=m CONFIG_IR_MCEUSB=m +CONFIG_IR_STREAMZAP=m CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -4015,7 +4017,7 @@ CONFIG_LIRC_SERIAL=m CONFIG_LIRC_SERIAL_TRANSMITTER=y CONFIG_LIRC_SASEM=m CONFIG_LIRC_SIR=m -CONFIG_LIRC_STREAMZAP=m +# CONFIG_LIRC_STREAMZAP is not set CONFIG_LIRC_TTUSBIR=m # CONFIG_SAMPLES is not set diff --git a/kernel.spec b/kernel.spec index 3b299f93a..20eefe23c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 8 +%global baserelease 9 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -679,6 +679,7 @@ Patch2910: linux-2.6-v4l-dvb-add-lgdt3304-support.patch Patch2911: linux-2.6-v4l-dvb-add-kworld-a340-support.patch Patch2912: linux-2.6-v4l-dvb-ir-core-update.patch Patch2913: linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch +Patch2914: linux-2.6-v4l-dvb-ir-core-streamzap.patch Patch2915: lirc-staging-2.6.36.patch #Patch2916: lirc-staging-2.6.36-fixes.patch @@ -1276,6 +1277,7 @@ ApplyPatch linux-2.6-v4l-dvb-uvcvideo-update.patch ApplyPatch linux-2.6-v4l-dvb-ir-core-update.patch ApplyPatch linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch +ApplyPatch linux-2.6-v4l-dvb-ir-core-streamzap.patch ApplyPatch linux-2.6-v4l-dvb-add-lgdt3304-support.patch ApplyPatch linux-2.6-v4l-dvb-add-kworld-a340-support.patch @@ -1884,6 +1886,9 @@ fi # and build. %changelog +* Mon Aug 16 2010 Jarod Wilson 2.6.35.2-9 +- Add ir-core streamzap driver, nuke lirc_streamzap + * Sun Aug 15 2010 Chuck Ebbert 2.6.35.2-8 - Linux 2.6.35.2 diff --git a/linux-2.6-v4l-dvb-ir-core-streamzap.patch b/linux-2.6-v4l-dvb-ir-core-streamzap.patch new file mode 100644 index 000000000..e1caed7b9 --- /dev/null +++ b/linux-2.6-v4l-dvb-ir-core-streamzap.patch @@ -0,0 +1,944 @@ +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/ir-core-priv.h linux-2.6.35.x86_64/drivers/media/IR/ir-core-priv.h +--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-core-priv.h 2010-08-15 17:50:34.572382442 -0400 ++++ linux-2.6.35.x86_64/drivers/media/IR/ir-core-priv.h 2010-08-16 00:11:42.756124321 -0400 +@@ -73,6 +73,12 @@ struct ir_raw_event_ctrl { + bool first; + bool toggle; + } jvc; ++ struct rc5_sz_dec { ++ int state; ++ u32 bits; ++ unsigned count; ++ unsigned wanted_bits; ++ } rc5_sz; + struct lirc_codec { + struct ir_input_dev *ir_dev; + struct lirc_driver *drv; +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/ir-rc5-sz-decoder.c linux-2.6.35.x86_64/drivers/media/IR/ir-rc5-sz-decoder.c +--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-rc5-sz-decoder.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.x86_64/drivers/media/IR/ir-rc5-sz-decoder.c 2010-08-16 00:07:19.962608685 -0400 +@@ -0,0 +1,153 @@ ++/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol ++ * ++ * Copyright (C) 2010 by Mauro Carvalho Chehab ++ * Copyright (C) 2010 by Jarod Wilson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++/* ++ * This code handles the 15 bit RC5-ish protocol used by the Streamzap ++ * PC Remote. ++ * It considers a carrier of 36 kHz, with a total of 15 bits, where ++ * the first two bits are start bits, and a third one is a filing bit ++ */ ++ ++#include "ir-core-priv.h" ++ ++#define RC5_SZ_NBITS 15 ++#define RC5_UNIT 888888 /* ns */ ++#define RC5_BIT_START (1 * RC5_UNIT) ++#define RC5_BIT_END (1 * RC5_UNIT) ++ ++enum rc5_sz_state { ++ STATE_INACTIVE, ++ STATE_BIT_START, ++ STATE_BIT_END, ++ STATE_FINISHED, ++}; ++ ++/** ++ * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space ++ * @input_dev: the struct input_dev descriptor of the device ++ * @ev: the struct ir_raw_event descriptor of the pulse/space ++ * ++ * This function returns -EINVAL if the pulse violates the state machine ++ */ ++static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev) ++{ ++ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz; ++ u8 toggle, command, system; ++ u32 scancode; ++ ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ)) ++ return 0; ++ ++ if (IS_RESET(ev)) { ++ data->state = STATE_INACTIVE; ++ return 0; ++ } ++ ++ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) ++ goto out; ++ ++again: ++ IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", ++ data->state, TO_US(ev.duration), TO_STR(ev.pulse)); ++ ++ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) ++ return 0; ++ ++ switch (data->state) { ++ ++ case STATE_INACTIVE: ++ if (!ev.pulse) ++ break; ++ ++ data->state = STATE_BIT_START; ++ data->count = 1; ++ data->wanted_bits = RC5_SZ_NBITS; ++ decrease_duration(&ev, RC5_BIT_START); ++ goto again; ++ ++ case STATE_BIT_START: ++ if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) ++ break; ++ ++ data->bits <<= 1; ++ if (!ev.pulse) ++ data->bits |= 1; ++ data->count++; ++ data->state = STATE_BIT_END; ++ return 0; ++ ++ case STATE_BIT_END: ++ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) ++ break; ++ ++ if (data->count == data->wanted_bits) ++ data->state = STATE_FINISHED; ++ else ++ data->state = STATE_BIT_START; ++ ++ decrease_duration(&ev, RC5_BIT_END); ++ goto again; ++ ++ case STATE_FINISHED: ++ if (ev.pulse) ++ break; ++ ++ /* RC5-sz */ ++ command = (data->bits & 0x0003F) >> 0; ++ system = (data->bits & 0x02FC0) >> 6; ++ toggle = (data->bits & 0x01000) ? 1 : 0; ++ scancode = system << 6 | command; ++ ++ IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", ++ scancode, toggle); ++ ++ ir_keydown(input_dev, scancode, toggle); ++ data->state = STATE_INACTIVE; ++ return 0; ++ } ++ ++out: ++ IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", ++ data->state, TO_US(ev.duration), TO_STR(ev.pulse)); ++ data->state = STATE_INACTIVE; ++ return -EINVAL; ++} ++ ++static struct ir_raw_handler rc5_sz_handler = { ++ .protocols = IR_TYPE_RC5_SZ, ++ .decode = ir_rc5_sz_decode, ++}; ++ ++static int __init ir_rc5_sz_decode_init(void) ++{ ++ ir_raw_handler_register(&rc5_sz_handler); ++ ++ printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); ++ return 0; ++} ++ ++static void __exit ir_rc5_sz_decode_exit(void) ++{ ++ ir_raw_handler_unregister(&rc5_sz_handler); ++} ++ ++module_init(ir_rc5_sz_decode_init); ++module_exit(ir_rc5_sz_decode_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jarod Wilson "); ++MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); ++MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/ir-sysfs.c linux-2.6.35.x86_64/drivers/media/IR/ir-sysfs.c +--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-sysfs.c 2010-08-15 17:50:34.574380413 -0400 ++++ linux-2.6.35.x86_64/drivers/media/IR/ir-sysfs.c 2010-08-16 00:23:24.893168856 -0400 +@@ -93,6 +93,11 @@ static ssize_t show_protocols(struct dev + else if (allowed & IR_TYPE_SONY) + tmp += sprintf(tmp, "sony "); + ++ if (allowed & enabled & IR_TYPE_RC5_SZ) ++ tmp += sprintf(tmp, "[rc5sz] "); ++ else if (allowed & IR_TYPE_RC5_SZ) ++ tmp += sprintf(tmp, "rc5sz "); ++ + if (allowed & enabled & IR_TYPE_LIRC) + tmp += sprintf(tmp, "[lirc] "); + else if (allowed & IR_TYPE_LIRC) +@@ -165,6 +170,9 @@ static ssize_t store_protocols(struct de + } else if (!strncasecmp(tmp, "sony", 4)) { + tmp += 4; + mask = IR_TYPE_SONY; ++ } else if (!strncasecmp(tmp, "rc5sz", 5)) { ++ tmp += 5; ++ mask = IR_TYPE_RC5_SZ; + } else if (!strncasecmp(tmp, "lirc", 4)) { + tmp += 4; + mask = IR_TYPE_LIRC; +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/Kconfig linux-2.6.35.x86_64/drivers/media/IR/Kconfig +--- linux-2.6.35.x86_64.orig/drivers/media/IR/Kconfig 2010-08-15 17:50:34.571382513 -0400 ++++ linux-2.6.35.x86_64/drivers/media/IR/Kconfig 2010-08-16 00:10:09.292873588 -0400 +@@ -69,6 +69,16 @@ config IR_SONY_DECODER + Enable this option if you have an infrared remote control which + uses the Sony protocol, and you need software decoding support. + ++config IR_RC5_SZ_DECODER ++ tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol" ++ depends on IR_CORE ++ select BITREVERSE ++ default y ++ ++ ---help--- ++ Enable this option if you have IR with RC-5 (streamzap) protocol, ++ and if the IR is decoded in software. ++ + config IR_LIRC_CODEC + tristate "Enable IR to LIRC bridge" + depends on IR_CORE +@@ -102,3 +112,15 @@ config IR_MCEUSB + + To compile this driver as a module, choose M here: the + module will be called mceusb. ++ ++config IR_STREAMZAP ++ tristate "Streamzap PC Remote IR Receiver" ++ depends on USB_ARCH_HAS_HCD ++ depends on IR_CORE ++ select USB ++ ---help--- ++ Say Y here if you want to use a Streamzap PC Remote ++ Infrared Receiver. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called streamzap. +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/Makefile linux-2.6.35.x86_64/drivers/media/IR/keymaps/Makefile +--- linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/Makefile 2010-08-15 17:50:34.575383346 -0400 ++++ linux-2.6.35.x86_64/drivers/media/IR/keymaps/Makefile 2010-08-16 00:05:47.400370419 -0400 +@@ -60,6 +60,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t + rc-rc5-tv.o \ + rc-rc6-mce.o \ + rc-real-audio-220-32-keys.o \ ++ rc-streamzap.o \ + rc-tbs-nec.o \ + rc-terratec-cinergy-xs.o \ + rc-tevii-nec.o \ +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/rc-streamzap.c linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-streamzap.c +--- linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/rc-streamzap.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-streamzap.c 2010-08-16 00:05:47.402370467 -0400 +@@ -0,0 +1,82 @@ ++/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use ++ * with the Streamzap PC Remote IR Receiver. ++ * ++ * Copyright (c) 2010 by Jarod Wilson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++static struct ir_scancode streamzap[] = { ++/* ++ * The Streamzap remote is almost, but not quite, RC-5, as it has an extra ++ * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently, ++ * an additional RC-5-sz decoder is being deployed to support it, but it ++ * may be possible to merge it back with the standard RC-5 decoder. ++ */ ++ { 0x28c0, KEY_NUMERIC_0 }, ++ { 0x28c1, KEY_NUMERIC_1 }, ++ { 0x28c2, KEY_NUMERIC_2 }, ++ { 0x28c3, KEY_NUMERIC_3 }, ++ { 0x28c4, KEY_NUMERIC_4 }, ++ { 0x28c5, KEY_NUMERIC_5 }, ++ { 0x28c6, KEY_NUMERIC_6 }, ++ { 0x28c7, KEY_NUMERIC_7 }, ++ { 0x28c8, KEY_NUMERIC_8 }, ++ { 0x28c9, KEY_NUMERIC_9 }, ++ { 0x28ca, KEY_POWER }, ++ { 0x28cb, KEY_MUTE }, ++ { 0x28cc, KEY_CHANNELUP }, ++ { 0x28cd, KEY_VOLUMEUP }, ++ { 0x28ce, KEY_CHANNELDOWN }, ++ { 0x28cf, KEY_VOLUMEDOWN }, ++ { 0x28d0, KEY_UP }, ++ { 0x28d1, KEY_LEFT }, ++ { 0x28d2, KEY_OK }, ++ { 0x28d3, KEY_RIGHT }, ++ { 0x28d4, KEY_DOWN }, ++ { 0x28d5, KEY_MENU }, ++ { 0x28d6, KEY_EXIT }, ++ { 0x28d7, KEY_PLAY }, ++ { 0x28d8, KEY_PAUSE }, ++ { 0x28d9, KEY_STOP }, ++ { 0x28da, KEY_BACK }, ++ { 0x28db, KEY_FORWARD }, ++ { 0x28dc, KEY_RECORD }, ++ { 0x28dd, KEY_REWIND }, ++ { 0x28de, KEY_FASTFORWARD }, ++ { 0x28e0, KEY_RED }, ++ { 0x28e1, KEY_GREEN }, ++ { 0x28e2, KEY_YELLOW }, ++ { 0x28e3, KEY_BLUE }, ++ ++}; ++ ++static struct rc_keymap streamzap_map = { ++ .map = { ++ .scan = streamzap, ++ .size = ARRAY_SIZE(streamzap), ++ .ir_type = IR_TYPE_RC5, ++ .name = RC_MAP_STREAMZAP, ++ } ++}; ++ ++static int __init init_rc_map_streamzap(void) ++{ ++ return ir_register_map(&streamzap_map); ++} ++ ++static void __exit exit_rc_map_streamzap(void) ++{ ++ ir_unregister_map(&streamzap_map); ++} ++ ++module_init(init_rc_map_streamzap) ++module_exit(exit_rc_map_streamzap) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jarod Wilson "); +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/Makefile linux-2.6.35.x86_64/drivers/media/IR/Makefile +--- linux-2.6.35.x86_64.orig/drivers/media/IR/Makefile 2010-08-15 17:50:34.571382513 -0400 ++++ linux-2.6.35.x86_64/drivers/media/IR/Makefile 2010-08-16 00:10:29.478144601 -0400 +@@ -11,8 +11,10 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-d + obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o + obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o + obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o ++obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o + obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o + + # stand-alone IR receivers/transmitters + obj-$(CONFIG_IR_IMON) += imon.o + obj-$(CONFIG_IR_MCEUSB) += mceusb.o ++obj-$(CONFIG_IR_STREAMZAP) += streamzap.o +diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/streamzap.c linux-2.6.35.x86_64/drivers/media/IR/streamzap.c +--- linux-2.6.35.x86_64.orig/drivers/media/IR/streamzap.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.x86_64/drivers/media/IR/streamzap.c 2010-08-16 00:12:43.223932881 -0400 +@@ -0,0 +1,569 @@ ++/* ++ * Streamzap Remote Control driver ++ * ++ * Copyright (c) 2005 Christoph Bartelmus ++ * Copyright (c) 2010 Jarod Wilson ++ * ++ * This driver was based on the work of Greg Wickham and Adrian ++ * Dewhurst. It was substantially rewritten to support correct signal ++ * gaps and now maintains a delay buffer, which is used to present ++ * consistent timing behaviour to user space applications. Without the ++ * delay buffer an ugly hack would be required in lircd, which can ++ * cause sluggish signal decoding in certain situations. ++ * ++ * Ported to in-kernel ir-core interface by Jarod Wilson ++ * ++ * This driver is based on the USB skeleton driver packaged with the ++ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_VERSION "1.61" ++#define DRIVER_NAME "streamzap" ++#define DRIVER_DESC "Streamzap Remote Control driver" ++ ++#ifdef CONFIG_USB_DEBUG ++static int debug = 1; ++#else ++static int debug; ++#endif ++ ++#define USB_STREAMZAP_VENDOR_ID 0x0e9c ++#define USB_STREAMZAP_PRODUCT_ID 0x0000 ++ ++/* table of devices that work with this driver */ ++static struct usb_device_id streamzap_table[] = { ++ /* Streamzap Remote Control */ ++ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, ++ /* Terminating entry */ ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(usb, streamzap_table); ++ ++#define STREAMZAP_PULSE_MASK 0xf0 ++#define STREAMZAP_SPACE_MASK 0x0f ++#define STREAMZAP_TIMEOUT 0xff ++#define STREAMZAP_RESOLUTION 256 ++ ++/* number of samples buffered */ ++#define SZ_BUF_LEN 128 ++ ++/* from ir-rc5-sz-decoder.c */ ++#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE ++#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") ++#else ++#define load_rc5_sz_decode() 0 ++#endif ++ ++enum StreamzapDecoderState { ++ PulseSpace, ++ FullPulse, ++ FullSpace, ++ IgnorePulse ++}; ++ ++/* structure to hold our device specific stuff */ ++struct streamzap_ir { ++ ++ /* ir-core */ ++ struct ir_dev_props *props; ++ ++ /* core device info */ ++ struct device *dev; ++ struct input_dev *idev; ++ ++ /* usb */ ++ struct usb_device *usbdev; ++ struct usb_interface *interface; ++ struct usb_endpoint_descriptor *endpoint; ++ struct urb *urb_in; ++ ++ /* buffer & dma */ ++ unsigned char *buf_in; ++ dma_addr_t dma_in; ++ unsigned int buf_in_len; ++ ++ /* track what state we're in */ ++ enum StreamzapDecoderState decoder_state; ++ /* tracks whether we are currently receiving some signal */ ++ bool idle; ++ /* sum of signal lengths received since signal start */ ++ unsigned long sum; ++ /* start time of signal; necessary for gap tracking */ ++ struct timeval signal_last; ++ struct timeval signal_start; ++ bool timeout_enabled; ++ ++ char name[128]; ++ char phys[64]; ++}; ++ ++ ++/* local function prototypes */ ++static int streamzap_probe(struct usb_interface *interface, ++ const struct usb_device_id *id); ++static void streamzap_disconnect(struct usb_interface *interface); ++static void streamzap_callback(struct urb *urb); ++static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); ++static int streamzap_resume(struct usb_interface *intf); ++ ++/* usb specific object needed to register this driver with the usb subsystem */ ++static struct usb_driver streamzap_driver = { ++ .name = DRIVER_NAME, ++ .probe = streamzap_probe, ++ .disconnect = streamzap_disconnect, ++ .suspend = streamzap_suspend, ++ .resume = streamzap_resume, ++ .id_table = streamzap_table, ++}; ++ ++static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) ++{ ++ ir_raw_event_store(sz->idev, &rawir); ++} ++ ++static void sz_push_full_pulse(struct streamzap_ir *sz, ++ unsigned char value) ++{ ++ struct ir_raw_event rawir; ++ ++ if (sz->idle) { ++ long deltv; ++ ++ sz->signal_last = sz->signal_start; ++ do_gettimeofday(&sz->signal_start); ++ ++ deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; ++ rawir.pulse = false; ++ if (deltv > 15) { ++ /* really long time */ ++ rawir.duration = IR_MAX_DURATION; ++ } else { ++ rawir.duration = (int)(deltv * 1000000 + ++ sz->signal_start.tv_usec - ++ sz->signal_last.tv_usec); ++ rawir.duration -= sz->sum; ++ rawir.duration *= 1000; ++ rawir.duration &= IR_MAX_DURATION; ++ } ++ dev_dbg(sz->dev, "ls %u\n", rawir.duration); ++ sz_push(sz, rawir); ++ ++ sz->idle = false; ++ sz->sum = 0; ++ } ++ ++ rawir.pulse = true; ++ rawir.duration = ((int) value) * STREAMZAP_RESOLUTION; ++ rawir.duration += STREAMZAP_RESOLUTION / 2; ++ sz->sum += rawir.duration; ++ rawir.duration *= 1000; ++ rawir.duration &= IR_MAX_DURATION; ++ dev_dbg(sz->dev, "p %u\n", rawir.duration); ++ sz_push(sz, rawir); ++} ++ ++static void sz_push_half_pulse(struct streamzap_ir *sz, ++ unsigned char value) ++{ ++ sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4); ++} ++ ++static void sz_push_full_space(struct streamzap_ir *sz, ++ unsigned char value) ++{ ++ struct ir_raw_event rawir; ++ ++ rawir.pulse = false; ++ rawir.duration = ((int) value) * STREAMZAP_RESOLUTION; ++ rawir.duration += STREAMZAP_RESOLUTION / 2; ++ sz->sum += rawir.duration; ++ rawir.duration *= 1000; ++ dev_dbg(sz->dev, "s %u\n", rawir.duration); ++ sz_push(sz, rawir); ++} ++ ++static void sz_push_half_space(struct streamzap_ir *sz, ++ unsigned long value) ++{ ++ sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK); ++} ++ ++/** ++ * streamzap_callback - usb IRQ handler callback ++ * ++ * This procedure is invoked on reception of data from ++ * the usb remote. ++ */ ++static void streamzap_callback(struct urb *urb) ++{ ++ struct streamzap_ir *sz; ++ unsigned int i; ++ int len; ++ static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) & ++ IR_MAX_DURATION) | 0x03000000); ++ ++ if (!urb) ++ return; ++ ++ sz = urb->context; ++ len = urb->actual_length; ++ ++ switch (urb->status) { ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* ++ * this urb is terminated, clean up. ++ * sz might already be invalid at this point ++ */ ++ dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); ++ return; ++ default: ++ break; ++ } ++ ++ dev_info(sz->dev, "%s: received urb, len %d\n", __func__, len); ++ for (i = 0; i < len; i++) { ++ dev_info(sz->dev, "sz idx %d: %x\n", ++ i, (unsigned char)sz->buf_in[i]); ++ switch (sz->decoder_state) { ++ case PulseSpace: ++ if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) == ++ STREAMZAP_PULSE_MASK) { ++ sz->decoder_state = FullPulse; ++ continue; ++ } else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK) ++ == STREAMZAP_SPACE_MASK) { ++ sz_push_half_pulse(sz, sz->buf_in[i]); ++ sz->decoder_state = FullSpace; ++ continue; ++ } else { ++ sz_push_half_pulse(sz, sz->buf_in[i]); ++ sz_push_half_space(sz, sz->buf_in[i]); ++ } ++ break; ++ case FullPulse: ++ sz_push_full_pulse(sz, sz->buf_in[i]); ++ sz->decoder_state = IgnorePulse; ++ break; ++ case FullSpace: ++ if (sz->buf_in[i] == STREAMZAP_TIMEOUT) { ++ struct ir_raw_event rawir; ++ ++ rawir.pulse = false; ++ rawir.duration = timeout * 1000; ++ sz->idle = true; ++ if (sz->timeout_enabled) ++ sz_push(sz, rawir); ++ ir_raw_event_handle(sz->idev); ++ } else { ++ sz_push_full_space(sz, sz->buf_in[i]); ++ } ++ sz->decoder_state = PulseSpace; ++ break; ++ case IgnorePulse: ++ if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK) == ++ STREAMZAP_SPACE_MASK) { ++ sz->decoder_state = FullSpace; ++ continue; ++ } ++ sz_push_half_space(sz, sz->buf_in[i]); ++ sz->decoder_state = PulseSpace; ++ break; ++ } ++ } ++ ++ usb_submit_urb(urb, GFP_ATOMIC); ++ ++ return; ++} ++ ++static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz) ++{ ++ struct input_dev *idev; ++ struct ir_dev_props *props; ++ struct device *dev = sz->dev; ++ int ret; ++ ++ idev = input_allocate_device(); ++ if (!idev) { ++ dev_err(dev, "remote input dev allocation failed\n"); ++ goto idev_alloc_failed; ++ } ++ ++ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); ++ if (!props) { ++ dev_err(dev, "remote ir dev props allocation failed\n"); ++ goto props_alloc_failed; ++ } ++ ++ snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared " ++ "Receiver (%04x:%04x)", ++ le16_to_cpu(sz->usbdev->descriptor.idVendor), ++ le16_to_cpu(sz->usbdev->descriptor.idProduct)); ++ ++ idev->name = sz->name; ++ usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); ++ strlcat(sz->phys, "/input0", sizeof(sz->phys)); ++ idev->phys = sz->phys; ++ ++ props->priv = sz; ++ props->driver_type = RC_DRIVER_IR_RAW; ++ props->allowed_protos = IR_TYPE_ALL; ++ ++ sz->props = props; ++ ++ ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME); ++ if (ret < 0) { ++ dev_err(dev, "remote input device register failed\n"); ++ goto irdev_failed; ++ } ++ ++ return idev; ++ ++irdev_failed: ++ kfree(props); ++props_alloc_failed: ++ input_free_device(idev); ++idev_alloc_failed: ++ return NULL; ++} ++ ++/** ++ * streamzap_probe ++ * ++ * Called by usb-core to associated with a candidate device ++ * On any failure the return value is the ERROR ++ * On success return 0 ++ */ ++static int __devinit streamzap_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *usbdev = interface_to_usbdev(intf); ++ struct usb_host_interface *iface_host; ++ struct streamzap_ir *sz = NULL; ++ char buf[63], name[128] = ""; ++ int retval = -ENOMEM; ++ int pipe, maxp; ++ ++ /* Allocate space for device driver specific data */ ++ sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL); ++ if (!sz) ++ return -ENOMEM; ++ ++ sz->usbdev = usbdev; ++ sz->interface = intf; ++ ++ /* Check to ensure endpoint information matches requirements */ ++ iface_host = intf->cur_altsetting; ++ ++ if (iface_host->desc.bNumEndpoints != 1) { ++ dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n", ++ __func__, iface_host->desc.bNumEndpoints); ++ retval = -ENODEV; ++ goto free_sz; ++ } ++ ++ sz->endpoint = &(iface_host->endpoint[0].desc); ++ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ != USB_DIR_IN) { ++ dev_err(&intf->dev, "%s: endpoint doesn't match input device " ++ "02%02x\n", __func__, sz->endpoint->bEndpointAddress); ++ retval = -ENODEV; ++ goto free_sz; ++ } ++ ++ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ != USB_ENDPOINT_XFER_INT) { ++ dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " ++ "02%02x\n", __func__, sz->endpoint->bmAttributes); ++ retval = -ENODEV; ++ goto free_sz; ++ } ++ ++ pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress); ++ maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe)); ++ ++ if (maxp == 0) { ++ dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n", ++ __func__); ++ retval = -ENODEV; ++ goto free_sz; ++ } ++ ++ /* Allocate the USB buffer and IRQ URB */ ++ sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in); ++ if (!sz->buf_in) ++ goto free_sz; ++ ++ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); ++ if (!sz->urb_in) ++ goto free_buf_in; ++ ++ sz->dev = &intf->dev; ++ sz->buf_in_len = maxp; ++ ++ if (usbdev->descriptor.iManufacturer ++ && usb_string(usbdev, usbdev->descriptor.iManufacturer, ++ buf, sizeof(buf)) > 0) ++ strlcpy(name, buf, sizeof(name)); ++ ++ if (usbdev->descriptor.iProduct ++ && usb_string(usbdev, usbdev->descriptor.iProduct, ++ buf, sizeof(buf)) > 0) ++ snprintf(name + strlen(name), sizeof(name) - strlen(name), ++ " %s", buf); ++ ++ sz->idev = streamzap_init_input_dev(sz); ++ if (!sz->idev) ++ goto input_dev_fail; ++ ++ sz->idle = true; ++ sz->decoder_state = PulseSpace; ++ /* FIXME: don't yet have a way to set this */ ++ sz->timeout_enabled = true; ++ #if 0 ++ /* not yet supported, depends on patches from maxim */ ++ /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ ++ sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000; ++ sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000; ++ #endif ++ ++ do_gettimeofday(&sz->signal_start); ++ ++ /* Complete final initialisations */ ++ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in, ++ maxp, (usb_complete_t)streamzap_callback, ++ sz, sz->endpoint->bInterval); ++ sz->urb_in->transfer_dma = sz->dma_in; ++ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ usb_set_intfdata(intf, sz); ++ ++ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) ++ dev_err(sz->dev, "urb submit failed\n"); ++ ++ dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, ++ usbdev->bus->busnum, usbdev->devnum); ++ ++ /* Load the streamzap not-quite-rc5 decoder too */ ++ load_rc5_sz_decode(); ++ ++ return 0; ++ ++input_dev_fail: ++ usb_free_urb(sz->urb_in); ++free_buf_in: ++ usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in); ++free_sz: ++ kfree(sz); ++ ++ return retval; ++} ++ ++/** ++ * streamzap_disconnect ++ * ++ * Called by the usb core when the device is removed from the system. ++ * ++ * This routine guarantees that the driver will not submit any more urbs ++ * by clearing dev->usbdev. It is also supposed to terminate any currently ++ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), ++ * does not provide any way to do this. ++ */ ++static void streamzap_disconnect(struct usb_interface *interface) ++{ ++ struct streamzap_ir *sz = usb_get_intfdata(interface); ++ struct usb_device *usbdev = interface_to_usbdev(interface); ++ ++ usb_set_intfdata(interface, NULL); ++ ++ if (!sz) ++ return; ++ ++ sz->usbdev = NULL; ++ ir_input_unregister(sz->idev); ++ usb_kill_urb(sz->urb_in); ++ usb_free_urb(sz->urb_in); ++ usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ ++ kfree(sz); ++} ++ ++static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct streamzap_ir *sz = usb_get_intfdata(intf); ++ ++ usb_kill_urb(sz->urb_in); ++ ++ return 0; ++} ++ ++static int streamzap_resume(struct usb_interface *intf) ++{ ++ struct streamzap_ir *sz = usb_get_intfdata(intf); ++ ++ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { ++ dev_err(sz->dev, "Error sumbiting urb\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/** ++ * streamzap_init ++ */ ++static int __init streamzap_init(void) ++{ ++ int ret; ++ ++ /* register this driver with the USB subsystem */ ++ ret = usb_register(&streamzap_driver); ++ if (ret < 0) ++ printk(KERN_ERR DRIVER_NAME ": usb register failed, " ++ "result = %d\n", ret); ++ ++ return ret; ++} ++ ++/** ++ * streamzap_exit ++ */ ++static void __exit streamzap_exit(void) ++{ ++ usb_deregister(&streamzap_driver); ++} ++ ++ ++module_init(streamzap_init); ++module_exit(streamzap_exit); ++ ++MODULE_AUTHOR("Jarod Wilson "); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); ++ ++module_param(debug, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Enable debugging messages"); +diff -Naurp linux-2.6.35.x86_64.orig/include/media/rc-map.h linux-2.6.35.x86_64/include/media/rc-map.h +--- linux-2.6.35.x86_64.orig/include/media/rc-map.h 2010-08-15 17:50:34.584382568 -0400 ++++ linux-2.6.35.x86_64/include/media/rc-map.h 2010-08-16 00:18:02.455993732 -0400 +@@ -17,12 +17,13 @@ + #define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ + #define IR_TYPE_JVC (1 << 3) /* JVC protocol */ + #define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ ++#define IR_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */ + #define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ + #define IR_TYPE_OTHER (1u << 31) + + #define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \ + IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \ +- IR_TYPE_OTHER) ++ IR_TYPE_RC5_SZ | IR_TYPE_OTHER) + + struct ir_scancode { + u32 scancode; +@@ -115,6 +116,7 @@ void rc_map_init(void); + #define RC_MAP_RC5_TV "rc-rc5-tv" + #define RC_MAP_RC6_MCE "rc-rc6-mce" + #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" ++#define RC_MAP_STREAMZAP "rc-streamzap" + #define RC_MAP_TBS_NEC "rc-tbs-nec" + #define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs" + #define RC_MAP_TEVII_NEC "rc-tevii-nec" diff --git a/lirc-staging-2.6.36.patch b/lirc-staging-2.6.36.patch index 23c80bc0e..8f7aa1236 100644 --- a/lirc-staging-2.6.36.patch +++ b/lirc-staging-2.6.36.patch @@ -1,7 +1,7 @@ drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + - drivers/staging/lirc/Kconfig | 111 +++ - drivers/staging/lirc/Makefile | 19 + + drivers/staging/lirc/Kconfig | 106 +++ + drivers/staging/lirc/Makefile | 18 + drivers/staging/lirc/TODO | 8 + drivers/staging/lirc/TODO.lirc_i2c | 3 + drivers/staging/lirc/lirc_bt829.c | 383 +++++++++ @@ -18,10 +18,9 @@ drivers/staging/lirc/lirc_sasem.c | 933 +++++++++++++++++++++ drivers/staging/lirc/lirc_serial.c | 1313 +++++++++++++++++++++++++++++ drivers/staging/lirc/lirc_sir.c | 1282 ++++++++++++++++++++++++++++ - drivers/staging/lirc/lirc_streamzap.c | 821 ++++++++++++++++++ drivers/staging/lirc/lirc_ttusbir.c | 396 +++++++++ drivers/staging/lirc/lirc_zilog.c | 1387 +++++++++++++++++++++++++++++++ - 23 files changed, 12034 insertions(+), 0 deletions(-) + 22 files changed, 11206 insertions(+), 0 deletions(-) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 984a754..9296517 100644 @@ -52,7 +51,7 @@ new file mode 100644 index 0000000..ab30a09 --- /dev/null +++ b/drivers/staging/lirc/Kconfig -@@ -0,0 +1,111 @@ +@@ -0,0 +1,105 @@ +# +# LIRC driver(s) configuration +# @@ -145,12 +144,6 @@ index 0000000..ab30a09 + help + Driver for the SIR IrDA port + -+config LIRC_STREAMZAP -+ tristate "Streamzap PC Receiver" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for the Streamzap PC Receiver -+ +config LIRC_TTUSBIR + tristate "Technotrend USB IR Receiver" + depends on LIRC_STAGING && USB @@ -169,7 +162,7 @@ new file mode 100644 index 0000000..a019182 --- /dev/null +++ b/drivers/staging/lirc/Makefile -@@ -0,0 +1,19 @@ +@@ -0,0 +1,18 @@ +# Makefile for the lirc drivers. +# + @@ -186,7 +179,6 @@ index 0000000..a019182 +obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o +obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o +obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o +obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o +obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO @@ -9582,833 +9574,6 @@ index 0000000..eb08fa7 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c -new file mode 100644 -index 0000000..be09c10 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_streamzap.c -@@ -0,0 +1,821 @@ -+/* -+ * Streamzap Remote Control driver -+ * -+ * Copyright (c) 2005 Christoph Bartelmus -+ * -+ * This driver was based on the work of Greg Wickham and Adrian -+ * Dewhurst. It was substantially rewritten to support correct signal -+ * gaps and now maintains a delay buffer, which is used to present -+ * consistent timing behaviour to user space applications. Without the -+ * delay buffer an ugly hack would be required in lircd, which can -+ * cause sluggish signal decoding in certain situations. -+ * -+ * This driver is based on the USB skeleton driver packaged with the -+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define DRIVER_VERSION "1.28" -+#define DRIVER_NAME "lirc_streamzap" -+#define DRIVER_DESC "Streamzap Remote Control driver" -+ -+static int debug; -+ -+#define USB_STREAMZAP_VENDOR_ID 0x0e9c -+#define USB_STREAMZAP_PRODUCT_ID 0x0000 -+ -+/* Use our own dbg macro */ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ -+ fmt "\n", ## args); \ -+ } while (0) -+ -+/* table of devices that work with this driver */ -+static struct usb_device_id streamzap_table[] = { -+ /* Streamzap Remote Control */ -+ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(usb, streamzap_table); -+ -+#define STREAMZAP_PULSE_MASK 0xf0 -+#define STREAMZAP_SPACE_MASK 0x0f -+#define STREAMZAP_TIMEOUT 0xff -+#define STREAMZAP_RESOLUTION 256 -+ -+/* number of samples buffered */ -+#define STREAMZAP_BUF_LEN 128 -+ -+enum StreamzapDecoderState { -+ PulseSpace, -+ FullPulse, -+ FullSpace, -+ IgnorePulse -+}; -+ -+/* Structure to hold all of our device specific stuff -+ * -+ * some remarks regarding locking: -+ * theoretically this struct can be accessed from three threads: -+ * -+ * - from lirc_dev through set_use_inc/set_use_dec -+ * -+ * - from the USB layer throuh probe/disconnect/irq -+ * -+ * Careful placement of lirc_register_driver/lirc_unregister_driver -+ * calls will prevent conflicts. lirc_dev makes sure that -+ * set_use_inc/set_use_dec are not being executed and will not be -+ * called after lirc_unregister_driver returns. -+ * -+ * - by the timer callback -+ * -+ * The timer is only running when the device is connected and the -+ * LIRC device is open. Making sure the timer is deleted by -+ * set_use_dec will make conflicts impossible. -+ */ -+struct usb_streamzap { -+ -+ /* usb */ -+ /* save off the usb device pointer */ -+ struct usb_device *udev; -+ /* the interface for this device */ -+ struct usb_interface *interface; -+ -+ /* buffer & dma */ -+ unsigned char *buf_in; -+ dma_addr_t dma_in; -+ unsigned int buf_in_len; -+ -+ struct usb_endpoint_descriptor *endpoint; -+ -+ /* IRQ */ -+ struct urb *urb_in; -+ -+ /* lirc */ -+ struct lirc_driver *driver; -+ struct lirc_buffer *delay_buf; -+ -+ /* timer used to support delay buffering */ -+ struct timer_list delay_timer; -+ int timer_running; -+ spinlock_t timer_lock; -+ -+ /* tracks whether we are currently receiving some signal */ -+ int idle; -+ /* sum of signal lengths received since signal start */ -+ unsigned long sum; -+ /* start time of signal; necessary for gap tracking */ -+ struct timeval signal_last; -+ struct timeval signal_start; -+ enum StreamzapDecoderState decoder_state; -+ struct timer_list flush_timer; -+ int flush; -+ int in_use; -+ int timeout_enabled; -+}; -+ -+ -+/* local function prototypes */ -+static int streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void streamzap_disconnect(struct usb_interface *interface); -+static void usb_streamzap_irq(struct urb *urb); -+static int streamzap_use_inc(void *data); -+static void streamzap_use_dec(void *data); -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg); -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); -+static int streamzap_resume(struct usb_interface *intf); -+ -+/* usb specific object needed to register this driver with the usb subsystem */ -+ -+static struct usb_driver streamzap_driver = { -+ .name = DRIVER_NAME, -+ .probe = streamzap_probe, -+ .disconnect = streamzap_disconnect, -+ .suspend = streamzap_suspend, -+ .resume = streamzap_resume, -+ .id_table = streamzap_table, -+}; -+ -+static void stop_timer(struct usb_streamzap *sz) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (sz->timer_running) { -+ sz->timer_running = 0; -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ del_timer_sync(&sz->delay_timer); -+ } else { -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ } -+} -+ -+static void flush_timeout(unsigned long arg) -+{ -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ -+ /* finally start accepting data */ -+ sz->flush = 0; -+} -+static void delay_timeout(unsigned long arg) -+{ -+ unsigned long flags; -+ /* deliver data every 10 ms */ -+ static unsigned long timer_inc = -+ (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ)); -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ int data; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ -+ if (!lirc_buffer_empty(sz->delay_buf) && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data); -+ } -+ if (!lirc_buffer_empty(sz->delay_buf)) { -+ while (lirc_buffer_available(sz->delay_buf) < -+ STREAMZAP_BUF_LEN / 2 && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } -+ if (sz->timer_running) { -+ sz->delay_timer.expires = jiffies + timer_inc; -+ add_timer(&sz->delay_timer); -+ } -+ } else { -+ sz->timer_running = 0; -+ } -+ -+ if (!lirc_buffer_empty(sz->driver->rbuf)) -+ wake_up(&sz->driver->rbuf->wait_poll); -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void flush_delay_buffer(struct usb_streamzap *sz) -+{ -+ int data; -+ int empty = 1; -+ -+ while (!lirc_buffer_empty(sz->delay_buf)) { -+ empty = 0; -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ if (!empty) -+ wake_up(&sz->driver->rbuf->wait_poll); -+} -+ -+static void push(struct usb_streamzap *sz, unsigned char *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (lirc_buffer_full(sz->delay_buf)) { -+ int read_data; -+ -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &read_data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &read_data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ -+ lirc_buffer_write(sz->delay_buf, data); -+ -+ if (!sz->timer_running) { -+ sz->delay_timer.expires = jiffies + HZ/10; -+ add_timer(&sz->delay_timer); -+ sz->timer_running = 1; -+ } -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void push_full_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int pulse; -+ -+ if (sz->idle) { -+ long deltv; -+ int tmp; -+ -+ sz->signal_last = sz->signal_start; -+ do_gettimeofday(&sz->signal_start); -+ -+ deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; -+ if (deltv > 15) { -+ /* really long time */ -+ tmp = LIRC_SPACE(LIRC_VALUE_MASK); -+ } else { -+ tmp = (int) (deltv*1000000+ -+ sz->signal_start.tv_usec - -+ sz->signal_last.tv_usec); -+ tmp -= sz->sum; -+ tmp = LIRC_SPACE(tmp); -+ } -+ dprintk("ls %u", sz->driver->minor, tmp); -+ push(sz, (char *)&tmp); -+ -+ sz->idle = 0; -+ sz->sum = 0; -+ } -+ -+ pulse = ((int) value) * STREAMZAP_RESOLUTION; -+ pulse += STREAMZAP_RESOLUTION / 2; -+ sz->sum += pulse; -+ pulse = LIRC_PULSE(pulse); -+ -+ dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK); -+ push(sz, (char *)&pulse); -+} -+ -+static void push_half_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); -+} -+ -+static void push_full_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int space; -+ -+ space = ((int) value)*STREAMZAP_RESOLUTION; -+ space += STREAMZAP_RESOLUTION/2; -+ sz->sum += space; -+ space = LIRC_SPACE(space); -+ dprintk("s %u", sz->driver->minor, space); -+ push(sz, (char *)&space); -+} -+ -+static void push_half_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_space(sz, value & STREAMZAP_SPACE_MASK); -+} -+ -+/** -+ * usb_streamzap_irq - IRQ handler -+ * -+ * This procedure is invoked on reception of data from -+ * the usb remote. -+ */ -+static void usb_streamzap_irq(struct urb *urb) -+{ -+ struct usb_streamzap *sz; -+ int len; -+ unsigned int i = 0; -+ -+ if (!urb) -+ return; -+ -+ sz = urb->context; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ /* -+ * this urb is terminated, clean up. -+ * sz might already be invalid at this point -+ */ -+ dprintk("urb status: %d", -1, urb->status); -+ return; -+ default: -+ break; -+ } -+ -+ dprintk("received %d", sz->driver->minor, urb->actual_length); -+ if (!sz->flush) { -+ for (i = 0; i < urb->actual_length; i++) { -+ dprintk("%d: %x", sz->driver->minor, -+ i, (unsigned char) sz->buf_in[i]); -+ switch (sz->decoder_state) { -+ case PulseSpace: -+ if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) == -+ STREAMZAP_PULSE_MASK) { -+ sz->decoder_state = FullPulse; -+ continue; -+ } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) -+ == STREAMZAP_SPACE_MASK) { -+ push_half_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = FullSpace; -+ continue; -+ } else { -+ push_half_pulse(sz, sz->buf_in[i]); -+ push_half_space(sz, sz->buf_in[i]); -+ } -+ break; -+ case FullPulse: -+ push_full_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = IgnorePulse; -+ break; -+ case FullSpace: -+ if (sz->buf_in[i] == STREAMZAP_TIMEOUT) { -+ sz->idle = 1; -+ stop_timer(sz); -+ if (sz->timeout_enabled) { -+ int timeout = -+ LIRC_TIMEOUT -+ (STREAMZAP_TIMEOUT * -+ STREAMZAP_RESOLUTION); -+ push(sz, (char *)&timeout); -+ } -+ flush_delay_buffer(sz); -+ } else -+ push_full_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ case IgnorePulse: -+ if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) == -+ STREAMZAP_SPACE_MASK) { -+ sz->decoder_state = FullSpace; -+ continue; -+ } -+ push_half_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ } -+ } -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+static const struct file_operations streamzap_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = streamzap_ioctl, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+ -+/** -+ * streamzap_probe -+ * -+ * Called by usb-core to associated with a candidate device -+ * On any failure the return value is the ERROR -+ * On success return 0 -+ */ -+static int streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *udev = interface_to_usbdev(interface); -+ struct usb_host_interface *iface_host; -+ struct usb_streamzap *sz; -+ struct lirc_driver *driver; -+ struct lirc_buffer *lirc_buf; -+ struct lirc_buffer *delay_buf; -+ char buf[63], name[128] = ""; -+ int retval = -ENOMEM; -+ int minor = 0; -+ -+ /* Allocate space for device driver specific data */ -+ sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL); -+ if (sz == NULL) -+ return -ENOMEM; -+ -+ sz->udev = udev; -+ sz->interface = interface; -+ -+ /* Check to ensure endpoint information matches requirements */ -+ iface_host = interface->cur_altsetting; -+ -+ if (iface_host->desc.bNumEndpoints != 1) { -+ err("%s: Unexpected desc.bNumEndpoints (%d)", __func__, -+ iface_host->desc.bNumEndpoints); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ sz->endpoint = &(iface_host->endpoint[0].desc); -+ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ != USB_DIR_IN) { -+ err("%s: endpoint doesn't match input device 02%02x", -+ __func__, sz->endpoint->bEndpointAddress); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_INT) { -+ err("%s: endpoint attributes don't match xfer 02%02x", -+ __func__, sz->endpoint->bmAttributes); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if (sz->endpoint->wMaxPacketSize == 0) { -+ err("%s: endpoint message size==0? ", __func__); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ /* Allocate the USB buffer and IRQ URB */ -+ -+ sz->buf_in_len = sz->endpoint->wMaxPacketSize; -+ sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len, -+ GFP_ATOMIC, &sz->dma_in); -+ if (sz->buf_in == NULL) -+ goto free_sz; -+ -+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (sz->urb_in == NULL) -+ goto free_sz; -+ -+ /* Connect this device to the LIRC sub-system */ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto free_sz; -+ -+ lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!lirc_buf) -+ goto free_driver; -+ if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_lirc_buf; -+ -+ delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!delay_buf) -+ goto free_lirc_buf; -+ if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_delay_buf; -+ -+ sz->driver = driver; -+ strcpy(sz->driver->name, DRIVER_NAME); -+ sz->driver->minor = -1; -+ sz->driver->sample_rate = 0; -+ sz->driver->code_length = sizeof(int) * 8; -+ sz->driver->features = LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_GET_REC_RESOLUTION | -+ LIRC_CAN_SET_REC_TIMEOUT; -+ sz->driver->data = sz; -+ sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->rbuf = lirc_buf; -+ sz->delay_buf = delay_buf; -+ sz->driver->set_use_inc = &streamzap_use_inc; -+ sz->driver->set_use_dec = &streamzap_use_dec; -+ sz->driver->fops = &streamzap_fops; -+ sz->driver->dev = &interface->dev; -+ sz->driver->owner = THIS_MODULE; -+ -+ sz->idle = 1; -+ sz->decoder_state = PulseSpace; -+ init_timer(&sz->delay_timer); -+ sz->delay_timer.function = delay_timeout; -+ sz->delay_timer.data = (unsigned long) sz; -+ sz->timer_running = 0; -+ spin_lock_init(&sz->timer_lock); -+ -+ init_timer(&sz->flush_timer); -+ sz->flush_timer.function = flush_timeout; -+ sz->flush_timer.data = (unsigned long) sz; -+ /* Complete final initialisations */ -+ -+ usb_fill_int_urb(sz->urb_in, udev, -+ usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), -+ sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, -+ sz->endpoint->bInterval); -+ sz->urb_in->transfer_dma = sz->dma_in; -+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (udev->descriptor.iManufacturer -+ && usb_string(udev, udev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ -+ if (udev->descriptor.iProduct -+ && usb_string(udev, udev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ minor = lirc_register_driver(driver); -+ -+ if (minor < 0) -+ goto free_delay_buf; -+ -+ sz->driver->minor = minor; -+ -+ usb_set_intfdata(interface, sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", -+ sz->driver->minor, name, -+ udev->bus->busnum, sz->udev->devnum); -+ -+ return 0; -+ -+free_delay_buf: -+ lirc_buffer_free(sz->delay_buf); -+kfree_delay_buf: -+ kfree(delay_buf); -+free_lirc_buf: -+ lirc_buffer_free(sz->driver->rbuf); -+kfree_lirc_buf: -+ kfree(lirc_buf); -+free_driver: -+ kfree(driver); -+free_sz: -+ if (retval == -ENOMEM) -+ err("Out of memory"); -+ -+ if (sz) { -+ usb_free_urb(sz->urb_in); -+ usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ kfree(sz); -+ } -+ -+ return retval; -+} -+ -+static int streamzap_use_inc(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return -EINVAL; -+ } -+ dprintk("set use inc", sz->driver->minor); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ sz->in_use++; -+ -+ return 0; -+} -+ -+static void streamzap_use_dec(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return; -+ } -+ dprintk("set use dec", sz->driver->minor); -+ -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ usb_kill_urb(sz->urb_in); -+ -+ stop_timer(sz); -+ -+ sz->in_use--; -+} -+ -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result = 0; -+ int val; -+ struct usb_streamzap *sz = lirc_get_pdata(filep); -+ -+ switch (cmd) { -+ case LIRC_GET_REC_RESOLUTION: -+ result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg); -+ break; -+ case LIRC_SET_REC_TIMEOUT: -+ result = get_user(val, (int *)arg); -+ if (result == 0) { -+ if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) -+ sz->timeout_enabled = 1; -+ else if (val == 0) -+ sz->timeout_enabled = 0; -+ else -+ result = -EINVAL; -+ } -+ break; -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ return result; -+} -+ -+/** -+ * streamzap_disconnect -+ * -+ * Called by the usb core when the device is removed from the system. -+ * -+ * This routine guarantees that the driver will not submit any more urbs -+ * by clearing dev->udev. It is also supposed to terminate any currently -+ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), -+ * does not provide any way to do this. -+ */ -+static void streamzap_disconnect(struct usb_interface *interface) -+{ -+ struct usb_streamzap *sz; -+ int errnum; -+ int minor; -+ -+ sz = usb_get_intfdata(interface); -+ -+ /* unregister from the LIRC sub-system */ -+ -+ errnum = lirc_unregister_driver(sz->driver->minor); -+ if (errnum != 0) -+ dprintk("error in lirc_unregister: (returned %d)", -+ sz->driver->minor, errnum); -+ -+ lirc_buffer_free(sz->delay_buf); -+ lirc_buffer_free(sz->driver->rbuf); -+ -+ /* unregister from the USB sub-system */ -+ -+ usb_free_urb(sz->urb_in); -+ -+ usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ -+ minor = sz->driver->minor; -+ kfree(sz->driver->rbuf); -+ kfree(sz->driver); -+ kfree(sz->delay_buf); -+ kfree(sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); -+} -+ -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor); -+ if (sz->in_use) { -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ stop_timer(sz); -+ -+ usb_kill_urb(sz->urb_in); -+ } -+ return 0; -+} -+ -+static int streamzap_resume(struct usb_interface *intf) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ if (sz->in_use) { -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * usb_streamzap_init -+ */ -+static int __init usb_streamzap_init(void) -+{ -+ int result; -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&streamzap_driver); -+ -+ if (result) { -+ err("usb_register failed. Error number %d", -+ result); -+ return result; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); -+ return 0; -+} -+ -+/** -+ * usb_streamzap_exit -+ */ -+static void __exit usb_streamzap_exit(void) -+{ -+ usb_deregister(&streamzap_driver); -+} -+ -+ -+module_init(usb_streamzap_init); -+module_exit(usb_streamzap_exit); -+ -+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c new file mode 100644 index 0000000..e345ab9 From 4cfceabb6ccb551a2326c726da207dce5dfda489 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 17 Aug 2010 10:32:29 -0400 Subject: [PATCH 014/277] fix make local, see %changelog for description --- kernel.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel.spec b/kernel.spec index 20eefe23c..711c5fb6d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1326,6 +1326,8 @@ done rm -f kernel-%{version}-*debug.config %endif +touch .scmversion + # now run oldconfig over all the config files for i in *.config do @@ -1886,6 +1888,12 @@ fi # and build. %changelog +* Tue Aug 17 2010 Kyle McMartin +- Touch .scmversion in the kernel top level to prevent scripts/setlocalversion + from recursing into our fedpkg git tree and trying to decide whether the + kernel git is modified (obviously not, since it's a tarball.) Fixes make + local. + * Mon Aug 16 2010 Jarod Wilson 2.6.35.2-9 - Add ir-core streamzap driver, nuke lirc_streamzap From e2302e0109bf13673309c52ff4cb94f22b22b282 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 17 Aug 2010 10:58:11 -0400 Subject: [PATCH 015/277] create a /sys/fs/cgroup mountpoint for cgroupfs --- ...e-sys-fs-cgroup-to-mount-cgroupfs-on.patch | 56 +++++++++++++++++++ kernel.spec | 7 +++ 2 files changed, 63 insertions(+) create mode 100644 create-sys-fs-cgroup-to-mount-cgroupfs-on.patch diff --git a/create-sys-fs-cgroup-to-mount-cgroupfs-on.patch b/create-sys-fs-cgroup-to-mount-cgroupfs-on.patch new file mode 100644 index 000000000..e1788a316 --- /dev/null +++ b/create-sys-fs-cgroup-to-mount-cgroupfs-on.patch @@ -0,0 +1,56 @@ +From: Greg KH +Date: Thu, 5 Aug 2010 20:53:35 +0000 (-0700) +Subject: cgroupfs: create /sys/fs/cgroup to mount cgroupfs on +X-Git-Tag: v2.6.36-rc1~521^2~7 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=676db4af043014e852f67ba0349dae0071bd11f3 + +cgroupfs: create /sys/fs/cgroup to mount cgroupfs on + +We really shouldn't be asking userspace to create new root filesystems. +So follow along with all of the other in-kernel filesystems, and provide +a mount point in sysfs. + +For cgroupfs, this should be in /sys/fs/cgroup/ This change provides +that mount point when the cgroup filesystem is registered in the kernel. + +Acked-by: Paul Menage +Acked-by: Dhaval Giani +Cc: Li Zefan +Cc: Lennart Poettering +Cc: Kay Sievers +Signed-off-by: Greg Kroah-Hartman +--- + +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index a8ce099..d83cab0 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -1623,6 +1623,8 @@ static struct file_system_type cgroup_fs_type = { + .kill_sb = cgroup_kill_sb, + }; + ++static struct kobject *cgroup_kobj; ++ + static inline struct cgroup *__d_cgrp(struct dentry *dentry) + { + return dentry->d_fsdata; +@@ -3894,9 +3896,18 @@ int __init cgroup_init(void) + hhead = css_set_hash(init_css_set.subsys); + hlist_add_head(&init_css_set.hlist, hhead); + BUG_ON(!init_root_id(&rootnode)); ++ ++ cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); ++ if (!cgroup_kobj) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + err = register_filesystem(&cgroup_fs_type); +- if (err < 0) ++ if (err < 0) { ++ kobject_put(cgroup_kobj); + goto out; ++ } + + proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations); + diff --git a/kernel.spec b/kernel.spec index 711c5fb6d..b300e45d5 100644 --- a/kernel.spec +++ b/kernel.spec @@ -612,6 +612,8 @@ Patch202: linux-2.6-debug-taint-vm.patch Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch Patch204: linux-2.6-debug-always-inline-kzalloc.patch +Patch300: create-sys-fs-cgroup-to-mount-cgroupfs-on.patch + Patch380: linux-2.6-defaults-pci_no_msi.patch Patch383: linux-2.6-defaults-aspm.patch Patch384: pci-acpi-disable-aspm-if-no-osc.patch @@ -1237,6 +1239,7 @@ ApplyPatch linux-2.6-silence-fbcon-logo.patch #ApplyPatch linux-2.6-sparc-selinux-mprotect-checks.patch # Changes to upstream defaults. +ApplyPatch create-sys-fs-cgroup-to-mount-cgroupfs-on.patch # /dev/crash driver. @@ -1888,6 +1891,10 @@ fi # and build. %changelog +* Tue Aug 17 2010 Kyle McMartin +- Move cgroup fs to /sys/fs/cgroup instead of /cgroup in accordance with + upstream change post 2.6.35. + * Tue Aug 17 2010 Kyle McMartin - Touch .scmversion in the kernel top level to prevent scripts/setlocalversion from recursing into our fedpkg git tree and trying to decide whether the From bfc8e84a86ee21140cd3882d4ccd49266d1cb0bc Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 17 Aug 2010 18:26:23 -0400 Subject: [PATCH 016/277] Fix fallout from the stack guard page fixes. (mm-fix-page-table-unmap-for-stack-guard-page-properly.patch, mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch) --- kernel.spec | 14 ++- ...-unmap-for-stack-guard-page-properly.patch | 71 ++++++++++++++++ ...ible-effects-of-the-stack-guard-page.patch | 85 +++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 mm-fix-page-table-unmap-for-stack-guard-page-properly.patch create mode 100644 mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch diff --git a/kernel.spec b/kernel.spec index b300e45d5..cd59c0861 100644 --- a/kernel.spec +++ b/kernel.spec @@ -710,6 +710,9 @@ Patch12050: direct-io-move-aio_complete-into-end_io.patch Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch +Patch12070: mm-fix-page-table-unmap-for-stack-guard-page-properly.patch +Patch12071: mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1305,6 +1308,10 @@ ApplyPatch direct-io-move-aio_complete-into-end_io.patch ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch +# fix fallout from stack guard page patches +ApplyPatch mm-fix-page-table-unmap-for-stack-guard-page-properly.patch +ApplyPatch mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch + # END OF PATCH APPLICATIONS %endif @@ -1891,6 +1898,11 @@ fi # and build. %changelog +* Tue Aug 17 2010 Chuck Ebbert 2.6.35.2-9 +- Fix fallout from the stack guard page fixes. + (mm-fix-page-table-unmap-for-stack-guard-page-properly.patch, + mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch) + * Tue Aug 17 2010 Kyle McMartin - Move cgroup fs to /sys/fs/cgroup instead of /cgroup in accordance with upstream change post 2.6.35. @@ -1901,7 +1913,7 @@ fi kernel git is modified (obviously not, since it's a tarball.) Fixes make local. -* Mon Aug 16 2010 Jarod Wilson 2.6.35.2-9 +* Mon Aug 16 2010 Jarod Wilson - Add ir-core streamzap driver, nuke lirc_streamzap * Sun Aug 15 2010 Chuck Ebbert 2.6.35.2-8 diff --git a/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch b/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch new file mode 100644 index 000000000..0989fe3b7 --- /dev/null +++ b/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch @@ -0,0 +1,71 @@ +From: Linus Torvalds +Date: Sat, 14 Aug 2010 18:44:56 +0000 (-0700) +Subject: mm: fix page table unmap for stack guard page properly +X-Git-Tag: v2.6.36-rc1~20 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=11ac552477e32835cb6970bf0a70c210807f5673 + +mm: fix page table unmap for stack guard page properly + +We do in fact need to unmap the page table _before_ doing the whole +stack guard page logic, because if it is needed (mainly 32-bit x86 with +PAE and CONFIG_HIGHPTE, but other architectures may use it too) then it +will do a kmap_atomic/kunmap_atomic. + +And those kmaps will create an atomic region that we cannot do +allocations in. However, the whole stack expand code will need to do +anon_vma_prepare() and vma_lock_anon_vma() and they cannot do that in an +atomic region. + +Now, a better model might actually be to do the anon_vma_prepare() when +_creating_ a VM_GROWSDOWN segment, and not have to worry about any of +this at page fault time. But in the meantime, this is the +straightforward fix for the issue. + +See https://bugzilla.kernel.org/show_bug.cgi?id=16588 for details. + +Reported-by: Wylda +Reported-by: Sedat Dilek +Reported-by: Mike Pagano +Reported-by: François Valenduc +Tested-by: Ed Tomlinson +Cc: Pekka Enberg +Cc: Greg KH +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +--- + +diff --git a/mm/memory.c b/mm/memory.c +index 9b3b73f..b6e5fd2 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2792,24 +2792,23 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, + spinlock_t *ptl; + pte_t entry; + +- if (check_stack_guard_page(vma, address) < 0) { +- pte_unmap(page_table); ++ pte_unmap(page_table); ++ ++ /* Check if we need to add a guard page to the stack */ ++ if (check_stack_guard_page(vma, address) < 0) + return VM_FAULT_SIGBUS; +- } + ++ /* Use the zero-page for reads */ + if (!(flags & FAULT_FLAG_WRITE)) { + entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), + vma->vm_page_prot)); +- ptl = pte_lockptr(mm, pmd); +- spin_lock(ptl); ++ page_table = pte_offset_map_lock(mm, pmd, address, &ptl); + if (!pte_none(*page_table)) + goto unlock; + goto setpte; + } + + /* Allocate our own private page. */ +- pte_unmap(page_table); +- + if (unlikely(anon_vma_prepare(vma))) + goto oom; + page = alloc_zeroed_user_highpage_movable(vma, address); diff --git a/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch b/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch new file mode 100644 index 000000000..095a9336d --- /dev/null +++ b/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch @@ -0,0 +1,85 @@ +From: Linus Torvalds +Date: Sun, 15 Aug 2010 18:35:52 +0000 (-0700) +Subject: mm: fix up some user-visible effects of the stack guard page +X-Git-Tag: v2.6.36-rc1~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d7824370e26325c881b665350ce64fb0a4fde24a + +mm: fix up some user-visible effects of the stack guard page + +This commit makes the stack guard page somewhat less visible to user +space. It does this by: + + - not showing the guard page in /proc//maps + + It looks like lvm-tools will actually read /proc/self/maps to figure + out where all its mappings are, and effectively do a specialized + "mlockall()" in user space. By not showing the guard page as part of + the mapping (by just adding PAGE_SIZE to the start for grows-up + pages), lvm-tools ends up not being aware of it. + + - by also teaching the _real_ mlock() functionality not to try to lock + the guard page. + + That would just expand the mapping down to create a new guard page, + so there really is no point in trying to lock it in place. + +It would perhaps be nice to show the guard page specially in +/proc//maps (or at least mark grow-down segments some way), but +let's not open ourselves up to more breakage by user space from programs +that depends on the exact deails of the 'maps' file. + +Special thanks to Henrique de Moraes Holschuh for diving into lvm-tools +source code to see what was going on with the whole new warning. + +Reported-and-tested-by: François Valenduc +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +--- + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index aea1d3f..439fc1f 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -210,6 +210,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + int flags = vma->vm_flags; + unsigned long ino = 0; + unsigned long long pgoff = 0; ++ unsigned long start; + dev_t dev = 0; + int len; + +@@ -220,8 +221,13 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; + } + ++ /* We don't show the stack guard page in /proc/maps */ ++ start = vma->vm_start; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ start += PAGE_SIZE; ++ + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", +- vma->vm_start, ++ start, + vma->vm_end, + flags & VM_READ ? 'r' : '-', + flags & VM_WRITE ? 'w' : '-', +diff --git a/mm/mlock.c b/mm/mlock.c +index 3f82720..49e5e4c 100644 +--- a/mm/mlock.c ++++ b/mm/mlock.c +@@ -167,6 +167,14 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, + if (vma->vm_flags & VM_WRITE) + gup_flags |= FOLL_WRITE; + ++ /* We don't try to access the guard page of a stack vma */ ++ if (vma->vm_flags & VM_GROWSDOWN) { ++ if (start == vma->vm_start) { ++ start += PAGE_SIZE; ++ nr_pages--; ++ } ++ } ++ + while (nr_pages > 0) { + int i; + From 13dcde24269646e0f2dacd3f8484d3ae7d01214f Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 17 Aug 2010 18:27:57 -0400 Subject: [PATCH 017/277] fix duplicate patch numbers --- kernel.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel.spec b/kernel.spec index cd59c0861..83c15b246 100644 --- a/kernel.spec +++ b/kernel.spec @@ -710,8 +710,8 @@ Patch12050: direct-io-move-aio_complete-into-end_io.patch Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch -Patch12070: mm-fix-page-table-unmap-for-stack-guard-page-properly.patch -Patch12071: mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch +Patch12080: mm-fix-page-table-unmap-for-stack-guard-page-properly.patch +Patch12081: mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch %endif From 4135368fb0e29a3e6693d56c23f98b855f31d237 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 18 Aug 2010 19:41:03 -0400 Subject: [PATCH 018/277] systemd is dependant upon autofs, so build it in instead of modular. --- config-generic | 3 ++- kernel.spec | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config-generic b/config-generic index d61368e37..c7e865d38 100644 --- a/config-generic +++ b/config-generic @@ -3324,7 +3324,8 @@ CONFIG_QUOTACTL=y CONFIG_DNOTIFY=y # Autofsv3 is obsolete. # CONFIG_AUTOFS_FS is not set -CONFIG_AUTOFS4_FS=m +# systemd is dependant upon AUTOFS, so build it in. +CONFIG_AUTOFS4_FS=y CONFIG_EXOFS_FS=m # CONFIG_EXOFS_DEBUG is not set CONFIG_NILFS2_FS=m diff --git a/kernel.spec b/kernel.spec index 83c15b246..9836c989f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1898,6 +1898,9 @@ fi # and build. %changelog +* Wed Aug 18 2010 Dave Jones +- systemd is dependant upon autofs, so build it in instead of modular. + * Tue Aug 17 2010 Chuck Ebbert 2.6.35.2-9 - Fix fallout from the stack guard page fixes. (mm-fix-page-table-unmap-for-stack-guard-page-properly.patch, From 74e18cdf9ed5dfaf48db88d7e8b1e5bca84076de Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 21 Aug 2010 00:29:58 -0400 Subject: [PATCH 019/277] Linux 2.6.35.3 Drop merged patches: mm-fix-page-table-unmap-for-stack-guard-page-properly.patch mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch --- kernel.spec | 17 ++-- ...-unmap-for-stack-guard-page-properly.patch | 71 ---------------- ...ible-effects-of-the-stack-guard-page.patch | 85 ------------------- sources | 2 +- 4 files changed, 9 insertions(+), 166 deletions(-) delete mode 100644 mm-fix-page-table-unmap-for-stack-guard-page-properly.patch delete mode 100644 mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch diff --git a/kernel.spec b/kernel.spec index 9836c989f..d1a190d3c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 9 +%global baserelease 10 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,7 +60,7 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 2 +%define stable_update 3 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -710,9 +710,6 @@ Patch12050: direct-io-move-aio_complete-into-end_io.patch Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch -Patch12080: mm-fix-page-table-unmap-for-stack-guard-page-properly.patch -Patch12081: mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch - %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1308,10 +1305,6 @@ ApplyPatch direct-io-move-aio_complete-into-end_io.patch ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch -# fix fallout from stack guard page patches -ApplyPatch mm-fix-page-table-unmap-for-stack-guard-page-properly.patch -ApplyPatch mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch - # END OF PATCH APPLICATIONS %endif @@ -1898,6 +1891,12 @@ fi # and build. %changelog +* Sat Aug 21 2010 Chuck Ebbert 2.6.35.3-10 +- Linux 2.6.35.3 +- Drop merged patches: + mm-fix-page-table-unmap-for-stack-guard-page-properly.patch + mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch + * Wed Aug 18 2010 Dave Jones - systemd is dependant upon autofs, so build it in instead of modular. diff --git a/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch b/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch deleted file mode 100644 index 0989fe3b7..000000000 --- a/mm-fix-page-table-unmap-for-stack-guard-page-properly.patch +++ /dev/null @@ -1,71 +0,0 @@ -From: Linus Torvalds -Date: Sat, 14 Aug 2010 18:44:56 +0000 (-0700) -Subject: mm: fix page table unmap for stack guard page properly -X-Git-Tag: v2.6.36-rc1~20 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=11ac552477e32835cb6970bf0a70c210807f5673 - -mm: fix page table unmap for stack guard page properly - -We do in fact need to unmap the page table _before_ doing the whole -stack guard page logic, because if it is needed (mainly 32-bit x86 with -PAE and CONFIG_HIGHPTE, but other architectures may use it too) then it -will do a kmap_atomic/kunmap_atomic. - -And those kmaps will create an atomic region that we cannot do -allocations in. However, the whole stack expand code will need to do -anon_vma_prepare() and vma_lock_anon_vma() and they cannot do that in an -atomic region. - -Now, a better model might actually be to do the anon_vma_prepare() when -_creating_ a VM_GROWSDOWN segment, and not have to worry about any of -this at page fault time. But in the meantime, this is the -straightforward fix for the issue. - -See https://bugzilla.kernel.org/show_bug.cgi?id=16588 for details. - -Reported-by: Wylda -Reported-by: Sedat Dilek -Reported-by: Mike Pagano -Reported-by: François Valenduc -Tested-by: Ed Tomlinson -Cc: Pekka Enberg -Cc: Greg KH -Cc: stable@kernel.org -Signed-off-by: Linus Torvalds ---- - -diff --git a/mm/memory.c b/mm/memory.c -index 9b3b73f..b6e5fd2 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -2792,24 +2792,23 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, - spinlock_t *ptl; - pte_t entry; - -- if (check_stack_guard_page(vma, address) < 0) { -- pte_unmap(page_table); -+ pte_unmap(page_table); -+ -+ /* Check if we need to add a guard page to the stack */ -+ if (check_stack_guard_page(vma, address) < 0) - return VM_FAULT_SIGBUS; -- } - -+ /* Use the zero-page for reads */ - if (!(flags & FAULT_FLAG_WRITE)) { - entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), - vma->vm_page_prot)); -- ptl = pte_lockptr(mm, pmd); -- spin_lock(ptl); -+ page_table = pte_offset_map_lock(mm, pmd, address, &ptl); - if (!pte_none(*page_table)) - goto unlock; - goto setpte; - } - - /* Allocate our own private page. */ -- pte_unmap(page_table); -- - if (unlikely(anon_vma_prepare(vma))) - goto oom; - page = alloc_zeroed_user_highpage_movable(vma, address); diff --git a/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch b/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch deleted file mode 100644 index 095a9336d..000000000 --- a/mm-fix-up-some-user-visible-effects-of-the-stack-guard-page.patch +++ /dev/null @@ -1,85 +0,0 @@ -From: Linus Torvalds -Date: Sun, 15 Aug 2010 18:35:52 +0000 (-0700) -Subject: mm: fix up some user-visible effects of the stack guard page -X-Git-Tag: v2.6.36-rc1~5 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d7824370e26325c881b665350ce64fb0a4fde24a - -mm: fix up some user-visible effects of the stack guard page - -This commit makes the stack guard page somewhat less visible to user -space. It does this by: - - - not showing the guard page in /proc//maps - - It looks like lvm-tools will actually read /proc/self/maps to figure - out where all its mappings are, and effectively do a specialized - "mlockall()" in user space. By not showing the guard page as part of - the mapping (by just adding PAGE_SIZE to the start for grows-up - pages), lvm-tools ends up not being aware of it. - - - by also teaching the _real_ mlock() functionality not to try to lock - the guard page. - - That would just expand the mapping down to create a new guard page, - so there really is no point in trying to lock it in place. - -It would perhaps be nice to show the guard page specially in -/proc//maps (or at least mark grow-down segments some way), but -let's not open ourselves up to more breakage by user space from programs -that depends on the exact deails of the 'maps' file. - -Special thanks to Henrique de Moraes Holschuh for diving into lvm-tools -source code to see what was going on with the whole new warning. - -Reported-and-tested-by: François Valenduc -Cc: stable@kernel.org -Signed-off-by: Linus Torvalds ---- - -diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c -index aea1d3f..439fc1f 100644 ---- a/fs/proc/task_mmu.c -+++ b/fs/proc/task_mmu.c -@@ -210,6 +210,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) - int flags = vma->vm_flags; - unsigned long ino = 0; - unsigned long long pgoff = 0; -+ unsigned long start; - dev_t dev = 0; - int len; - -@@ -220,8 +221,13 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) - pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; - } - -+ /* We don't show the stack guard page in /proc/maps */ -+ start = vma->vm_start; -+ if (vma->vm_flags & VM_GROWSDOWN) -+ start += PAGE_SIZE; -+ - seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", -- vma->vm_start, -+ start, - vma->vm_end, - flags & VM_READ ? 'r' : '-', - flags & VM_WRITE ? 'w' : '-', -diff --git a/mm/mlock.c b/mm/mlock.c -index 3f82720..49e5e4c 100644 ---- a/mm/mlock.c -+++ b/mm/mlock.c -@@ -167,6 +167,14 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, - if (vma->vm_flags & VM_WRITE) - gup_flags |= FOLL_WRITE; - -+ /* We don't try to access the guard page of a stack vma */ -+ if (vma->vm_flags & VM_GROWSDOWN) { -+ if (start == vma->vm_start) { -+ start += PAGE_SIZE; -+ nr_pages--; -+ } -+ } -+ - while (nr_pages > 0) { - int i; - diff --git a/sources b/sources index 824148714..cd4a453f8 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -c0d9ece021feaf0b86c031ab59840ea8 patch-2.6.35.2.bz2 +a921f7789b7047b84f30a6f283cf6d07 patch-2.6.35.3.bz2 From 3e8e94e0cd83d003c42f10f61b34de72a278856c Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Wed, 25 Aug 2010 08:17:36 -0400 Subject: [PATCH 020/277] Linux 2.6.35.4-rc1 Fix up linux-2.6-i386-nx-emulation.patch for 2.6.35.4 --- kernel.spec | 10 +++++++--- linux-2.6-i386-nx-emulation.patch | 11 ++++++----- sources | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/kernel.spec b/kernel.spec index d1a190d3c..496cfd7c1 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 10 +%global baserelease 11 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,9 +60,9 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 3 +%define stable_update 4 # Is it a -stable RC? -%define stable_rc 0 +%define stable_rc 1 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1891,6 +1891,10 @@ fi # and build. %changelog +* Wed Aug 25 2010 Chuck Ebbert 2.6.35.4-11.rc1 +- Linux 2.6.35.4-rc1 +- Fix up linux-2.6-i386-nx-emulation.patch for 2.6.35.4 + * Sat Aug 21 2010 Chuck Ebbert 2.6.35.3-10 - Linux 2.6.35.3 - Drop merged patches: diff --git a/linux-2.6-i386-nx-emulation.patch b/linux-2.6-i386-nx-emulation.patch index a47e99d47..224fe0587 100644 --- a/linux-2.6-i386-nx-emulation.patch +++ b/linux-2.6-i386-nx-emulation.patch @@ -538,15 +538,16 @@ static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end); -@@ -388,6 +401,8 @@ - __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, - struct vm_area_struct *prev, struct rb_node *rb_parent) +@@ -388,6 +401,9 @@ { + struct vm_area_struct *next; + + if (vma->vm_flags & VM_EXEC) + arch_add_exec_range(mm, vma->vm_end); ++ + vma->vm_prev = prev; if (prev) { - vma->vm_next = prev->vm_next; - prev->vm_next = vma; + next = prev->vm_next; @@ -489,6 +504,8 @@ rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) diff --git a/sources b/sources index cd4a453f8..bd22fb7a1 100644 --- a/sources +++ b/sources @@ -1,2 +1,3 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 a921f7789b7047b84f30a6f283cf6d07 patch-2.6.35.3.bz2 +33afb339ec201d14792ba66e4c20985e patch-2.6.35.4-rc1.bz2 From b30c150da139a41d091d2bf85bbf4b933e1edd87 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 27 Aug 2010 01:59:01 -0400 Subject: [PATCH 021/277] Linux 2.6.35.4 --- kernel.spec | 7 +++++-- sources | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel.spec b/kernel.spec index 496cfd7c1..4dbe47ee5 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 11 +%global baserelease 12 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -62,7 +62,7 @@ Summary: The Linux kernel # Do we have a -stable update to apply? %define stable_update 4 # Is it a -stable RC? -%define stable_rc 1 +%define stable_rc 0 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1891,6 +1891,9 @@ fi # and build. %changelog +* Fri Aug 27 2010 Chuck Ebbert 2.6.35.4-12 +- Linux 2.6.35.4 + * Wed Aug 25 2010 Chuck Ebbert 2.6.35.4-11.rc1 - Linux 2.6.35.4-rc1 - Fix up linux-2.6-i386-nx-emulation.patch for 2.6.35.4 diff --git a/sources b/sources index bd22fb7a1..d1eb64f29 100644 --- a/sources +++ b/sources @@ -1,3 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -a921f7789b7047b84f30a6f283cf6d07 patch-2.6.35.3.bz2 -33afb339ec201d14792ba66e4c20985e patch-2.6.35.4-rc1.bz2 +738f762746488345b1a8707d00895eef patch-2.6.35.4.bz2 From 8f132e348cea0c67a7e10eb2425ca849006cf869 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 27 Aug 2010 02:07:13 -0400 Subject: [PATCH 022/277] kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch (#610941) --- kernel.spec | 6 ++ ...x-kprobes-to-skip-prefixes-correctly.patch | 98 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch diff --git a/kernel.spec b/kernel.spec index 4dbe47ee5..768af16bf 100644 --- a/kernel.spec +++ b/kernel.spec @@ -710,6 +710,8 @@ Patch12050: direct-io-move-aio_complete-into-end_io.patch Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch +Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1305,6 +1307,9 @@ ApplyPatch direct-io-move-aio_complete-into-end_io.patch ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch +# bz 610941 +ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch + # END OF PATCH APPLICATIONS %endif @@ -1893,6 +1898,7 @@ fi %changelog * Fri Aug 27 2010 Chuck Ebbert 2.6.35.4-12 - Linux 2.6.35.4 +- kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch (#610941) * Wed Aug 25 2010 Chuck Ebbert 2.6.35.4-11.rc1 - Linux 2.6.35.4-rc1 diff --git a/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch b/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch new file mode 100644 index 000000000..ae70d4126 --- /dev/null +++ b/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch @@ -0,0 +1,98 @@ +From: Masami Hiramatsu +Date: Tue, 29 Jun 2010 05:53:50 +0000 (+0900) +Subject: kprobes/x86: Fix kprobes to skip prefixes correctly +X-Git-Tag: v2.6.36-rc1~41^2~53 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=567a9fd86735ccdc897768ed2dacdd5e83a13509 + +kprobes/x86: Fix kprobes to skip prefixes correctly + +Fix resume_execution() and is_IF_modifier() to skip x86 +instruction prefixes correctly by using x86 instruction +attribute. + +Without this fix, resume_execution() can't handle instructions +which have non-REX prefixes (REX prefixes are skipped). This +will cause unexpected kernel panic by hitting bad address when a +kprobe hits on two-byte ret (e.g. "repz ret" generated for +Athlon/K8 optimization), because it just checks "repz" and can't +recognize the "ret" instruction. + +These prefixes can be found easily with x86 instruction +attribute. This patch introduces skip_prefixes() and uses it in +resume_execution() and is_IF_modifier() to skip prefixes. + +Signed-off-by: Masami Hiramatsu +Cc: Ananth N Mavinakayanahalli +LKML-Reference: <4C298A6E.8070609@hitachi.com> +Signed-off-by: Ingo Molnar +--- + +diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c +index 345a4b1..175f85c 100644 +--- a/arch/x86/kernel/kprobes.c ++++ b/arch/x86/kernel/kprobes.c +@@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to) + } + + /* +- * Check for the REX prefix which can only exist on X86_64 +- * X86_32 always returns 0 ++ * Skip the prefixes of the instruction. + */ +-static int __kprobes is_REX_prefix(kprobe_opcode_t *insn) ++static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn) + { ++ insn_attr_t attr; ++ ++ attr = inat_get_opcode_attribute((insn_byte_t)*insn); ++ while (inat_is_legacy_prefix(attr)) { ++ insn++; ++ attr = inat_get_opcode_attribute((insn_byte_t)*insn); ++ } + #ifdef CONFIG_X86_64 +- if ((*insn & 0xf0) == 0x40) +- return 1; ++ if (inat_is_rex_prefix(attr)) ++ insn++; + #endif +- return 0; ++ return insn; + } + + /* +@@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr) + */ + static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) + { ++ /* Skip prefixes */ ++ insn = skip_prefixes(insn); ++ + switch (*insn) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ +@@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) + return 1; + } + +- /* +- * on X86_64, 0x40-0x4f are REX prefixes so we need to look +- * at the next byte instead.. but of course not recurse infinitely +- */ +- if (is_REX_prefix(insn)) +- return is_IF_modifier(++insn); +- + return 0; + } + +@@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p, + unsigned long orig_ip = (unsigned long)p->addr; + kprobe_opcode_t *insn = p->ainsn.insn; + +- /*skip the REX prefix*/ +- if (is_REX_prefix(insn)) +- insn++; ++ /* Skip prefixes */ ++ insn = skip_prefixes(insn); + + regs->flags &= ~X86_EFLAGS_TF; + switch (*insn) { From 27e8302707fdb4c6888522bf5418647bf668ae40 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 27 Aug 2010 02:11:04 -0400 Subject: [PATCH 023/277] Drop obsolete ssb patch --- kernel.spec | 7 -- ssb_check_for_sprom.patch | 155 -------------------------------------- 2 files changed, 162 deletions(-) delete mode 100644 ssb_check_for_sprom.patch diff --git a/kernel.spec b/kernel.spec index 768af16bf..8d311561b 100644 --- a/kernel.spec +++ b/kernel.spec @@ -691,8 +691,6 @@ Patch2917: hdpvr-ir-enable.patch # NFSv4 -# VIA Nano / VX8xx updates - # patches headed upstream Patch12016: disable-i8042-check-on-apple-mac.patch @@ -701,8 +699,6 @@ Patch12017: prevent-runtime-conntrack-changes.patch Patch12018: neuter_intel_microcode_load.patch -Patch12030: ssb_check_for_sprom.patch - Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch # rhbz #617699 @@ -1297,9 +1293,6 @@ ApplyPatch disable-i8042-check-on-apple-mac.patch ApplyPatch neuter_intel_microcode_load.patch -# rhbz#533746 -#ApplyPatch ssb_check_for_sprom.patch - ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch # rhbz #617699 diff --git a/ssb_check_for_sprom.patch b/ssb_check_for_sprom.patch deleted file mode 100644 index 9415e1337..000000000 --- a/ssb_check_for_sprom.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 4d9d1ff88f920e9fcdde155c0a1366b7e0462d14 Mon Sep 17 00:00:00 2001 -From: John W. Linville -Date: Fri, 19 Mar 2010 14:58:01 -0400 -Subject: [PATCH v4] ssb: do not read SPROM if it does not exist - -Attempting to read registers that don't exist on the SSB bus can cause -hangs on some boxes. At least some b43 devices are 'in the wild' that -don't have SPROMs at all. When the SSB bus support loads, it attempts -to read these (non-existant) SPROMs and causes hard hangs on the box -- -no console output, etc. - -This patch adds some intelligence to determine whether or not the SPROM -is present before attempting to read it. This avoids those hard hangs -on those devices with no SPROM attached to their SSB bus. The -SSB-attached devices (e.g. b43, et al.) won't work, but at least the box -will survive to test further patches. :-) - -Signed-off-by: John W. Linville -Cc: Larry Finger -Cc: Michael Buesch -Cc: stable@kernel.org ---- - drivers/ssb/driver_chipcommon.c | 3 +++ - drivers/ssb/pci.c | 3 +++ - drivers/ssb/sprom.c | 26 ++++++++++++++++++++++++++ - include/linux/ssb/ssb.h | 3 +++ - include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++ - 5 files changed, 50 insertions(+), 0 deletions(-) - -diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c -index 9681536..6cf288d 100644 ---- a/drivers/ssb/driver_chipcommon.c -+++ b/drivers/ssb/driver_chipcommon.c -@@ -233,6 +233,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) - { - if (!cc->dev) - return; /* We don't have a ChipCommon */ -+ if (cc->dev->id.revision >= 11) { -+ cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); -+ } - ssb_pmu_init(cc); - chipco_powercontrol_init(cc); - ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); -diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c -index a8dbb06..89d7ab1 100644 ---- a/drivers/ssb/pci.c -+++ b/drivers/ssb/pci.c -@@ -621,6 +621,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, - int err = -ENOMEM; - u16 *buf; - -+ if (!ssb_is_sprom_available(bus)) -+ return -ENODEV; -+ - buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); - if (!buf) - goto out; -diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c -index f2f920f..c690f58 100644 ---- a/drivers/ssb/sprom.c -+++ b/drivers/ssb/sprom.c -@@ -176,3 +176,29 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void) - { - return fallback_sprom; - } -+ -+bool ssb_is_sprom_available(struct ssb_bus *bus) -+{ -+ /* some older devices don't have chipcommon, but they have sprom */ -+ if (!bus->chipco.dev) -+ return true; -+ -+ /* status register only exists on chipcomon rev >= 11 */ -+ if (bus->chipco.dev->id.revision < 11) -+ return true; -+ -+ switch (bus->chip_id) { -+ case 0x4312: -+ return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status); -+ case 0x4322: -+ return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status); -+ case 0x4325: -+ return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status); -+ default: -+ break; -+ } -+ if (bus->chipco.dev->id.revision >= 31) -+ return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; -+ -+ return true; -+} -diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h -index 24f9885..3b4da23 100644 ---- a/include/linux/ssb/ssb.h -+++ b/include/linux/ssb/ssb.h -@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus, - - extern void ssb_bus_unregister(struct ssb_bus *bus); - -+/* Does the device have an SPROM? */ -+extern bool ssb_is_sprom_available(struct ssb_bus *bus); -+ - /* Set a fallback SPROM. - * See kdoc at the function definition for complete documentation. */ - extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); -diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h -index 4e27acf..2cdf249 100644 ---- a/include/linux/ssb/ssb_driver_chipcommon.h -+++ b/include/linux/ssb/ssb_driver_chipcommon.h -@@ -53,6 +53,7 @@ - #define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ - #define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ - #define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ -+#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */ - #define SSB_CHIPCO_CORECTL 0x0008 - #define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ - #define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ -@@ -385,6 +386,7 @@ - - - /** Chip specific Chip-Status register contents. */ -+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */ - #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003 - #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ - #define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ -@@ -398,6 +400,18 @@ - #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4 - #define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */ - -+/** Macros to determine SPROM presence based on Chip-Status register. */ -+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \ -+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ -+ SSB_CHIPCO_CHST_4325_OTP_SEL) -+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \ -+ (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS) -+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \ -+ (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ -+ SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \ -+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ -+ SSB_CHIPCO_CHST_4325_OTP_SEL)) -+ - - - /** Clockcontrol masks and values **/ -@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu { - struct ssb_chipcommon { - struct ssb_device *dev; - u32 capabilities; -+ u32 status; - /* Fast Powerup Delay constant */ - u16 fast_pwrup_delay; - struct ssb_chipcommon_pmu pmu; --- -1.7.0.1 - From 10931f111228f5de94ef2fcc616d6c449ece269a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 Aug 2010 11:44:00 -0400 Subject: [PATCH 024/277] Fix incorrect DMA size freeing error in via-velocity. --- kernel.spec | 8 +++++++- linux-2.6-via-velocity-dma-fix.patch | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 linux-2.6-via-velocity-dma-fix.patch diff --git a/kernel.spec b/kernel.spec index 8d311561b..ec84c0074 100644 --- a/kernel.spec +++ b/kernel.spec @@ -687,7 +687,7 @@ Patch2915: lirc-staging-2.6.36.patch #Patch2916: lirc-staging-2.6.36-fixes.patch Patch2917: hdpvr-ir-enable.patch -# fs fixes +Patch3000: linux-2.6-via-velocity-dma-fix.patch # NFSv4 @@ -1288,6 +1288,9 @@ ApplyPatch lirc-staging-2.6.36.patch # enable IR receiver on Hauppauge HD PVR (v4l-dvb merge pending) ApplyPatch hdpvr-ir-enable.patch +# Fix DMA bug on via-velocity +ApplyPatch linux-2.6-via-velocity-dma-fix.patch + # Patches headed upstream ApplyPatch disable-i8042-check-on-apple-mac.patch @@ -1889,6 +1892,9 @@ fi # and build. %changelog +* Tue Aug 31 2010 Dave Jones +- Fix incorrect DMA size freeing error in via-velocity. + * Fri Aug 27 2010 Chuck Ebbert 2.6.35.4-12 - Linux 2.6.35.4 - kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch (#610941) diff --git a/linux-2.6-via-velocity-dma-fix.patch b/linux-2.6-via-velocity-dma-fix.patch new file mode 100644 index 000000000..9e945d5e1 --- /dev/null +++ b/linux-2.6-via-velocity-dma-fix.patch @@ -0,0 +1,20 @@ +From: Simon Kagstrom +Date: Tue, 31 Aug 2010 08:41:26 +0200 +Subject: [PATCH] via-velocity: Correct packet length on tx free + +Signed-off-by: Simon Kagstrom +--- + drivers/net/via-velocity.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +--- linux-2.6.35.x86_64/drivers/net/via-velocity.c~ 2010-08-31 11:40:51.000000000 -0400 ++++ linux-2.6.35.x86_64/drivers/net/via-velocity.c 2010-08-31 11:40:58.000000000 -0400 +@@ -1721,7 +1721,7 @@ static void velocity_free_tx_buf(struct + /* For scatter-gather */ + if (skb_shinfo(skb)->nr_frags > 0) + pktlen = max_t(size_t, pktlen, +- td->td_buf[i].size & ~TD_QUEUE); ++ skb_headlen(skb)); + + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], + le16_to_cpu(pktlen), PCI_DMA_TODEVICE); From 90303f94623893e072ce18abd293c27953a7195e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 Aug 2010 11:45:25 -0400 Subject: [PATCH 025/277] bump release --- kernel.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel.spec b/kernel.spec index ec84c0074..d5c36388f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 12 +%global baserelease 13 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1892,7 +1892,7 @@ fi # and build. %changelog -* Tue Aug 31 2010 Dave Jones +* Tue Aug 31 2010 Dave Jones 2.6.35.4-13 - Fix incorrect DMA size freeing error in via-velocity. * Fri Aug 27 2010 Chuck Ebbert 2.6.35.4-12 From 3c5d4de07ca16d799f1ca63454b56a03456191fe Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 31 Aug 2010 17:23:33 -0400 Subject: [PATCH 026/277] add in patch from lmacken to support more mac models with efifb --- efifb-add-more-models.patch | 59 +++++++++++++++++++++++++++++++++++++ kernel.spec | 10 ++++++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 efifb-add-more-models.patch diff --git a/efifb-add-more-models.patch b/efifb-add-more-models.patch new file mode 100644 index 000000000..3351970d7 --- /dev/null +++ b/efifb-add-more-models.patch @@ -0,0 +1,59 @@ +--- vanilla-2.6.35.3.orig/drivers/video/efifb.c ++++ vanilla-2.6.35.3/drivers/video/efifb.c +@@ -39,7 +39,11 @@ enum { + M_I20, /* 20-Inch iMac */ + M_I20_SR, /* 20-Inch iMac (Santa Rosa) */ + M_I24, /* 24-Inch iMac */ ++ M_I24_8_1, /* 24-Inch iMac, 8,1th gen */ ++ M_I24_10_1, /* 24-Inch iMac, 10,1th gen */ + M_MINI, /* Mac Mini */ ++ M_MINI_3_1, /* Mac Mini, 3,1th gen */ ++ M_MINI_4_1, /* Mac Mini, 4,1th gen */ + M_MB, /* MacBook */ + M_MB_2, /* MacBook, 2nd rev. */ + M_MB_3, /* MacBook, 3rd rev. */ +@@ -47,6 +51,7 @@ enum { + M_MBA, /* MacBook Air */ + M_MBP, /* MacBook Pro */ + M_MBP_2, /* MacBook Pro 2nd gen */ ++ M_MBP_2_2, /* MacBook Pro 2,2nd gen */ + M_MBP_SR, /* MacBook Pro (Santa Rosa) */ + M_MBP_4, /* MacBook Pro, 4th gen */ + M_MBP_5_1, /* MacBook Pro, 5,1th gen */ +@@ -64,11 +69,16 @@ static struct efifb_dmi_info { + [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ + [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, + [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ ++ [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 }, ++ [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 }, + [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, ++ [M_MINI_3_1]= { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, ++ [M_MINI_4_1]= { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, + [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, + [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, + [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, + [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ ++ [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 }, + [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, + [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, + [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, +@@ -92,7 +102,11 @@ static struct dmi_system_id __initdata d + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB), + /* At least one of these two will be right; maybe both? */ + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB), +@@ -104,6 +118,7 @@ static struct dmi_system_id __initdata d + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), ++ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), diff --git a/kernel.spec b/kernel.spec index d5c36388f..77630ecb2 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 13 +%global baserelease 14 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -663,6 +663,8 @@ Patch1824: drm-intel-next.patch Patch1825: drm-intel-make-lvds-work.patch Patch1900: linux-2.6-intel-iommu-igfx.patch +Patch2000: efifb-add-more-models.patch + # linux1394 git patches Patch2200: linux-2.6-firewire-git-update.patch Patch2201: linux-2.6-firewire-git-pending.patch @@ -1262,6 +1264,8 @@ ApplyOptionalPatch drm-intel-next.patch ApplyPatch drm-intel-make-lvds-work.patch ApplyPatch linux-2.6-intel-iommu-igfx.patch +ApplyPatch efifb-add-more-models.patch + # linux1394 git patches #ApplyPatch linux-2.6-firewire-git-update.patch #ApplyOptionalPatch linux-2.6-firewire-git-pending.patch @@ -1892,6 +1896,10 @@ fi # and build. %changelog +* Tue Aug 31 2010 Kyle McMartin 2.6.35.4-14 +- efifb-add-more-models.patch: Add patch from Luke Macken to + support more Mac models (rhbz#528232) + * Tue Aug 31 2010 Dave Jones 2.6.35.4-13 - Fix incorrect DMA size freeing error in via-velocity. From 0c8a5559c3af3c1b47961a5da748c47084cbdb14 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Wed, 1 Sep 2010 07:58:56 -0400 Subject: [PATCH 027/277] Don't build UIO platform drivers: they require additional platform code. --- config-generic | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config-generic b/config-generic index c7e865d38..2b97a950b 100644 --- a/config-generic +++ b/config-generic @@ -3992,8 +3992,8 @@ CONFIG_AUXDISPLAY=y CONFIG_UIO=m CONFIG_UIO_CIF=m CONFIG_UIO_SMX=m -CONFIG_UIO_PDRV=m -CONFIG_UIO_PDRV_GENIRQ=m +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set CONFIG_UIO_AEC=m CONFIG_UIO_SERCOS3=m CONFIG_UIO_PCI_GENERIC=m From c348adbe3998b31c8bc9a0288ef184f799be5bc4 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 1 Sep 2010 16:45:48 -0400 Subject: [PATCH 028/277] Improved version of the VIA Velocity DMA unmapping fix. --- kernel.spec | 5 +- linux-2.6-via-velocity-dma-fix.patch | 135 +++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/kernel.spec b/kernel.spec index 77630ecb2..d1a81f1ae 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 14 +%global baserelease 15 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1896,6 +1896,9 @@ fi # and build. %changelog +* Wed Sep 01 2010 Dave Jones 2.6.35.4-15 +- Improved version of the VIA Velocity DMA fix. + * Tue Aug 31 2010 Kyle McMartin 2.6.35.4-14 - efifb-add-more-models.patch: Add patch from Luke Macken to support more Mac models (rhbz#528232) diff --git a/linux-2.6-via-velocity-dma-fix.patch b/linux-2.6-via-velocity-dma-fix.patch index 9e945d5e1..37084847a 100644 --- a/linux-2.6-via-velocity-dma-fix.patch +++ b/linux-2.6-via-velocity-dma-fix.patch @@ -1,20 +1,121 @@ -From: Simon Kagstrom -Date: Tue, 31 Aug 2010 08:41:26 +0200 -Subject: [PATCH] via-velocity: Correct packet length on tx free +Date: Wed, 01 Sep 2010 13:37:33 -0700 (PDT) +Message-Id: <20100901.133733.223467599.davem@davemloft.net> +To: davej@redhat.com +Cc: simon.kagstrom@netinsight.net, netdev@vger.kernel.org +Subject: Re: via-velocity dma-debug warnings again. (2.6.35.2) +From: David Miller +In-Reply-To: <20100901.133547.236248297.davem@davemloft.net> +References: <20100901200555.GA30689@redhat.com> + <20100901.133414.24593005.davem@davemloft.net> + <20100901.133547.236248297.davem@davemloft.net> -Signed-off-by: Simon Kagstrom ---- - drivers/net/via-velocity.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) +New patch: ---- linux-2.6.35.x86_64/drivers/net/via-velocity.c~ 2010-08-31 11:40:51.000000000 -0400 -+++ linux-2.6.35.x86_64/drivers/net/via-velocity.c 2010-08-31 11:40:58.000000000 -0400 -@@ -1721,7 +1721,7 @@ static void velocity_free_tx_buf(struct - /* For scatter-gather */ - if (skb_shinfo(skb)->nr_frags > 0) - pktlen = max_t(size_t, pktlen, -- td->td_buf[i].size & ~TD_QUEUE); -+ skb_headlen(skb)); +via-velocity: Fix TX buffer unmapping. + +Fix several bugs in TX buffer DMA unmapping: + +1) Use pci_unmap_page() as appropriate. + +2) Don't try to fetch the length from the DMA descriptor, + the chip and modify that value. Use the correct lengths, + calculated the same way as is done at map time. + +3) Kill meaningless NULL checks (against embedded sized + arrays which can never be NULL, and against the address + of the non-zero indexed entry of an array). + +4) max() on ETH_ZLEN is not necessary and just adds + confusion, since the xmit function does a proper + skb_padto() very early on. + +Reported-by: Dave Jones +Signed-off-by: David S. Miller + +diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c +index fd69095..4167e1f 100644 +--- a/drivers/net/via-velocity.c ++++ b/drivers/net/via-velocity.c +@@ -1705,28 +1705,21 @@ err_free_dma_rings_0: + * recycle it, if not then unmap the buffer. + */ + static void velocity_free_tx_buf(struct velocity_info *vptr, +- struct velocity_td_info *tdinfo, struct tx_desc *td) ++ struct velocity_td_info *tdinfo) + { + struct sk_buff *skb = tdinfo->skb; ++ int i; - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], - le16_to_cpu(pktlen), PCI_DMA_TODEVICE); +- /* +- * Don't unmap the pre-allocated tx_bufs +- */ +- if (tdinfo->skb_dma) { +- int i; +- +- for (i = 0; i < tdinfo->nskb_dma; i++) { +- size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN); ++ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[0], ++ skb_headlen(skb), PCI_DMA_TODEVICE); + +- /* For scatter-gather */ +- if (skb_shinfo(skb)->nr_frags > 0) +- pktlen = max_t(size_t, pktlen, +- td->td_buf[i].size & ~TD_QUEUE); ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + +- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], +- le16_to_cpu(pktlen), PCI_DMA_TODEVICE); +- } ++ pci_unmap_page(vptr->pdev, tdinfo->skb_dma[i + 1], ++ frag->size, PCI_DMA_TODEVICE); + } ++ + dev_kfree_skb_irq(skb); + tdinfo->skb = NULL; + } +@@ -1739,22 +1732,8 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, + int q, int n) + { + struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); +- int i; +- +- if (td_info == NULL) +- return; + +- if (td_info->skb) { +- for (i = 0; i < td_info->nskb_dma; i++) { +- if (td_info->skb_dma[i]) { +- pci_unmap_single(vptr->pdev, td_info->skb_dma[i], +- td_info->skb->len, PCI_DMA_TODEVICE); +- td_info->skb_dma[i] = 0; +- } +- } +- dev_kfree_skb(td_info->skb); +- td_info->skb = NULL; +- } ++ velocity_free_tx_buf(vptr, td_info); + } + + /** +@@ -1925,7 +1904,7 @@ static int velocity_tx_srv(struct velocity_info *vptr) + stats->tx_packets++; + stats->tx_bytes += tdinfo->skb->len; + } +- velocity_free_tx_buf(vptr, tdinfo, td); ++ velocity_free_tx_buf(vptr, tdinfo); + vptr->tx.used[qnum]--; + } + vptr->tx.tail[qnum] = idx; +@@ -2534,9 +2513,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + +- pktlen = skb_shinfo(skb)->nr_frags == 0 ? +- max_t(unsigned int, skb->len, ETH_ZLEN) : +- skb_headlen(skb); ++ pktlen = skb_headlen(skb); + + spin_lock_irqsave(&vptr->lock, flags); + + From 705539efb54181dbec9105a98fdc8595b0286ddc Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 1 Sep 2010 21:45:56 -0400 Subject: [PATCH 029/277] One more velocity fix. --- kernel.spec | 5 ++++- linux-2.6-via-velocity-dma-fix.patch | 14 ++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/kernel.spec b/kernel.spec index d1a81f1ae..26a664deb 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 15 +%global baserelease 16 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1896,6 +1896,9 @@ fi # and build. %changelog +* Wed Sep 01 2010 Dave Jones 2.6.35.4-16 +- Another VIA Velocity fix. This time in ifdown path. + * Wed Sep 01 2010 Dave Jones 2.6.35.4-15 - Improved version of the VIA Velocity DMA fix. diff --git a/linux-2.6-via-velocity-dma-fix.patch b/linux-2.6-via-velocity-dma-fix.patch index 37084847a..d11064661 100644 --- a/linux-2.6-via-velocity-dma-fix.patch +++ b/linux-2.6-via-velocity-dma-fix.patch @@ -33,10 +33,10 @@ Reported-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c -index fd69095..4167e1f 100644 +index fd69095..258c368 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c -@@ -1705,28 +1705,21 @@ err_free_dma_rings_0: +@@ -1705,28 +1705,24 @@ err_free_dma_rings_0: * recycle it, if not then unmap the buffer. */ static void velocity_free_tx_buf(struct velocity_info *vptr, @@ -51,7 +51,9 @@ index fd69095..4167e1f 100644 - */ - if (tdinfo->skb_dma) { - int i; -- ++ if (unlikely(!tdinfo->skb)) ++ return; + - for (i = 0; i < tdinfo->nskb_dma; i++) { - size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN); + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[0], @@ -74,7 +76,7 @@ index fd69095..4167e1f 100644 dev_kfree_skb_irq(skb); tdinfo->skb = NULL; } -@@ -1739,22 +1732,8 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, +@@ -1739,22 +1735,8 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, int q, int n) { struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); @@ -98,7 +100,7 @@ index fd69095..4167e1f 100644 } /** -@@ -1925,7 +1904,7 @@ static int velocity_tx_srv(struct velocity_info *vptr) +@@ -1925,7 +1907,7 @@ static int velocity_tx_srv(struct velocity_info *vptr) stats->tx_packets++; stats->tx_bytes += tdinfo->skb->len; } @@ -107,7 +109,7 @@ index fd69095..4167e1f 100644 vptr->tx.used[qnum]--; } vptr->tx.tail[qnum] = idx; -@@ -2534,9 +2513,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, +@@ -2534,9 +2516,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } From 35cc504508a2b3d5dd8671eeb269b1b845e71f7b Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 2 Sep 2010 13:15:02 -0400 Subject: [PATCH 030/277] Simplify the VIA Velocity changes. The last round of fixes introduced some bugs. --- kernel.spec | 6 +- linux-2.6-via-velocity-dma-fix.patch | 120 +++++++++++++-------------- 2 files changed, 65 insertions(+), 61 deletions(-) diff --git a/kernel.spec b/kernel.spec index 26a664deb..b71554d0d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 16 +%global baserelease 17 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1896,6 +1896,10 @@ fi # and build. %changelog +* Thu Sep 02 2010 Dave Jones 2.6.35.4-17 +- Simplify the VIA Velocity changes. The last round of + fixes introduced some bugs. + * Wed Sep 01 2010 Dave Jones 2.6.35.4-16 - Another VIA Velocity fix. This time in ifdown path. diff --git a/linux-2.6-via-velocity-dma-fix.patch b/linux-2.6-via-velocity-dma-fix.patch index d11064661..09c2ec6c3 100644 --- a/linux-2.6-via-velocity-dma-fix.patch +++ b/linux-2.6-via-velocity-dma-fix.patch @@ -33,91 +33,91 @@ Reported-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c -index fd69095..258c368 100644 +index fd69095..a4e2164 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c -@@ -1705,28 +1705,24 @@ err_free_dma_rings_0: - * recycle it, if not then unmap the buffer. - */ - static void velocity_free_tx_buf(struct velocity_info *vptr, -- struct velocity_td_info *tdinfo, struct tx_desc *td) -+ struct velocity_td_info *tdinfo) - { - struct sk_buff *skb = tdinfo->skb; -+ int i; +@@ -1716,15 +1716,15 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, + int i; -- /* -- * Don't unmap the pre-allocated tx_bufs -- */ -- if (tdinfo->skb_dma) { -- int i; -+ if (unlikely(!tdinfo->skb)) -+ return; - -- for (i = 0; i < tdinfo->nskb_dma; i++) { + for (i = 0; i < tdinfo->nskb_dma; i++) { - size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN); -+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[0], -+ skb_headlen(skb), PCI_DMA_TODEVICE); ++ if (i > 0) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; - /* For scatter-gather */ - if (skb_shinfo(skb)->nr_frags > 0) - pktlen = max_t(size_t, pktlen, - td->td_buf[i].size & ~TD_QUEUE); -+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { -+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - +- - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], - le16_to_cpu(pktlen), PCI_DMA_TODEVICE); -- } -+ pci_unmap_page(vptr->pdev, tdinfo->skb_dma[i + 1], -+ frag->size, PCI_DMA_TODEVICE); ++ pci_unmap_page(vptr->pdev, tdinfo->skb_dma[i], ++ frag->size, PCI_DMA_TODEVICE); ++ } else { ++ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], ++ skb_headlen(skb), PCI_DMA_TODEVICE); ++ } + } } -+ dev_kfree_skb_irq(skb); - tdinfo->skb = NULL; - } -@@ -1739,22 +1735,8 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, - int q, int n) - { - struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); -- int i; -- -- if (td_info == NULL) -- return; +@@ -1745,14 +1745,20 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, + return; -- if (td_info->skb) { -- for (i = 0; i < td_info->nskb_dma; i++) { + if (td_info->skb) { ++ struct sk_buff *skb = td_info->skb; ++ + for (i = 0; i < td_info->nskb_dma; i++) { - if (td_info->skb_dma[i]) { -- pci_unmap_single(vptr->pdev, td_info->skb_dma[i], ++ if (i > 0) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; ++ ++ pci_unmap_page(vptr->pdev, td_info->skb_dma[i], ++ frag->size, PCI_DMA_TODEVICE); ++ } else { + pci_unmap_single(vptr->pdev, td_info->skb_dma[i], - td_info->skb->len, PCI_DMA_TODEVICE); - td_info->skb_dma[i] = 0; -- } -- } -- dev_kfree_skb(td_info->skb); -- td_info->skb = NULL; -- } -+ velocity_free_tx_buf(vptr, td_info); - } - - /** -@@ -1925,7 +1907,7 @@ static int velocity_tx_srv(struct velocity_info *vptr) - stats->tx_packets++; - stats->tx_bytes += tdinfo->skb->len; ++ skb_headlen(skb), PCI_DMA_TODEVICE); } -- velocity_free_tx_buf(vptr, tdinfo, td); -+ velocity_free_tx_buf(vptr, tdinfo); - vptr->tx.used[qnum]--; } - vptr->tx.tail[qnum] = idx; -@@ -2534,9 +2516,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, +- dev_kfree_skb(td_info->skb); ++ dev_kfree_skb(skb); + td_info->skb = NULL; + } + } +@@ -2520,7 +2526,6 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, + struct tx_desc *td_ptr; + struct velocity_td_info *tdinfo; + unsigned long flags; +- int pktlen; + int index, prev; + int i = 0; + +@@ -2534,10 +2539,6 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } - pktlen = skb_shinfo(skb)->nr_frags == 0 ? - max_t(unsigned int, skb->len, ETH_ZLEN) : - skb_headlen(skb); -+ pktlen = skb_headlen(skb); - +- spin_lock_irqsave(&vptr->lock, flags); + index = vptr->tx.curr[qnum]; +@@ -2552,11 +2553,12 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, + * add it to the transmit ring. + */ + tdinfo->skb = skb; +- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); +- td_ptr->tdesc0.len = cpu_to_le16(pktlen); ++ tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, ++ skb_headlen(skb), PCI_DMA_TODEVICE); ++ td_ptr->tdesc0.len = cpu_to_le16(skb->len); + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; +- td_ptr->td_buf[0].size = cpu_to_le16(pktlen); ++ td_ptr->td_buf[0].size = cpu_to_le16(skb_headlen(skb)); + + /* Handle fragments */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { From 7def7eaed3c2c124c8179917f544674931ed416d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 2 Sep 2010 17:23:32 -0400 Subject: [PATCH 031/277] Scatter-gather on via-velocity is hopelessly broken. Just switch it off for now. --- kernel.spec | 6 +- linux-2.6-via-velocity-dma-fix.patch | 115 +++------------------------ 2 files changed, 15 insertions(+), 106 deletions(-) diff --git a/kernel.spec b/kernel.spec index b71554d0d..0ac884dc5 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 17 +%global baserelease 18 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1896,6 +1896,10 @@ fi # and build. %changelog +* Thu Sep 02 2010 Dave Jones 2.6.35.4-18 +- Scatter-gather on via-velocity is hopelessly broken. + Just switch it off for now. + * Thu Sep 02 2010 Dave Jones 2.6.35.4-17 - Simplify the VIA Velocity changes. The last round of fixes introduced some bugs. diff --git a/linux-2.6-via-velocity-dma-fix.patch b/linux-2.6-via-velocity-dma-fix.patch index 09c2ec6c3..21286776c 100644 --- a/linux-2.6-via-velocity-dma-fix.patch +++ b/linux-2.6-via-velocity-dma-fix.patch @@ -9,115 +9,20 @@ References: <20100901200555.GA30689@redhat.com> <20100901.133414.24593005.davem@davemloft.net> <20100901.133547.236248297.davem@davemloft.net> -New patch: -via-velocity: Fix TX buffer unmapping. - -Fix several bugs in TX buffer DMA unmapping: - -1) Use pci_unmap_page() as appropriate. - -2) Don't try to fetch the length from the DMA descriptor, - the chip and modify that value. Use the correct lengths, - calculated the same way as is done at map time. - -3) Kill meaningless NULL checks (against embedded sized - arrays which can never be NULL, and against the address - of the non-zero indexed entry of an array). - -4) max() on ETH_ZLEN is not necessary and just adds - confusion, since the xmit function does a proper - skb_padto() very early on. - -Reported-by: Dave Jones -Signed-off-by: David S. Miller +Ok, this is becomming hopeless. Let's just try turning off SG support +for now, the length calculations are correct in those cases. diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c -index fd69095..a4e2164 100644 +index fd69095..f534123 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c -@@ -1716,15 +1716,15 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, - int i; +@@ -2824,7 +2824,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi + netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); - for (i = 0; i < tdinfo->nskb_dma; i++) { -- size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN); -+ if (i > 0) { -+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | +- NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM | NETIF_F_SG; ++ NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; -- /* For scatter-gather */ -- if (skb_shinfo(skb)->nr_frags > 0) -- pktlen = max_t(size_t, pktlen, -- td->td_buf[i].size & ~TD_QUEUE); -- -- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], -- le16_to_cpu(pktlen), PCI_DMA_TODEVICE); -+ pci_unmap_page(vptr->pdev, tdinfo->skb_dma[i], -+ frag->size, PCI_DMA_TODEVICE); -+ } else { -+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], -+ skb_headlen(skb), PCI_DMA_TODEVICE); -+ } - } - } - dev_kfree_skb_irq(skb); -@@ -1745,14 +1745,20 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, - return; - - if (td_info->skb) { -+ struct sk_buff *skb = td_info->skb; -+ - for (i = 0; i < td_info->nskb_dma; i++) { -- if (td_info->skb_dma[i]) { -+ if (i > 0) { -+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; -+ -+ pci_unmap_page(vptr->pdev, td_info->skb_dma[i], -+ frag->size, PCI_DMA_TODEVICE); -+ } else { - pci_unmap_single(vptr->pdev, td_info->skb_dma[i], -- td_info->skb->len, PCI_DMA_TODEVICE); -- td_info->skb_dma[i] = 0; -+ skb_headlen(skb), PCI_DMA_TODEVICE); - } - } -- dev_kfree_skb(td_info->skb); -+ dev_kfree_skb(skb); - td_info->skb = NULL; - } - } -@@ -2520,7 +2526,6 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, - struct tx_desc *td_ptr; - struct velocity_td_info *tdinfo; - unsigned long flags; -- int pktlen; - int index, prev; - int i = 0; - -@@ -2534,10 +2539,6 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, - return NETDEV_TX_OK; - } - -- pktlen = skb_shinfo(skb)->nr_frags == 0 ? -- max_t(unsigned int, skb->len, ETH_ZLEN) : -- skb_headlen(skb); -- - spin_lock_irqsave(&vptr->lock, flags); - - index = vptr->tx.curr[qnum]; -@@ -2552,11 +2553,12 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, - * add it to the transmit ring. - */ - tdinfo->skb = skb; -- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); -- td_ptr->tdesc0.len = cpu_to_le16(pktlen); -+ tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, -+ skb_headlen(skb), PCI_DMA_TODEVICE); -+ td_ptr->tdesc0.len = cpu_to_le16(skb->len); - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; -- td_ptr->td_buf[0].size = cpu_to_le16(pktlen); -+ td_ptr->td_buf[0].size = cpu_to_le16(skb_headlen(skb)); - - /* Handle fragments */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - + ret = register_netdev(dev); + if (ret < 0) From 44c4f071d9238f07851103008bd4589d9d8857cc Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 3 Sep 2010 05:23:00 -0400 Subject: [PATCH 032/277] Re-enable I2O, but only for 32-bit x86 (#629676) --- config-i686-PAE | 3 +++ config-x86-generic | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/config-i686-PAE b/config-i686-PAE index 1e58e65b2..eebaa6fba 100644 --- a/config-i686-PAE +++ b/config-i686-PAE @@ -3,3 +3,6 @@ CONFIG_HIGHMEM64G=y CONFIG_XEN_DEV_EVTCHN=m CONFIG_XEN_SYS_HYPERVISOR=y + +# I2O only works on non-PAE 32-bit x86 +# CONFIG_I2O is not set diff --git a/config-x86-generic b/config-x86-generic index 58a8cf11b..4f2f6092f 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -100,6 +100,16 @@ CONFIG_SECCOMP=y CONFIG_CAPI_EICON=y +# I2O enabled only for 32-bit x86, disabled for PAE kernel +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_I2O_CONFIG=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m + # # APM (Advanced Power Management) BIOS Support # From d3a72eaedc5c7c197033f209aa1101f9894bbbdc Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 3 Sep 2010 13:25:36 -0400 Subject: [PATCH 033/277] restore appleir driver that got lost from f13 --- add-appleir-usb-driver.patch | 99 ++++++++++++++++++++++++++++++++++++ kernel.spec | 7 +++ 2 files changed, 106 insertions(+) create mode 100644 add-appleir-usb-driver.patch diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch new file mode 100644 index 000000000..4d83e70e6 --- /dev/null +++ b/add-appleir-usb-driver.patch @@ -0,0 +1,99 @@ +appleir usb driver from hadess + +--- + drivers/hid/hid-apple.c | 4 ---- + drivers/hid/hid-core.c | 5 +++-- + drivers/hid/hid-ids.h | 1 + + drivers/input/misc/Kconfig | 13 +++++++++++++ + drivers/input/misc/Makefile | 1 + + 5 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c +index bba05d0..0059d5a 100644 +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev) + } + + static const struct hid_device_id apple_devices[] = { +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL), +- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4), +- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), + .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 866e54e..42c2a27 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1239,8 +1239,6 @@ static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, +@@ -1574,6 +1572,9 @@ static const struct hid_device_id hid_ignore_list[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 31601ee..280b7a8 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -98,6 +98,7 @@ + #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b + #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a + #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b ++#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 + #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 + #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 + +diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig +index c44b9ea..90b85a6 100644 +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -199,6 +199,19 @@ config INPUT_KEYSPAN_REMOTE + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. + ++config INPUT_APPLEIR ++ tristate "Apple infrared receiver (built in)" ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use a Apple infrared remote control. All ++ the Apple computers from 2005 onwards include such a port, except ++ the unibody Macbook (2009), and Mac Pros. This receiver is also ++ used in the Apple TV set-top box. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called appleir. ++ + config INPUT_POWERMATE + tristate "Griffin PowerMate and Contour Jog support" + depends on USB_ARCH_HAS_HCD +diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile +index 71fe57d..62a5c60 100644 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_INPUT_AD714X) += ad714x.o + obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o + obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o + obj-$(CONFIG_INPUT_APANEL) += apanel.o ++obj-$(CONFIG_INPUT_APPLEIR) += appleir.o + obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o + obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o + obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o +-- +1.7.2.2 + diff --git a/kernel.spec b/kernel.spec index 0ac884dc5..0b9539b92 100644 --- a/kernel.spec +++ b/kernel.spec @@ -701,6 +701,8 @@ Patch12017: prevent-runtime-conntrack-changes.patch Patch12018: neuter_intel_microcode_load.patch +Patch12019: add-appleir-usb-driver.patch + Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch # rhbz #617699 @@ -1298,6 +1300,8 @@ ApplyPatch linux-2.6-via-velocity-dma-fix.patch # Patches headed upstream ApplyPatch disable-i8042-check-on-apple-mac.patch +ApplyPatch add-appleir-usb-driver.patch + ApplyPatch neuter_intel_microcode_load.patch ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch @@ -1896,6 +1900,9 @@ fi # and build. %changelog +* Fri Sep 03 2010 Kyle McMartin +- Restore appleir driver that got lost in the 2.6.35 rebase. + * Thu Sep 02 2010 Dave Jones 2.6.35.4-18 - Scatter-gather on via-velocity is hopelessly broken. Just switch it off for now. From 1001ab34f7e74ce2704af0746e23abe4a84ece32 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Sep 2010 15:55:25 +1000 Subject: [PATCH 034/277] nouveau: misc fixes from upstream + NVAF support This looks far far worse than it is... The reason: - NVAF support came after nv50_grctx.c was de-magiced (ie. lots of comments explaining what all the hexified numbers are for) - nv50_grctx.c de-magic depended on an earlier commit which changed all gpu object accessors from 32-bit indices to byte offsets All in all, it was easier to pull in those big scary-looking (but harmless) commits than to risk messing up a backport. --- drm-nouveau-race-fix.patch | 14 +- drm-nouveau-updates.patch | 7170 ++++++++++++++++++++++++++++++++++-- kernel.spec | 5 +- 3 files changed, 6772 insertions(+), 417 deletions(-) diff --git a/drm-nouveau-race-fix.patch b/drm-nouveau-race-fix.patch index 8b6f4dfd7..bf6cc4f83 100644 --- a/drm-nouveau-race-fix.patch +++ b/drm-nouveau-race-fix.patch @@ -1,7 +1,7 @@ -From 6b33cff9cd4f6f26df99e1486d53c91698d133b4 Mon Sep 17 00:00:00 2001 +From 4733f633c4bfb0672d5bd88a8d19a03e27a3c1d0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 23 Jul 2010 09:06:52 +1000 -Subject: [PATCH 5/5] drm-nouveau-race-fix +Subject: [PATCH 2/2] drm-nouveau-race-fix drm/nouveau: fix race condition when under memory pressure @@ -30,7 +30,7 @@ Signed-off-by: Ben Skeggs 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index f1357f1..f552c76 100644 +index 553a01d..5e62d1b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -36,6 +36,21 @@ @@ -56,10 +56,10 @@ index f1357f1..f552c76 100644 nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index c001574..922ef43 100644 +index 2eb622b..70a16f3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h -@@ -1165,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); +@@ -1167,6 +1167,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); @@ -68,7 +68,7 @@ index c001574..922ef43 100644 /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c -index 547f2c2..a915dcd 100644 +index 62ac673..613f878 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -361,16 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, @@ -137,5 +137,5 @@ index 547f2c2..a915dcd 100644 ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, req->nr_buffers, &op, &do_reloc); -- -1.7.2 +1.7.2.2 diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 08baed1e1..82ded4701 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,7 +1,7 @@ -From 0983b95112413e5239b09f1f1a4500c0bccfe3b7 Mon Sep 17 00:00:00 2001 +From c156fa3c71b6581b34526a9b2b649c3f4d57dd3e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Jun 2010 15:32:24 +1000 -Subject: [PATCH 4/4] drm-nouveau-updates +Subject: [PATCH 1/2] drm-nouveau-updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -656,73 +656,268 @@ drm/nouveau: Don't try DDC on the dummy I2C channel. Signed-off-by: Francisco Jerez drm/nv50: fix minor thinko from nvc0 changes + +drm/nouveau: check for error when allocating/mapping dummy page + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove warning about unknown tmds table revisions + +This message is apparently confusing people, and is being blamed for some +modesetting issues. Lets remove the message, and instead replace it +with an unconditional printout of the table revision. + +Signed-off-by: Ben Skeggs + +drm/nouveau: punt some more log messages to debug level + +Signed-off-by: Ben Skeggs + +drm/nv50-nvc0: ramht_size is meant to be in bytes, not entries + +Fixes an infinite loop that can happen in RAMHT lookup. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Add TV-out quirk for an MSI nForce2 IGP. + +The blob also thinks there's a TV connected, so hardware bug... + +Signed-off-by: Francisco Jerez + +drm/nouveau: Workaround missing GPIO tables on an Apple iMac G4 NV18. + +This should fix the reported TV-out load detection false positives +(fdo bug 29455). + +Reported-by: Vlado Plaga +Signed-off-by: Francisco Jerez + +drm/nvc0: fix thinko in instmem suspend/resume + +Signed-off-by: Ben Skeggs + +drm/nv50: calculate vram reordering block size + +Will be used at a later point when we plug in an alternative VRAM memory +manager for GeForce 8+ boards. + +Based on pscnv code to do the same. + +Signed-off-by: Ben Skeggs +Signed-off-by: Marcin KoÅ›cielnicki + +drm/nv50: add dcb type 14 to enum to prevent compiler complaint + +Signed-off-by: Ben Skeggs + +drm/nouveau: Use a helper function to match PCI device/subsystem IDs. + +Signed-off-by: Francisco Jerez + +drm/nv30: Apply modesetting to the correct slave encoder + +Signed-off-by: Patrice Mandin +Reviewed-by: Francisco Jerez + +drm/nouveau: Fix backlight control on PPC machines with an internal TMDS panel. + +This commit fixes fdo bug 29685. + +Reported-by: Vlado Plaga +Signed-off-by: Francisco Jerez + +drm/nouveau: Fix TMDS on some DCB1.5 boards. + +The TMDS output of an nv11 was being detected as LVDS, because it uses +DCB type 2 for TMDS instead of type 4. + +Reported-by: Bertrand VIEILLE +Signed-off-by: Francisco Jerez + +drm/nv20: Don't use pushbuf calls on the original nv20. + +The "return" command is buggy on the original nv20, it jumps back to +the caller address as expected, but it doesn't clear the subroutine +active bit making the subsequent pushbuf calls fail with a "stack" +overflow. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Fix suspend on some nv4x AGP cards. + +On some nv4x cards (specifically, the ones that use an internal +PCIE->AGP bridge) the AGP controller state isn't preserved after a +suspend/resume cycle, and the AGP control registers have moved from +0x18xx to 0x100xx, so the FW check in nouveau_mem_reset_agp() doesn't +quite work. Check "dev->agp->mode" instead. + +Signed-off-by: Francisco Jerez + +drm/nv20: Use the nv30 CRTC bandwidth calculation code. + +nv2x CRTC FIFOs are as large as in nv3x (4kB it seems), and the FIFO +control registers have the same layout: we can make them share the +same implementation. + +Previously we were using the nv1x code, but the calculated FIFO +watermarks are usually too low for nv2x and they cause horrible +scanout artifacts. They've gone unnoticed until now because we've been +leaving one of the bandwidth regs uninitialized (CRE 47, which +contains the most significant bits of FFLWM), so everything seemed to +work fine except in some cases after a cold boot, depending on the +memory bandwidth and pixel clocks used. + +Signed-off-by: Francisco Jerez + +drm/nv50: add new accelerated bo move funtion + +Hopefully this one will be better able to cope with moving tiled buffers +around without getting them all scrambled as a result. + +Signed-off-by: Ben Skeggs + +drm/nouveau: move check for no-op bo move before memcpy fallback + +Signed-off-by: Ben Skeggs + +drm/nouveau: remove second map of notifier bo + +Signed-off-by: Ben Skeggs + +drm/nouveau: require explicit unmap of kmapped bos + +Signed-off-by: Ben Skeggs + +drm/nv17-nv4x: Fix analog load detection false positive on rare occasions. + +On some boards the residual current DAC outputs can draw when they're +disconnected can be high enough to give a false load detection +positive (I've only seen it in the S-video luma output of some cards, +but just to be sure). The output line capacitance is limited and +sampling twice should fix it reliably. + +Signed-off-by: Francisco Jerez + +drm/nv40: Try to set up CRE_LCD even if it has unknown bits set. + +They don't seem to do anything useful, and we really want to program +CRE_LCD if we aren't lucky enough to find the right CRTC binding +already set. + +Signed-off-by: Francisco Jerez + +drm/nouveau: have nv_mask return original register value + +Signed-off-by: Ben Skeggs + +drm/nv50: initialize ramht_refs list for faked 0 channel + +We need it for PFIFO_INTR_CACHE_ERROR interrupt handling, +because nouveau_fifo_swmthd looks for matching gpuobj in +ramht_refs list. +It fixes kernel panic in nouveau_gpuobj_ref_find. + +Signed-off-by: Marcin Slusarz +Signed-off-by: Ben Skeggs + +drm/nouveau: move ramht code out of nouveau_object.c, nothing to see here + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: modify object accessors, offset in bytes rather than dwords + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv50: demagic grctx, and add NVAF support + +Signed-off-by: Ben Skeggs +Signed-off-by: Marcin KoÅ›cielnicki + +drm/nv50: move vm trap to nv50_fb.c + +Signed-off-by: Ben Skeggs + +drm/nv50: report BAR access faults + +Signed-off-by: Ben Skeggs --- drivers/gpu/drm/drm_crtc_helper.c | 22 +- drivers/gpu/drm/i2c/ch7006_drv.c | 22 +- drivers/gpu/drm/i2c/ch7006_priv.h | 2 +- drivers/gpu/drm/nouveau/Makefile | 12 +- - drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 ++- - drivers/gpu/drm/nouveau/nouveau_bios.c | 820 ++++++++++++++++++++++----- - drivers/gpu/drm/nouveau/nouveau_bios.h | 5 +- - drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +- - drivers/gpu/drm/nouveau/nouveau_calc.c | 4 +- - drivers/gpu/drm/nouveau/nouveau_channel.c | 5 - - drivers/gpu/drm/nouveau/nouveau_connector.c | 417 ++++++-------- + drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 +- + drivers/gpu/drm/nouveau/nouveau_bios.c | 910 ++++++-- + drivers/gpu/drm/nouveau/nouveau_bios.h | 6 +- + drivers/gpu/drm/nouveau/nouveau_bo.c | 223 ++- + drivers/gpu/drm/nouveau/nouveau_calc.c | 10 +- + drivers/gpu/drm/nouveau/nouveau_channel.c | 6 +- + drivers/gpu/drm/nouveau/nouveau_connector.c | 417 ++-- drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +- - drivers/gpu/drm/nouveau/nouveau_dma.c | 8 +- - drivers/gpu/drm/nouveau/nouveau_dp.c | 128 +++-- + drivers/gpu/drm/nouveau/nouveau_dma.c | 7 - + drivers/gpu/drm/nouveau/nouveau_dp.c | 128 +- drivers/gpu/drm/nouveau/nouveau_drv.c | 39 +- - drivers/gpu/drm/nouveau/nouveau_drv.h | 178 ++++--- + drivers/gpu/drm/nouveau/nouveau_drv.h | 203 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 16 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- drivers/gpu/drm/nouveau/nouveau_fence.c | 35 +- - drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +- - drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 ------ - drivers/gpu/drm/nouveau/nouveau_hw.c | 11 +- - drivers/gpu/drm/nouveau/nouveau_i2c.c | 83 ++- + drivers/gpu/drm/nouveau/nouveau_gem.c | 15 +- + drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 -- + drivers/gpu/drm/nouveau/nouveau_grctx.h | 2 +- + drivers/gpu/drm/nouveau/nouveau_hw.c | 13 +- + drivers/gpu/drm/nouveau/nouveau_i2c.c | 83 +- drivers/gpu/drm/nouveau/nouveau_i2c.h | 11 +- - drivers/gpu/drm/nouveau/nouveau_irq.c | 6 +- - drivers/gpu/drm/nouveau/nouveau_mem.c | 327 +++--------- + drivers/gpu/drm/nouveau/nouveau_irq.c | 70 +- + drivers/gpu/drm/nouveau/nouveau_mem.c | 404 ++--- drivers/gpu/drm/nouveau/nouveau_notifier.c | 30 +- - drivers/gpu/drm/nouveau/nouveau_object.c | 105 +--- - drivers/gpu/drm/nouveau/nouveau_reg.h | 109 +++-- - drivers/gpu/drm/nouveau/nouveau_sgdma.c | 46 +-- - drivers/gpu/drm/nouveau/nouveau_state.c | 340 +++++++---- - drivers/gpu/drm/nouveau/nv04_crtc.c | 8 + - drivers/gpu/drm/nouveau/nv04_dac.c | 50 ++- - drivers/gpu/drm/nouveau/nv04_dfp.c | 85 +++- - drivers/gpu/drm/nouveau/nv04_display.c | 90 ++-- - drivers/gpu/drm/nouveau/nv04_fifo.c | 20 +- + drivers/gpu/drm/nouveau/nouveau_object.c | 325 +-- + drivers/gpu/drm/nouveau/nouveau_ramht.c | 160 ++ + drivers/gpu/drm/nouveau/nouveau_ramht.h | 31 + + drivers/gpu/drm/nouveau/nouveau_reg.h | 109 +- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 108 +- + drivers/gpu/drm/nouveau/nouveau_state.c | 340 ++- + drivers/gpu/drm/nouveau/nv04_crtc.c | 11 +- + drivers/gpu/drm/nouveau/nv04_dac.c | 60 +- + drivers/gpu/drm/nouveau/nv04_dfp.c | 145 +- + drivers/gpu/drm/nouveau/nv04_display.c | 90 +- + drivers/gpu/drm/nouveau/nv04_fifo.c | 28 +- drivers/gpu/drm/nouveau/nv04_graph.c | 5 +- drivers/gpu/drm/nouveau/nv04_instmem.c | 21 +- drivers/gpu/drm/nouveau/nv04_mc.c | 4 + - drivers/gpu/drm/nouveau/nv04_tv.c | 133 ++--- + drivers/gpu/drm/nouveau/nv04_tv.c | 133 +- drivers/gpu/drm/nouveau/nv10_fifo.c | 10 - - drivers/gpu/drm/nouveau/nv10_gpio.c | 92 +++ - drivers/gpu/drm/nouveau/nv10_graph.c | 175 ++++-- - drivers/gpu/drm/nouveau/nv17_gpio.c | 92 --- - drivers/gpu/drm/nouveau/nv17_tv.c | 65 ++- - drivers/gpu/drm/nouveau/nv20_graph.c | 96 ++-- - drivers/gpu/drm/nouveau/nv30_fb.c | 95 +++ + drivers/gpu/drm/nouveau/nv10_gpio.c | 92 + + drivers/gpu/drm/nouveau/nv10_graph.c | 175 +- + drivers/gpu/drm/nouveau/nv17_gpio.c | 92 - + drivers/gpu/drm/nouveau/nv17_tv.c | 82 +- + drivers/gpu/drm/nouveau/nv20_graph.c | 564 +++--- + drivers/gpu/drm/nouveau/nv30_fb.c | 95 + drivers/gpu/drm/nouveau/nv40_fifo.c | 8 - - drivers/gpu/drm/nouveau/nv40_graph.c | 58 +-- + drivers/gpu/drm/nouveau/nv40_graph.c | 62 +- + drivers/gpu/drm/nouveau/nv40_grctx.c | 6 +- drivers/gpu/drm/nouveau/nv40_mc.c | 2 +- - drivers/gpu/drm/nouveau/nv50_crtc.c | 65 +-- + drivers/gpu/drm/nouveau/nv50_crtc.c | 67 +- drivers/gpu/drm/nouveau/nv50_dac.c | 43 +- - drivers/gpu/drm/nouveau/nv50_display.c | 424 +++++++++------ + drivers/gpu/drm/nouveau/nv50_display.c | 435 +++-- drivers/gpu/drm/nouveau/nv50_display.h | 6 +- - drivers/gpu/drm/nouveau/nv50_fifo.c | 126 ++--- - drivers/gpu/drm/nouveau/nv50_gpio.c | 35 ++ - drivers/gpu/drm/nouveau/nv50_graph.c | 86 ++-- - drivers/gpu/drm/nouveau/nv50_instmem.c | 67 +-- - drivers/gpu/drm/nouveau/nv50_sor.c | 105 ++-- - drivers/gpu/drm/nouveau/nvc0_fb.c | 38 ++ - drivers/gpu/drm/nouveau/nvc0_fifo.c | 95 +++ - drivers/gpu/drm/nouveau/nvc0_graph.c | 74 +++ - drivers/gpu/drm/nouveau/nvc0_instmem.c | 231 ++++++++ + drivers/gpu/drm/nouveau/nv50_fb.c | 39 + + drivers/gpu/drm/nouveau/nv50_fifo.c | 335 ++-- + drivers/gpu/drm/nouveau/nv50_gpio.c | 35 + + drivers/gpu/drm/nouveau/nv50_graph.c | 104 +- + drivers/gpu/drm/nouveau/nv50_grctx.c | 3305 +++++++++++++++++---------- + drivers/gpu/drm/nouveau/nv50_instmem.c | 81 +- + drivers/gpu/drm/nouveau/nv50_sor.c | 105 +- + drivers/gpu/drm/nouveau/nvc0_fb.c | 38 + + drivers/gpu/drm/nouveau/nvc0_fifo.c | 95 + + drivers/gpu/drm/nouveau/nvc0_graph.c | 74 + + drivers/gpu/drm/nouveau/nvc0_instmem.c | 234 ++ drivers/gpu/drm/nouveau/nvreg.h | 22 - - 64 files changed, 3285 insertions(+), 2257 deletions(-) + 70 files changed, 6456 insertions(+), 4215 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c + create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.c + create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.h create mode 100644 drivers/gpu/drm/nouveau/nv10_gpio.c delete mode 100644 drivers/gpu/drm/nouveau/nv17_gpio.c create mode 100644 drivers/gpu/drm/nouveau/nv30_fb.c @@ -857,7 +1052,7 @@ index 9487123..17667b7 100644 struct ch7006_state state; diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile -index acd31ed..e9b06e4 100644 +index acd31ed..d6cfbf2 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -9,20 +9,20 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ @@ -865,7 +1060,7 @@ index acd31ed..e9b06e4 100644 nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ - nouveau_dp.o nouveau_grctx.o \ -+ nouveau_dp.o \ ++ nouveau_dp.o nouveau_ramht.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ @@ -955,7 +1150,7 @@ index d4bcca8..c17a055 100644 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index e492919..eb77710 100644 +index e492919..8fa3396 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -28,6 +28,8 @@ @@ -2043,7 +2238,52 @@ index e492919..eb77710 100644 { NULL , 0 , NULL } }; -@@ -4068,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, +@@ -3376,27 +3869,10 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr + } + #ifdef __powerpc__ + /* Powerbook specific quirks */ +- if ((dev->pci_device & 0xffff) == 0x0179 || +- (dev->pci_device & 0xffff) == 0x0189 || +- (dev->pci_device & 0xffff) == 0x0329) { +- if (script == LVDS_RESET) { +- nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); +- +- } else if (script == LVDS_PANEL_ON) { +- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, +- bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) +- | (1 << 31)); +- bios_wr32(bios, NV_PCRTC_GPIO_EXT, +- bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); +- +- } else if (script == LVDS_PANEL_OFF) { +- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, +- bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) +- & ~(1 << 31)); +- bios_wr32(bios, NV_PCRTC_GPIO_EXT, +- bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); +- } +- } ++ if (script == LVDS_RESET && ++ (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || ++ dev->pci_device == 0x0329)) ++ nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); + #endif + + return 0; +@@ -3888,11 +4364,8 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b + * + * For the moment, a quirk will do :) + */ +- if ((dev->pdev->device == 0x01d7) && +- (dev->pdev->subsystem_vendor == 0x1028) && +- (dev->pdev->subsystem_device == 0x01c2)) { ++ if (nv_match_device(dev, 0x01d7, 0x1028, 0x01c2)) + bios->fp.duallink_transition_clk = 80000; +- } + + /* set dual_link flag for EDID case */ + if (pxclk && (chip_version < 0x25 || chip_version > 0x28)) +@@ -4068,7 +4541,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, bios->display.script_table_ptr, table[2], table[3], table[0] >= 0x21); if (!otable) { @@ -2052,7 +2292,34 @@ index e492919..eb77710 100644 return 1; } -@@ -4125,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, +@@ -4094,7 +4567,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + return 1; + } + +- NV_TRACE(dev, "0x%04X: parsing output script 0\n", script); ++ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); + nouveau_bios_run_init_table(dev, script, dcbent); + } else + if (pxclk == -1) { +@@ -4104,7 +4577,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + return 1; + } + +- NV_TRACE(dev, "0x%04X: parsing output script 1\n", script); ++ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); + nouveau_bios_run_init_table(dev, script, dcbent); + } else + if (pxclk == -2) { +@@ -4117,7 +4590,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + return 1; + } + +- NV_TRACE(dev, "0x%04X: parsing output script 2\n", script); ++ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); + nouveau_bios_run_init_table(dev, script, dcbent); + } else + if (pxclk > 0) { +@@ -4125,11 +4598,11 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, if (script) script = clkcmptable(bios, script, pxclk); if (!script) { @@ -2061,7 +2328,21 @@ index e492919..eb77710 100644 return 1; } -@@ -4484,7 +4977,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims +- NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script); ++ NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); + nouveau_bios_run_init_table(dev, script, dcbent); + } else + if (pxclk < 0) { +@@ -4141,7 +4614,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + return 1; + } + +- NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script); ++ NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); + nouveau_bios_run_init_table(dev, script, dcbent); + } + +@@ -4484,7 +4957,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims pll_lim->min_p = record[12]; pll_lim->max_p = record[13]; /* where did this go to?? */ @@ -2070,7 +2351,32 @@ index e492919..eb77710 100644 pll_lim->refclk = 27000; else pll_lim->refclk = 100000; -@@ -5151,10 +5644,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi +@@ -4864,19 +5337,17 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios, + } + + tmdstableptr = ROM16(bios->data[bitentry->offset]); +- +- if (tmdstableptr == 0x0) { ++ if (!tmdstableptr) { + NV_ERROR(dev, "Pointer to TMDS table invalid\n"); + return -EINVAL; + } + ++ NV_INFO(dev, "TMDS table version %d.%d\n", ++ bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); ++ + /* nv50+ has v2.0, but we don't parse it atm */ +- if (bios->data[tmdstableptr] != 0x11) { +- NV_WARN(dev, +- "TMDS table revision %d.%d not currently supported\n", +- bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); ++ if (bios->data[tmdstableptr] != 0x11) + return -ENOSYS; +- } + + /* + * These two scripts are odd: they don't seem to get run even when +@@ -5151,10 +5622,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; @@ -2089,7 +2395,39 @@ index e492919..eb77710 100644 if (bmplength > 74) { bios->fmaxvco = ROM32(bmp[67]); -@@ -5506,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) +@@ -5312,6 +5787,20 @@ parse_dcb_gpio_table(struct nvbios *bios) + gpio->line = tvdac_gpio[1] >> 4; + gpio->invert = tvdac_gpio[0] & 2; + } ++ } else { ++ /* ++ * No systematic way to store GPIO info on pre-v2.2 ++ * DCBs, try to match the PCI device IDs. ++ */ ++ ++ /* Apple iMac G4 NV18 */ ++ if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { ++ struct dcb_gpio_entry *gpio = new_gpio_entry(bios); ++ ++ gpio->tag = DCB_GPIO_TVDAC0; ++ gpio->line = 4; ++ } ++ + } + + if (!gpio_table_ptr) +@@ -5387,9 +5876,7 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx) + struct drm_device *dev = bios->dev; + + /* Gigabyte NX85T */ +- if ((dev->pdev->device == 0x0421) && +- (dev->pdev->subsystem_vendor == 0x1458) && +- (dev->pdev->subsystem_device == 0x344c)) { ++ if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) { + if (cte->type == DCB_CONNECTOR_HDMI_1) + cte->type = DCB_CONNECTOR_DVI_I; + } +@@ -5506,7 +5993,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) entry->i2c_index = i2c; entry->heads = heads; entry->location = DCB_LOC_ON_CHIP; @@ -2098,7 +2436,7 @@ index e492919..eb77710 100644 } static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) -@@ -5589,9 +6086,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, +@@ -5589,9 +6076,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x4 || conf & 0x8) entry->lvdsconf.use_power_scripts = true; } else { @@ -2112,7 +2450,7 @@ index e492919..eb77710 100644 } if (conf & mask) { /* -@@ -5631,7 +6131,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, +@@ -5631,9 +6121,15 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, } break; case OUTPUT_TMDS: @@ -2125,9 +2463,41 @@ index e492919..eb77710 100644 + entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; + break; - case 0xe: +- case 0xe: ++ case OUTPUT_EOL: /* weird g80 mobile type that "nv" treats as a terminator */ -@@ -5706,13 +6212,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, + dcb->entries--; + return false; +@@ -5670,22 +6166,14 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, + entry->type = OUTPUT_TV; + break; + case 2: +- case 3: +- entry->type = OUTPUT_LVDS; +- break; + case 4: +- switch ((conn & 0x000000f0) >> 4) { +- case 0: +- entry->type = OUTPUT_TMDS; +- break; +- case 1: ++ if (conn & 0x10) + entry->type = OUTPUT_LVDS; +- break; +- default: +- NV_ERROR(dev, "Unknown DCB subtype 4/%d\n", +- (conn & 0x000000f0) >> 4); +- return false; +- } ++ else ++ entry->type = OUTPUT_TMDS; ++ break; ++ case 3: ++ entry->type = OUTPUT_LVDS; + break; + default: + NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f); +@@ -5706,13 +6194,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, case OUTPUT_TV: entry->tvconf.has_component_output = false; break; @@ -2141,7 +2511,7 @@ index e492919..eb77710 100644 case OUTPUT_LVDS: if ((conn & 0x00003f00) != 0x10) entry->lvdsconf.use_straps_for_mode = true; -@@ -5793,6 +6292,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) +@@ -5793,6 +6274,29 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) dcb->entries = newentries; } @@ -2160,9 +2530,7 @@ index e492919..eb77710 100644 + * nasty problems until this is sorted (assuming it's not a + * VBIOS bug). + */ -+ if ((dev->pdev->device == 0x040d) && -+ (dev->pdev->subsystem_vendor == 0x1028) && -+ (dev->pdev->subsystem_device == 0x019b)) { ++ if (nv_match_device(dev, 0x040d, 0x1028, 0x019b)) { + if (*conn == 0x02026312 && *conf == 0x00000020) + return false; + } @@ -2173,7 +2541,7 @@ index e492919..eb77710 100644 static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) { -@@ -5903,6 +6427,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +@@ -5903,6 +6407,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) dcb->i2c_table = &bios->data[i2ctabptr]; if (dcb->version >= 0x30) dcb->i2c_default_indices = dcb->i2c_table[4]; @@ -2193,7 +2561,7 @@ index e492919..eb77710 100644 } if (entries > DCB_MAX_NUM_ENTRIES) -@@ -5926,6 +6463,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +@@ -5926,6 +6443,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) if ((connection & 0x0000000f) == 0x0000000f) continue; @@ -2203,7 +2571,7 @@ index e492919..eb77710 100644 NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", dcb->entries, connection, config); -@@ -6181,9 +6721,8 @@ nouveau_run_vbios_init(struct drm_device *dev) +@@ -6181,9 +6701,8 @@ nouveau_run_vbios_init(struct drm_device *dev) struct nvbios *bios = &dev_priv->vbios; int i, ret = 0; @@ -2215,7 +2583,7 @@ index e492919..eb77710 100644 if (bios->major_version < 5) /* BMP only */ load_nv17_hw_sequencer_ucode(dev, bios); -@@ -6216,8 +6755,6 @@ nouveau_run_vbios_init(struct drm_device *dev) +@@ -6216,8 +6735,6 @@ nouveau_run_vbios_init(struct drm_device *dev) } } @@ -2224,7 +2592,7 @@ index e492919..eb77710 100644 return ret; } -@@ -6238,7 +6775,6 @@ static bool +@@ -6238,7 +6755,6 @@ static bool nouveau_bios_posted(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -2232,7 +2600,7 @@ index e492919..eb77710 100644 unsigned htotal; if (dev_priv->chipset >= NV_50) { -@@ -6248,13 +6784,12 @@ nouveau_bios_posted(struct drm_device *dev) +@@ -6248,13 +6764,12 @@ nouveau_bios_posted(struct drm_device *dev) return true; } @@ -2247,7 +2615,7 @@ index e492919..eb77710 100644 return (htotal != 0); } -@@ -6263,8 +6798,6 @@ nouveau_bios_init(struct drm_device *dev) +@@ -6263,8 +6778,6 @@ nouveau_bios_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; @@ -2256,7 +2624,7 @@ index e492919..eb77710 100644 int ret; if (!NVInitVBIOS(dev)) -@@ -6284,40 +6817,27 @@ nouveau_bios_init(struct drm_device *dev) +@@ -6284,40 +6797,27 @@ nouveau_bios_init(struct drm_device *dev) if (!bios->major_version) /* we don't run version 0 bios */ return 0; @@ -2300,7 +2668,7 @@ index e492919..eb77710 100644 /* allow subsequent scripts to execute */ bios->execute = true; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h -index adf4ec2..fd14dfd 100644 +index adf4ec2..c1de2f3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -81,6 +81,7 @@ struct dcb_connector_table_entry { @@ -2311,7 +2679,15 @@ index adf4ec2..fd14dfd 100644 }; struct dcb_connector_table { -@@ -117,6 +118,7 @@ struct dcb_entry { +@@ -94,6 +95,7 @@ enum dcb_type { + OUTPUT_TMDS = 2, + OUTPUT_LVDS = 3, + OUTPUT_DP = 6, ++ OUTPUT_EOL = 14, /* DCB 4.0+, appears to be end-of-list */ + OUTPUT_ANY = -1 + }; + +@@ -117,6 +119,7 @@ struct dcb_entry { struct { struct sor_conf sor; bool use_straps_for_mode; @@ -2319,7 +2695,7 @@ index adf4ec2..fd14dfd 100644 bool use_power_scripts; } lvdsconf; struct { -@@ -129,6 +131,7 @@ struct dcb_entry { +@@ -129,6 +132,7 @@ struct dcb_entry { } dpconf; struct { struct sor_conf sor; @@ -2327,7 +2703,7 @@ index adf4ec2..fd14dfd 100644 } tmdsconf; }; bool i2c_upper_default; -@@ -249,8 +252,6 @@ struct nvbios { +@@ -249,8 +253,6 @@ struct nvbios { struct { int crtchead; @@ -2337,10 +2713,18 @@ index adf4ec2..fd14dfd 100644 struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index 6f3c195..f1357f1 100644 +index 6f3c195..553a01d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c -@@ -51,9 +51,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) +@@ -43,17 +43,12 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) + struct drm_device *dev = dev_priv->dev; + struct nouveau_bo *nvbo = nouveau_bo(bo); + +- ttm_bo_kunmap(&nvbo->kmap); +- + if (unlikely(nvbo->gem)) + DRM_ERROR("bo %p still attached to GEM object\n", bo); + if (nvbo->tile) nv10_mem_expire_tiling(dev, nvbo->tile, NULL); @@ -2350,7 +2734,7 @@ index 6f3c195..f1357f1 100644 kfree(nvbo); } -@@ -166,9 +163,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -166,9 +161,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } nvbo->channel = NULL; @@ -2360,7 +2744,17 @@ index 6f3c195..f1357f1 100644 *pnvbo = nvbo; return 0; } -@@ -461,9 +455,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, +@@ -296,7 +288,8 @@ nouveau_bo_map(struct nouveau_bo *nvbo) + void + nouveau_bo_unmap(struct nouveau_bo *nvbo) + { +- ttm_bo_kunmap(&nvbo->kmap); ++ if (nvbo) ++ ttm_bo_kunmap(&nvbo->kmap); + } + + u16 +@@ -461,18 +454,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, @@ -2373,18 +2767,276 @@ index 6f3c195..f1357f1 100644 nouveau_fence_unref((void *)&fence); return ret; } -@@ -711,8 +705,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, + + static inline uint32_t +-nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, +- struct ttm_mem_reg *mem) ++nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, ++ struct nouveau_channel *chan, struct ttm_mem_reg *mem) + { +- if (chan == nouveau_bdev(nvbo->bo.bdev)->channel) { ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ ++ if (nvbo->no_vm) { + if (mem->mem_type == TTM_PL_TT) + return NvDmaGART; + return NvDmaVRAM; +@@ -484,86 +479,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, + } + + static int +-nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, +- bool no_wait_reserve, bool no_wait_gpu, +- struct ttm_mem_reg *new_mem) ++nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, ++ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) + { +- struct nouveau_bo *nvbo = nouveau_bo(bo); + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); +- struct ttm_mem_reg *old_mem = &bo->mem; +- struct nouveau_channel *chan; +- uint64_t src_offset, dst_offset; +- uint32_t page_count; ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ u64 length = (new_mem->num_pages << PAGE_SHIFT); ++ u64 src_offset, dst_offset; + int ret; + +- chan = nvbo->channel; +- if (!chan || nvbo->tile_flags || nvbo->no_vm) +- chan = dev_priv->channel; +- + src_offset = old_mem->mm_node->start << PAGE_SHIFT; + dst_offset = new_mem->mm_node->start << PAGE_SHIFT; +- if (chan != dev_priv->channel) { +- if (old_mem->mem_type == TTM_PL_TT) +- src_offset += dev_priv->vm_gart_base; +- else ++ if (!nvbo->no_vm) { ++ if (old_mem->mem_type == TTM_PL_VRAM) + src_offset += dev_priv->vm_vram_base; +- +- if (new_mem->mem_type == TTM_PL_TT) +- dst_offset += dev_priv->vm_gart_base; + else ++ src_offset += dev_priv->vm_gart_base; ++ ++ if (new_mem->mem_type == TTM_PL_VRAM) + dst_offset += dev_priv->vm_vram_base; ++ else ++ dst_offset += dev_priv->vm_gart_base; + } + + ret = RING_SPACE(chan, 3); + if (ret) + return ret; +- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2); +- OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, old_mem)); +- OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, new_mem)); + +- if (dev_priv->card_type >= NV_50) { +- ret = RING_SPACE(chan, 4); ++ BEGIN_RING(chan, NvSubM2MF, 0x0184, 2); ++ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); ++ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); ++ ++ while (length) { ++ u32 amount, stride, height; ++ ++ amount = min(length, (u64)(16 * 1024 * 1024)); ++ stride = 64 * 4; ++ height = amount / stride; ++ ++ if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { ++ ret = RING_SPACE(chan, 8); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubM2MF, 0x0200, 7); ++ OUT_RING (chan, 0); ++ OUT_RING (chan, 0x20); ++ OUT_RING (chan, stride); ++ OUT_RING (chan, height); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 0); ++ OUT_RING (chan, 0); ++ } else { ++ ret = RING_SPACE(chan, 2); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); ++ OUT_RING (chan, 1); ++ } ++ if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { ++ ret = RING_SPACE(chan, 8); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubM2MF, 0x021c, 7); ++ OUT_RING (chan, 0); ++ OUT_RING (chan, 0x20); ++ OUT_RING (chan, stride); ++ OUT_RING (chan, height); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 0); ++ OUT_RING (chan, 0); ++ } else { ++ ret = RING_SPACE(chan, 2); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubM2MF, 0x021c, 1); ++ OUT_RING (chan, 1); ++ } ++ ++ ret = RING_SPACE(chan, 14); + if (ret) + return ret; +- BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); +- OUT_RING(chan, 1); +- BEGIN_RING(chan, NvSubM2MF, 0x021c, 1); +- OUT_RING(chan, 1); ++ ++ BEGIN_RING(chan, NvSubM2MF, 0x0238, 2); ++ OUT_RING (chan, upper_32_bits(src_offset)); ++ OUT_RING (chan, upper_32_bits(dst_offset)); ++ BEGIN_RING(chan, NvSubM2MF, 0x030c, 8); ++ OUT_RING (chan, lower_32_bits(src_offset)); ++ OUT_RING (chan, lower_32_bits(dst_offset)); ++ OUT_RING (chan, stride); ++ OUT_RING (chan, stride); ++ OUT_RING (chan, stride); ++ OUT_RING (chan, height); ++ OUT_RING (chan, 0x00000101); ++ OUT_RING (chan, 0x00000000); ++ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); ++ OUT_RING (chan, 0); ++ ++ length -= amount; ++ src_offset += amount; ++ dst_offset += amount; + } + ++ return 0; ++} ++ ++static int ++nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, ++ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) ++{ ++ u32 src_offset = old_mem->mm_node->start << PAGE_SHIFT; ++ u32 dst_offset = new_mem->mm_node->start << PAGE_SHIFT; ++ u32 page_count = new_mem->num_pages; ++ int ret; ++ ++ ret = RING_SPACE(chan, 3); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2); ++ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); ++ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); ++ + page_count = new_mem->num_pages; + while (page_count) { + int line_count = (page_count > 2047) ? 2047 : page_count; + +- if (dev_priv->card_type >= NV_50) { +- ret = RING_SPACE(chan, 3); +- if (ret) +- return ret; +- BEGIN_RING(chan, NvSubM2MF, 0x0238, 2); +- OUT_RING(chan, upper_32_bits(src_offset)); +- OUT_RING(chan, upper_32_bits(dst_offset)); +- } + ret = RING_SPACE(chan, 11); + if (ret) + return ret; ++ + BEGIN_RING(chan, NvSubM2MF, + NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); +- OUT_RING(chan, lower_32_bits(src_offset)); +- OUT_RING(chan, lower_32_bits(dst_offset)); +- OUT_RING(chan, PAGE_SIZE); /* src_pitch */ +- OUT_RING(chan, PAGE_SIZE); /* dst_pitch */ +- OUT_RING(chan, PAGE_SIZE); /* line_length */ +- OUT_RING(chan, line_count); +- OUT_RING(chan, (1<<8)|(1<<0)); +- OUT_RING(chan, 0); ++ OUT_RING (chan, src_offset); ++ OUT_RING (chan, dst_offset); ++ OUT_RING (chan, PAGE_SIZE); /* src_pitch */ ++ OUT_RING (chan, PAGE_SIZE); /* dst_pitch */ ++ OUT_RING (chan, PAGE_SIZE); /* line_length */ ++ OUT_RING (chan, line_count); ++ OUT_RING (chan, 0x00000101); ++ OUT_RING (chan, 0x00000000); + BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); +- OUT_RING(chan, 0); ++ OUT_RING (chan, 0); + + page_count -= line_count; + src_offset += (PAGE_SIZE * line_count); + dst_offset += (PAGE_SIZE * line_count); + } + ++ return 0; ++} ++ ++static int ++nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, ++ bool no_wait_reserve, bool no_wait_gpu, ++ struct ttm_mem_reg *new_mem) ++{ ++ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct nouveau_channel *chan; ++ int ret; ++ ++ chan = nvbo->channel; ++ if (!chan || nvbo->no_vm) ++ chan = dev_priv->channel; ++ ++ if (dev_priv->card_type < NV_50) ++ ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); ++ else ++ ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem); ++ if (ret) ++ return ret; ++ + return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); + } + +@@ -710,13 +800,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, + if (ret) return ret; - /* Software copy if the card isn't up and running yet. */ +- /* Software copy if the card isn't up and running yet. */ - if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || - !dev_priv->channel) { -+ if (!dev_priv->channel) { - ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); +- ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); +- goto out; +- } +- + /* Fake bo copy. */ + if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { + BUG_ON(bo->mem.mm_node != NULL); +@@ -725,6 +808,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, goto out; } + ++ /* Software copy if the card isn't up and running yet. */ ++ if (!dev_priv->channel) { ++ ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); ++ goto out; ++ } ++ + /* Hardware assisted copy. */ + if (new_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c -index 88f9bc0..ca85da7 100644 +index 88f9bc0..23d9896 100644 --- a/drivers/gpu/drm/nouveau/nouveau_calc.c +++ b/drivers/gpu/drm/nouveau/nouveau_calc.c @@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, @@ -2405,8 +3057,34 @@ index 88f9bc0..ca85da7 100644 sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64; sim_data.mem_latency = cfg1 & 0xf; sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1); +@@ -234,7 +234,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, + } + + static void +-nv30_update_arb(int *burst, int *lwm) ++nv20_update_arb(int *burst, int *lwm) + { + unsigned int fifo_size, burst_size, graphics_lwm; + +@@ -251,14 +251,14 @@ nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- if (dev_priv->card_type < NV_30) ++ if (dev_priv->card_type < NV_20) + nv04_update_arb(dev, vclk, bpp, burst, lwm); + else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ || + (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) { + *burst = 128; + *lwm = 0x0480; + } else +- nv30_update_arb(burst, lwm); ++ nv20_update_arb(burst, lwm); + } + + static int diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c -index 1fc57ef..e952c3b 100644 +index 1fc57ef..9a31023 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -257,9 +257,7 @@ nouveau_channel_free(struct nouveau_channel *chan) @@ -2419,7 +3097,15 @@ index 1fc57ef..e952c3b 100644 if (chan->fence.sequence != chan->fence.sequence_ack) { struct nouveau_fence *fence = NULL; -@@ -368,8 +366,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, +@@ -311,6 +309,7 @@ nouveau_channel_free(struct nouveau_channel *chan) + /* Release the channel's resources */ + nouveau_gpuobj_ref_del(dev, &chan->pushbuf); + if (chan->pushbuf_bo) { ++ nouveau_bo_unmap(chan->pushbuf_bo); + nouveau_bo_unpin(chan->pushbuf_bo); + nouveau_bo_ref(NULL, &chan->pushbuf_bo); + } +@@ -368,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -2428,7 +3114,7 @@ index 1fc57ef..e952c3b 100644 if (dev_priv->engine.graph.accel_blocked) return -ENODEV; -@@ -418,7 +414,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, +@@ -418,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, struct drm_nouveau_channel_free *cfree = data; struct nouveau_channel *chan; @@ -3076,24 +3762,23 @@ index 4ef38ab..0d2e668 100644 #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c -index 65c441a..2e3c6ca 100644 +index 65c441a..2d00699 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c -@@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan) +@@ -91,13 +91,6 @@ nouveau_dma_init(struct nouveau_channel *chan) + if (ret) return ret; - /* Map M2MF notifier object - fbcon. */ +- /* Map M2MF notifier object - fbcon. */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = nouveau_bo_map(chan->notifier_bo); - if (ret) - return ret; - } -+ ret = nouveau_bo_map(chan->notifier_bo); -+ if (ret) -+ return ret; - +- /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); + if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index deeb21c..8a1b188 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -3380,7 +4065,7 @@ index 2737704..a8d3d17 100644 nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index c697191..c001574 100644 +index c697191..2eb622b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) @@ -3398,7 +4083,11 @@ index c697191..c001574 100644 enum nouveau_flags { NV_NFORCE = 0x10000000, NV_NFORCE2 = 0x20000000 -@@ -149,7 +141,7 @@ struct nouveau_gpuobj { +@@ -146,10 +138,11 @@ enum nouveau_flags { + #define NVOBJ_FLAG_ZERO_FREE (1 << 2) + #define NVOBJ_FLAG_FAKE (1 << 3) + struct nouveau_gpuobj { ++ struct drm_device *dev; struct list_head list; struct nouveau_channel *im_channel; @@ -3407,7 +4096,7 @@ index c697191..c001574 100644 struct nouveau_bo *im_backing; uint32_t im_backing_start; uint32_t *im_backing_suspend; -@@ -196,7 +188,7 @@ struct nouveau_channel { +@@ -196,7 +189,7 @@ struct nouveau_channel { struct list_head pending; uint32_t sequence; uint32_t sequence_ack; @@ -3416,7 +4105,7 @@ index c697191..c001574 100644 } fence; /* DMA push buffer */ -@@ -206,7 +198,7 @@ struct nouveau_channel { +@@ -206,7 +199,7 @@ struct nouveau_channel { /* Notifier memory */ struct nouveau_bo *notifier_bo; @@ -3425,7 +4114,7 @@ index c697191..c001574 100644 /* PFIFO context */ struct nouveau_gpuobj_ref *ramfc; -@@ -224,7 +216,7 @@ struct nouveau_channel { +@@ -224,7 +217,7 @@ struct nouveau_channel { /* Objects */ struct nouveau_gpuobj_ref *ramin; /* Private instmem */ @@ -3434,7 +4123,7 @@ index c697191..c001574 100644 struct nouveau_gpuobj_ref *ramht; /* Hash table */ struct list_head ramht_refs; /* Objects referenced by RAMHT */ -@@ -277,8 +269,7 @@ struct nouveau_instmem_engine { +@@ -277,8 +270,7 @@ struct nouveau_instmem_engine { void (*clear)(struct drm_device *, struct nouveau_gpuobj *); int (*bind)(struct drm_device *, struct nouveau_gpuobj *); int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); @@ -3444,7 +4133,7 @@ index c697191..c001574 100644 }; struct nouveau_mc_engine { -@@ -303,10 +294,11 @@ struct nouveau_fb_engine { +@@ -303,10 +295,11 @@ struct nouveau_fb_engine { }; struct nouveau_fifo_engine { @@ -3458,7 +4147,7 @@ index c697191..c001574 100644 int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); -@@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class { +@@ -339,10 +332,11 @@ struct nouveau_pgraph_object_class { struct nouveau_pgraph_engine { struct nouveau_pgraph_object_class *grclass; bool accel_blocked; @@ -3472,7 +4161,7 @@ index c697191..c001574 100644 int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); -@@ -358,6 +351,24 @@ struct nouveau_pgraph_engine { +@@ -358,6 +352,24 @@ struct nouveau_pgraph_engine { uint32_t size, uint32_t pitch); }; @@ -3497,7 +4186,7 @@ index c697191..c001574 100644 struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; -@@ -365,6 +376,8 @@ struct nouveau_engine { +@@ -365,6 +377,8 @@ struct nouveau_engine { struct nouveau_fb_engine fb; struct nouveau_pgraph_engine graph; struct nouveau_fifo_engine fifo; @@ -3506,7 +4195,7 @@ index c697191..c001574 100644 }; struct nouveau_pll_vals { -@@ -397,7 +410,7 @@ enum nv04_fp_display_regs { +@@ -397,7 +411,7 @@ enum nv04_fp_display_regs { struct nv04_crtc_reg { unsigned char MiscOutReg; /* */ @@ -3515,7 +4204,7 @@ index c697191..c001574 100644 uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; -@@ -496,15 +509,11 @@ enum nouveau_card_type { +@@ -496,15 +510,11 @@ enum nouveau_card_type { NV_30 = 0x30, NV_40 = 0x40, NV_50 = 0x50, @@ -3532,7 +4221,7 @@ index c697191..c001574 100644 /* the card type, takes NV_* as values */ enum nouveau_card_type card_type; -@@ -528,13 +537,9 @@ struct drm_nouveau_private { +@@ -528,13 +538,9 @@ struct drm_nouveau_private { struct ttm_global_reference mem_global_ref; struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_device bdev; @@ -3546,7 +4235,15 @@ index c697191..c001574 100644 int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; -@@ -595,11 +600,7 @@ struct drm_nouveau_private { +@@ -579,6 +585,7 @@ struct drm_nouveau_private { + /* VRAM/fb configuration */ + uint64_t vram_size; + uint64_t vram_sys_base; ++ u32 vram_rblock_size; + + uint64_t fb_phys; + uint64_t fb_available_size; +@@ -595,11 +602,7 @@ struct drm_nouveau_private { struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; @@ -3559,7 +4256,7 @@ index c697191..c001574 100644 struct list_head gpuobj_list; -@@ -618,6 +619,11 @@ struct drm_nouveau_private { +@@ -618,6 +621,11 @@ struct drm_nouveau_private { struct backlight_device *backlight; struct nouveau_channel *evo; @@ -3571,7 +4268,7 @@ index c697191..c001574 100644 struct { struct dentry *channel_root; -@@ -652,14 +658,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) +@@ -652,14 +660,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) return 0; } @@ -3586,7 +4283,7 @@ index c697191..c001574 100644 #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (!nouveau_channel_owner(dev, (cl), (id))) { \ -@@ -682,7 +680,6 @@ extern int nouveau_tv_disable; +@@ -682,7 +682,6 @@ extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; @@ -3594,7 +4291,7 @@ index c697191..c001574 100644 extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; -@@ -707,17 +704,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); +@@ -707,17 +706,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ @@ -3613,7 +4310,7 @@ index c697191..c001574 100644 extern void nouveau_mem_close(struct drm_device *); extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, -@@ -857,11 +847,13 @@ void nouveau_register_dsm_handler(void); +@@ -857,11 +849,13 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); @@ -3627,7 +4324,7 @@ index c697191..c001574 100644 #endif /* nouveau_backlight.c */ -@@ -924,6 +916,10 @@ extern void nv10_fb_takedown(struct drm_device *); +@@ -924,15 +918,23 @@ extern void nv10_fb_takedown(struct drm_device *); extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); @@ -3638,18 +4335,21 @@ index c697191..c001574 100644 /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); -@@ -934,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, + extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); +- + /* nv50_fb.c */ extern int nv50_fb_init(struct drm_device *); extern void nv50_fb_takedown(struct drm_device *); - ++extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *); ++ +/* nvc0_fb.c */ +extern int nvc0_fb_init(struct drm_device *); +extern void nvc0_fb_takedown(struct drm_device *); -+ + /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); - extern void nv04_fifo_disable(struct drm_device *); -@@ -971,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); +@@ -971,6 +973,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); @@ -3670,7 +4370,7 @@ index c697191..c001574 100644 /* nv04_graph.c */ extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern int nv04_graph_init(struct drm_device *); -@@ -1035,11 +1049,15 @@ extern int nv50_graph_unload_context(struct drm_device *); +@@ -1035,11 +1051,15 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); @@ -3691,7 +4391,7 @@ index c697191..c001574 100644 /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); -@@ -1051,8 +1069,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1051,8 +1071,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -3701,7 +4401,7 @@ index c697191..c001574 100644 /* nv50_instmem.c */ extern int nv50_instmem_init(struct drm_device *); -@@ -1064,8 +1081,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1064,8 +1083,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -3725,7 +4425,7 @@ index c697191..c001574 100644 /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); -@@ -1088,13 +1118,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, +@@ -1088,13 +1120,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nv04_dac.c */ @@ -3742,7 +4442,7 @@ index c697191..c001574 100644 extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, int head, bool dl); -@@ -1103,15 +1134,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); +@@ -1103,15 +1136,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); /* nv04_tv.c */ extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); @@ -3763,7 +4463,7 @@ index c697191..c001574 100644 /* nv04_crtc.c */ extern int nv04_crtc_create(struct drm_device *, int index); -@@ -1147,7 +1180,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); +@@ -1147,7 +1182,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); extern int nouveau_fence_flush(void *obj, void *arg); extern void nouveau_fence_unref(void **obj); extern void *nouveau_fence_ref(void *obj); @@ -3771,7 +4471,7 @@ index c697191..c001574 100644 /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, -@@ -1167,13 +1199,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, +@@ -1167,13 +1201,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); @@ -3790,21 +4490,56 @@ index c697191..c001574 100644 /* nv50_calc. */ int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, -@@ -1220,6 +1254,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) +@@ -1220,6 +1256,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) iowrite32_native(val, dev_priv->mmio + reg); } -+static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val) ++static inline u32 nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val) +{ + u32 tmp = nv_rd32(dev, reg); -+ tmp &= ~mask; -+ tmp |= val; -+ nv_wr32(dev, reg, tmp); ++ nv_wr32(dev, reg, (tmp & ~mask) | val); ++ return tmp; +} + static inline u8 nv_rd08(struct drm_device *dev, unsigned reg) { struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -1249,17 +1292,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val) + } + + /* object access */ +-static inline u32 nv_ro32(struct drm_device *dev, struct nouveau_gpuobj *obj, +- unsigned index) +-{ +- return nv_ri32(dev, obj->im_pramin->start + index * 4); +-} +- +-static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj, +- unsigned index, u32 val) +-{ +- nv_wi32(dev, obj->im_pramin->start + index * 4, val); +-} ++extern u32 nv_ro32(struct nouveau_gpuobj *, u32 offset); ++extern void nv_wo32(struct nouveau_gpuobj *, u32 offset, u32 val); + + /* + * Logging +@@ -1346,6 +1380,15 @@ nv_two_reg_pll(struct drm_device *dev) + return false; + } + ++static inline bool ++nv_match_device(struct drm_device *dev, unsigned device, ++ unsigned sub_vendor, unsigned sub_device) ++{ ++ return dev->pdev->device == device && ++ dev->pdev->subsystem_vendor == sub_vendor && ++ dev->pdev->subsystem_device == sub_device; ++} ++ + #define NV_SW 0x0000506e + #define NV_SW_DMA_SEMAPHORE 0x00000060 + #define NV_SW_SEMAPHORE_OFFSET 0x00000064 diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index e1df820..7c82d68 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -3988,7 +4723,7 @@ index faddf53..6b208ff 100644 } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c -index 69c76cf..547f2c2 100644 +index 69c76cf..62ac673 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, @@ -4012,6 +4747,24 @@ index 69c76cf..547f2c2 100644 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); req->vram_available = dev_priv->fb_aper_free; +@@ -650,7 +647,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, + push[i].length); + } + } else +- if (dev_priv->card_type >= NV_20) { ++ if (dev_priv->chipset >= 0x25) { + ret = RING_SPACE(chan, req->nr_push * 2); + if (ret) { + NV_ERROR(dev, "cal_space: %d\n", ret); +@@ -725,7 +722,7 @@ out_next: + req->suffix0 = 0x00000000; + req->suffix1 = 0x00000000; + } else +- if (dev_priv->card_type >= NV_20) { ++ if (dev_priv->chipset >= 0x25) { + req->suffix0 = 0x00020000; + req->suffix1 = 0x00000000; + } else { @@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); int ret = -EINVAL; @@ -4205,37 +4958,53 @@ index f731c5f..0000000 - nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset), - le32_to_cpu(cv->data[i].value)); -} +diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h +index 5d39c4c..4a8ad13 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_grctx.h ++++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h +@@ -126,7 +126,7 @@ gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val) + reg = (reg - 0x00400000) / 4; + reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base; + +- nv_wo32(ctx->dev, ctx->data, reg, val); ++ nv_wo32(ctx->data, reg * 4, val); + } + #endif + diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c -index 7855b35..7b61368 100644 +index 7855b35..f8ec49b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c -@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head, +@@ -865,8 +865,13 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_21); - if (dev_priv->card_type >= NV_30) + -+ if (dev_priv->card_type >= NV_30) { ++ if (dev_priv->card_type >= NV_20) rd_cio_state(dev, head, regp, NV_CIO_CRE_47); ++ ++ if (dev_priv->card_type >= NV_30) + rd_cio_state(dev, head, regp, 0x9f); -+ } + rd_cio_state(dev, head, regp, NV_CIO_CRE_49); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); -@@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head, +@@ -971,9 +976,13 @@ nv_load_state_ext(struct drm_device *dev, int head, wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); - if (dev_priv->card_type >= NV_30) + -+ if (dev_priv->card_type >= NV_30) { ++ if (dev_priv->card_type >= NV_20) wr_cio_state(dev, head, regp, NV_CIO_CRE_47); -+ wr_cio_state(dev, head, regp, 0x9f); -+ } ++ if (dev_priv->card_type >= NV_30) ++ wr_cio_state(dev, head, regp, 0x9f); ++ wr_cio_state(dev, head, regp, NV_CIO_CRE_49); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); + wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 316a3c7..8461485 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -4388,7 +5157,7 @@ index c8eaf7a..f71cb32 100644 #endif /* __NOUVEAU_I2C_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c -index 53360f1..794b0ee 100644 +index 53360f1..b8658a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev) @@ -4400,7 +5169,22 @@ index 53360f1..794b0ee 100644 INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); INIT_LIST_HEAD(&dev_priv->vbl_waiting); -@@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) +@@ -226,6 +226,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev) + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + } + ++ if (dev_priv->card_type == NV_50) { ++ if (status & 0x00000010) { ++ nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); ++ status &= ~0x00000010; ++ nv_wr32(dev, 0x002100, 0x00000010); ++ } ++ } ++ + if (status) { + NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", + status, chid); +@@ -586,11 +594,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) } if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { @@ -4414,8 +5198,140 @@ index 53360f1..794b0ee 100644 } if (status) { +@@ -605,40 +613,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) + nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); + } + +-static void +-nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t trap[6]; +- int i, ch; +- uint32_t idx = nv_rd32(dev, 0x100c90); +- if (idx & 0x80000000) { +- idx &= 0xffffff; +- if (display) { +- for (i = 0; i < 6; i++) { +- nv_wr32(dev, 0x100c90, idx | i << 24); +- trap[i] = nv_rd32(dev, 0x100c94); +- } +- for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { +- struct nouveau_channel *chan = dev_priv->fifos[ch]; +- +- if (!chan || !chan->ramin) +- continue; +- +- if (trap[1] == chan->ramin->instance >> 12) +- break; +- } +- NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n", +- name, (trap[5]&0x100?"read":"write"), +- trap[5]&0xff, trap[4]&0xffff, +- trap[3]&0xffff, trap[0], trap[2], ch); +- } +- nv_wr32(dev, 0x100c90, idx | 0x80000000); +- } else if (display) { +- NV_INFO(dev, "%s - no VM fault?\n", name); +- } +-} +- + static struct nouveau_enum_names nv50_mp_exec_error_names[] = + { + { 3, "STACK_UNDERFLOW" }, +@@ -711,7 +685,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, + tps++; + switch (type) { + case 6: /* texture error... unknown for now */ +- nv50_pfb_vm_trap(dev, display, name); ++ nv50_fb_vm_trap(dev, display, name); + if (display) { + NV_ERROR(dev, "magic set %d:\n", i); + for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) +@@ -734,7 +708,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, + uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); + uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); + uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); +- nv50_pfb_vm_trap(dev, display, name); ++ nv50_fb_vm_trap(dev, display, name); + /* 2d engine destination */ + if (ustatus & 0x00000010) { + if (display) { +@@ -817,7 +791,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + + /* Known to be triggered by screwed up NOTIFY and COND... */ + if (ustatus & 0x00000001) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT"); + nv_wr32(dev, 0x400500, 0); + if (nv_rd32(dev, 0x400808) & 0x80000000) { + if (display) { +@@ -842,7 +816,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + ustatus &= ~0x00000001; + } + if (ustatus & 0x00000002) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY"); + nv_wr32(dev, 0x400500, 0); + if (nv_rd32(dev, 0x40084c) & 0x80000000) { + if (display) { +@@ -884,15 +858,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n"); + } + if (ustatus & 0x00000001) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY"); + ustatus &= ~0x00000001; + } + if (ustatus & 0x00000002) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN"); + ustatus &= ~0x00000002; + } + if (ustatus & 0x00000004) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT"); + ustatus &= ~0x00000004; + } + NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n", +@@ -917,7 +891,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n"); + } + if (ustatus & 0x00000001) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n", + nv_rd32(dev, 0x400c00), + nv_rd32(dev, 0x400c08), +@@ -939,7 +913,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n"); + } + if (ustatus & 0x00000001) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n", + nv_rd32(dev, 0x401804), + nv_rd32(dev, 0x401808), +@@ -964,7 +938,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n"); + } + if (ustatus & 0x00000001) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n", + nv_rd32(dev, 0x405800), + nv_rd32(dev, 0x405804), +@@ -986,7 +960,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) + * remaining, so try to handle it anyway. Perhaps related to that + * unknown DMA slot on tesla? */ + if (status & 0x20) { +- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04"); ++ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04"); + ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; + if (display) + NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c -index c1fd42b..db442c1 100644 +index c1fd42b..ee799c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -35,162 +35,6 @@ @@ -4589,7 +5505,15 @@ index c1fd42b..db442c1 100644 while (size) { unsigned offset_h = upper_32_bits(phys); unsigned offset_l = lower_32_bits(phys); -@@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, +@@ -326,41 +169,18 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, + virt += (end - pte); + + while (pte < end) { +- nv_wo32(dev, pgt, pte++, offset_l); +- nv_wo32(dev, pgt, pte++, offset_h); ++ nv_wo32(pgt, (pte * 4) + 0, offset_l); ++ nv_wo32(pgt, (pte * 4) + 4, offset_h); ++ pte += 2; } } } @@ -4631,7 +5555,7 @@ index c1fd42b..db442c1 100644 return 0; } -@@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) +@@ -374,7 +194,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) virt -= dev_priv->vm_vram_base; pages = (size >> 16) << 1; @@ -4639,10 +5563,13 @@ index c1fd42b..db442c1 100644 while (pages) { pgt = dev_priv->vm_vram_pt[virt >> 29]; pte = (virt & 0x1ffe0000ULL) >> 15; -@@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) - while (pte < end) - nv_wo32(dev, pgt, pte++, 0); - } +@@ -385,60 +204,24 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) + pages -= (end - pte); + virt += (end - pte) << 15; + +- while (pte < end) +- nv_wo32(dev, pgt, pte++, 0); +- } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, 0x100c80, 0x00050001); @@ -4664,7 +5591,11 @@ index c1fd42b..db442c1 100644 - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return; -- } ++ while (pte < end) { ++ nv_wo32(pgt, (pte * 4), 0); ++ pte++; ++ } + } + dev_priv->engine.instmem.flush(dev); - nv_wr32(dev, 0x100c80, 0x00060001); @@ -4704,7 +5635,7 @@ index c1fd42b..db442c1 100644 { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev) +@@ -449,8 +232,7 @@ void nouveau_mem_close(struct drm_device *dev) nouveau_ttm_global_release(dev_priv); @@ -4714,7 +5645,7 @@ index c1fd42b..db442c1 100644 struct drm_agp_mem *entry, *tempe; /* Remove AGP resources, but leave dev->agp -@@ -470,29 +249,29 @@ void nouveau_mem_close(struct drm_device *dev) +@@ -470,29 +252,29 @@ void nouveau_mem_close(struct drm_device *dev) dev->agp->enabled = 0; } @@ -4752,7 +5683,70 @@ index c1fd42b..db442c1 100644 return 4 * 1024 * 1024; } -@@ -536,12 +315,22 @@ nouveau_mem_detect(struct drm_device *dev) +@@ -525,7 +307,61 @@ nouveau_mem_detect_nforce(struct drm_device *dev) + return 0; + } + +-/* returns the amount of FB ram in bytes */ ++static void ++nv50_vram_preinit(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int i, parts, colbits, rowbitsa, rowbitsb, banks; ++ u64 rowsize, predicted; ++ u32 r0, r4, rt, ru; ++ ++ r0 = nv_rd32(dev, 0x100200); ++ r4 = nv_rd32(dev, 0x100204); ++ rt = nv_rd32(dev, 0x100250); ++ ru = nv_rd32(dev, 0x001540); ++ NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); ++ ++ for (i = 0, parts = 0; i < 8; i++) { ++ if (ru & (0x00010000 << i)) ++ parts++; ++ } ++ ++ colbits = (r4 & 0x0000f000) >> 12; ++ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; ++ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; ++ banks = ((r4 & 0x01000000) ? 8 : 4); ++ ++ rowsize = parts * banks * (1 << colbits) * 8; ++ predicted = rowsize << rowbitsa; ++ if (r0 & 0x00000004) ++ predicted += rowsize << rowbitsb; ++ ++ if (predicted != dev_priv->vram_size) { ++ NV_WARN(dev, "memory controller reports %dMiB VRAM\n", ++ (u32)(dev_priv->vram_size >> 20)); ++ NV_WARN(dev, "we calculated %dMiB VRAM\n", ++ (u32)(predicted >> 20)); ++ } ++ ++ dev_priv->vram_rblock_size = rowsize >> 12; ++ if (rt & 1) ++ dev_priv->vram_rblock_size *= 3; ++ ++ NV_DEBUG(dev, "rblock %lld bytes\n", ++ (u64)dev_priv->vram_rblock_size << 12); ++} ++ ++static void ++nvaa_vram_preinit(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ /* To our knowledge, there's no large scale reordering of pages ++ * that occurs on IGP chipsets. ++ */ ++ dev_priv->vram_rblock_size = 1; ++} ++ + int + nouveau_mem_detect(struct drm_device *dev) + { +@@ -536,12 +372,31 @@ nouveau_mem_detect(struct drm_device *dev) } else if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { dev_priv->vram_size = nouveau_mem_detect_nforce(dev); @@ -4769,9 +5763,18 @@ index c1fd42b..db442c1 100644 + dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); + dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; + dev_priv->vram_size &= 0xffffffff00ll; -+ if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { ++ ++ switch (dev_priv->chipset) { ++ case 0xaa: ++ case 0xac: ++ case 0xaf: dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); dev_priv->vram_sys_base <<= 12; ++ nvaa_vram_preinit(dev); ++ break; ++ default: ++ nv50_vram_preinit(dev); ++ break; + } + } else { + dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; @@ -4779,7 +5782,7 @@ index c1fd42b..db442c1 100644 } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -@@ -555,18 +344,36 @@ nouveau_mem_detect(struct drm_device *dev) +@@ -555,18 +410,37 @@ nouveau_mem_detect(struct drm_device *dev) return -ENOMEM; } @@ -4796,7 +5799,8 @@ index c1fd42b..db442c1 100644 + /* First of all, disable fast writes, otherwise if it's + * already enabled in the AGP bridge and we disable the card's + * AGP controller we might be locking ourselves out of it. */ -+ if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) { ++ if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) | ++ dev->agp->mode) & PCI_AGP_COMMAND_FW) { + struct drm_agp_info info; + struct drm_agp_mode mode; + @@ -4822,7 +5826,7 @@ index c1fd42b..db442c1 100644 /* power cycle pgraph, if enabled */ pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); -@@ -578,11 +385,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) +@@ -578,11 +452,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) } /* and restore (gives effect of resetting AGP) */ @@ -4837,7 +5841,7 @@ index c1fd42b..db442c1 100644 int nouveau_mem_init_agp(struct drm_device *dev) { -@@ -592,11 +400,6 @@ nouveau_mem_init_agp(struct drm_device *dev) +@@ -592,11 +467,6 @@ nouveau_mem_init_agp(struct drm_device *dev) struct drm_agp_mode mode; int ret; @@ -4849,7 +5853,7 @@ index c1fd42b..db442c1 100644 if (!dev->agp->acquired) { ret = drm_agp_acquire(dev); if (ret) { -@@ -605,6 +408,8 @@ nouveau_mem_init_agp(struct drm_device *dev) +@@ -605,6 +475,8 @@ nouveau_mem_init_agp(struct drm_device *dev) } } @@ -4858,7 +5862,7 @@ index c1fd42b..db442c1 100644 ret = drm_agp_info(dev, &info); if (ret) { NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); -@@ -659,8 +464,6 @@ nouveau_mem_init(struct drm_device *dev) +@@ -659,8 +531,6 @@ nouveau_mem_init(struct drm_device *dev) return ret; } @@ -4867,7 +5871,7 @@ index c1fd42b..db442c1 100644 spin_lock_init(&dev_priv->tile.lock); dev_priv->fb_available_size = dev_priv->vram_size; -@@ -692,7 +495,7 @@ nouveau_mem_init(struct drm_device *dev) +@@ -692,7 +562,7 @@ nouveau_mem_init(struct drm_device *dev) /* GART */ #if !defined(__powerpc__) && !defined(__ia64__) @@ -4970,60 +5974,160 @@ index 9537f3e..3ec181f 100644 ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c -index e7c100b..4bf6b33 100644 +index e7c100b..6aedc3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c -@@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - } - } +@@ -34,6 +34,7 @@ + #include "drm.h" + #include "nouveau_drv.h" + #include "nouveau_drm.h" ++#include "nouveau_ramht.h" + /* NVidia uses context objects to drive drawing operations. + +@@ -65,141 +66,6 @@ + The key into the hash table depends on the object handle and channel id and + is given as: + */ +-static uint32_t +-nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t hash = 0; +- int i; +- +- NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle); +- +- for (i = 32; i > 0; i -= dev_priv->ramht_bits) { +- hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); +- handle >>= dev_priv->ramht_bits; +- } +- +- if (dev_priv->card_type < NV_50) +- hash ^= channel << (dev_priv->ramht_bits - 4); +- hash <<= 3; +- +- NV_DEBUG(dev, "hash=0x%08x\n", hash); +- return hash; +-} +- +-static int +-nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, +- uint32_t offset) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t ctx = nv_ro32(dev, ramht, (offset + 4)/4); +- +- if (dev_priv->card_type < NV_40) +- return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); +- return (ctx != 0); +-} +- +-static int +-nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; +- struct nouveau_channel *chan = ref->channel; +- struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; +- uint32_t ctx, co, ho; +- +- if (!ramht) { +- NV_ERROR(dev, "No hash table!\n"); +- return -EINVAL; +- } +- +- if (dev_priv->card_type < NV_40) { +- ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | +- (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | +- (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); +- } else +- if (dev_priv->card_type < NV_50) { +- ctx = (ref->instance >> 4) | +- (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | +- (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); +- } else { +- if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { +- ctx = (ref->instance << 10) | 2; +- } else { +- ctx = (ref->instance >> 4) | +- ((ref->gpuobj->engine << +- NV40_RAMHT_CONTEXT_ENGINE_SHIFT)); +- } +- } +- - instmem->prepare_access(dev, true); - co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); - do { - if (!nouveau_ramht_entry_valid(dev, ramht, co)) { -@@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - nv_wo32(dev, ramht, (co + 4)/4, ctx); - - list_add_tail(&ref->list, &chan->ramht_refs); +- co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); +- do { +- if (!nouveau_ramht_entry_valid(dev, ramht, co)) { +- NV_DEBUG(dev, +- "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", +- chan->id, co, ref->handle, ctx); +- nv_wo32(dev, ramht, (co + 0)/4, ref->handle); +- nv_wo32(dev, ramht, (co + 4)/4, ctx); +- +- list_add_tail(&ref->list, &chan->ramht_refs); - instmem->finish_access(dev); -+ instmem->flush(dev); - return 0; - } - NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n", -@@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - if (co >= dev_priv->ramht_size) - co = 0; - } while (co != ho); +- return 0; +- } +- NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n", +- chan->id, co, nv_ro32(dev, ramht, co/4)); +- +- co += 8; +- if (co >= dev_priv->ramht_size) +- co = 0; +- } while (co != ho); - instmem->finish_access(dev); - - NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); - return -ENOMEM; -@@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - return; - } - +- +- NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); +- return -ENOMEM; +-} +- +-static void +-nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; +- struct nouveau_channel *chan = ref->channel; +- struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; +- uint32_t co, ho; +- +- if (!ramht) { +- NV_ERROR(dev, "No hash table!\n"); +- return; +- } +- - instmem->prepare_access(dev, true); - co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); - do { - if (nouveau_ramht_entry_valid(dev, ramht, co) && -@@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - nv_wo32(dev, ramht, (co + 4)/4, 0x00000000); - - list_del(&ref->list); +- co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); +- do { +- if (nouveau_ramht_entry_valid(dev, ramht, co) && +- (ref->handle == nv_ro32(dev, ramht, (co/4)))) { +- NV_DEBUG(dev, +- "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", +- chan->id, co, ref->handle, +- nv_ro32(dev, ramht, (co + 4))); +- nv_wo32(dev, ramht, (co + 0)/4, 0x00000000); +- nv_wo32(dev, ramht, (co + 4)/4, 0x00000000); +- +- list_del(&ref->list); - instmem->finish_access(dev); -+ instmem->flush(dev); - return; - } - -@@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) - co = 0; - } while (co != ho); - list_del(&ref->list); +- return; +- } +- +- co += 8; +- if (co >= dev_priv->ramht_size) +- co = 0; +- } while (co != ho); +- list_del(&ref->list); - instmem->finish_access(dev); +- +- NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", +- chan->id, ref->handle); +-} - NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", - chan->id, ref->handle); -@@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + int + nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -209,7 +75,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; struct nouveau_gpuobj *gpuobj; @@ -5032,7 +6136,15 @@ index e7c100b..4bf6b33 100644 int ret; NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", -@@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -222,6 +88,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + if (!gpuobj) + return -ENOMEM; + NV_DEBUG(dev, "gpuobj %p\n", gpuobj); ++ gpuobj->dev = dev; + gpuobj->flags = flags; + gpuobj->im_channel = chan; + +@@ -233,25 +100,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, * available. */ if (chan) { @@ -5050,18 +6162,18 @@ index e7c100b..4bf6b33 100644 NV_DEBUG(dev, "global heap\n"); - pramin = dev_priv->ramin_heap; - } -- ++ pramin = &dev_priv->ramin_heap; + - if (!pramin) { - NV_ERROR(dev, "No PRAMIN heap!\n"); - return -EINVAL; - } -+ pramin = &dev_priv->ramin_heap; - +- - if (!chan) { ret = engine->instmem.populate(dev, gpuobj, &size); if (ret) { nouveau_gpuobj_del(dev, &gpuobj); -@@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -260,9 +114,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, } /* Allocate a chunk of the PRAMIN aperture */ @@ -5075,31 +6187,33 @@ index e7c100b..4bf6b33 100644 if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; -@@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -279,10 +134,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { int i; - engine->instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); +- nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); ++ nv_wo32(gpuobj, i, 0); + engine->instmem.flush(dev); } *gpuobj_ret = gpuobj; -@@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) +@@ -370,10 +224,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) } if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { - engine->instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); +- nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); ++ nv_wo32(gpuobj, i, 0); + engine->instmem.flush(dev); } if (gpuobj->dtor) -@@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) +@@ -386,7 +239,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) if (gpuobj->flags & NVOBJ_FLAG_FAKE) kfree(gpuobj->im_pramin); else @@ -5108,7 +6222,14 @@ index e7c100b..4bf6b33 100644 } list_del(&gpuobj->list); -@@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, +@@ -583,13 +436,14 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, + if (!gpuobj) + return -ENOMEM; + NV_DEBUG(dev, "gpuobj %p\n", gpuobj); ++ gpuobj->dev = dev; + gpuobj->im_channel = NULL; + gpuobj->flags = flags | NVOBJ_FLAG_FAKE; + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); if (p_offset != ~0) { @@ -5117,19 +6238,20 @@ index e7c100b..4bf6b33 100644 GFP_KERNEL); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); -@@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, +@@ -605,10 +459,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, } if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); +- nv_wo32(dev, gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(gpuobj, i, 0); + dev_priv->engine.instmem.flush(dev); } if (pref) { -@@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, +@@ -696,8 +549,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, return ret; } @@ -5138,8 +6260,43 @@ index e7c100b..4bf6b33 100644 if (dev_priv->card_type < NV_50) { uint32_t frame, adjust, pte_flags = 0; -@@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, - nv_wo32(dev, *gpuobj, 5, flags5); +@@ -706,14 +557,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, + adjust = offset & 0x00000fff; + frame = offset & ~0x00000fff; + +- nv_wo32(dev, *gpuobj, 0, ((1<<12) | (1<<13) | +- (adjust << 20) | +- (access << 14) | +- (target << 16) | +- class)); +- nv_wo32(dev, *gpuobj, 1, size - 1); +- nv_wo32(dev, *gpuobj, 2, frame | pte_flags); +- nv_wo32(dev, *gpuobj, 3, frame | pte_flags); ++ nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) | ++ (access << 14) | (target << 16) | ++ class)); ++ nv_wo32(*gpuobj, 4, size - 1); ++ nv_wo32(*gpuobj, 8, frame | pte_flags); ++ nv_wo32(*gpuobj, 12, frame | pte_flags); + } else { + uint64_t limit = offset + size - 1; + uint32_t flags0, flags5; +@@ -726,15 +575,15 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, + flags5 = 0x00080000; + } + +- nv_wo32(dev, *gpuobj, 0, flags0 | class); +- nv_wo32(dev, *gpuobj, 1, lower_32_bits(limit)); +- nv_wo32(dev, *gpuobj, 2, lower_32_bits(offset)); +- nv_wo32(dev, *gpuobj, 3, ((upper_32_bits(limit) & 0xff) << 24) | +- (upper_32_bits(offset) & 0xff)); +- nv_wo32(dev, *gpuobj, 5, flags5); ++ nv_wo32(*gpuobj, 0, flags0 | class); ++ nv_wo32(*gpuobj, 4, lower_32_bits(limit)); ++ nv_wo32(*gpuobj, 8, lower_32_bits(offset)); ++ nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) | ++ (upper_32_bits(offset) & 0xff)); ++ nv_wo32(*gpuobj, 20, flags5); } - instmem->finish_access(dev); @@ -5147,15 +6304,40 @@ index e7c100b..4bf6b33 100644 (*gpuobj)->engine = NVOBJ_ENGINE_SW; (*gpuobj)->class = class; -@@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, +@@ -849,32 +698,31 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return ret; } - dev_priv->engine.instmem.prepare_access(dev, true); if (dev_priv->card_type >= NV_50) { - nv_wo32(dev, *gpuobj, 0, class); - nv_wo32(dev, *gpuobj, 5, 0x00010000); -@@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, +- nv_wo32(dev, *gpuobj, 0, class); +- nv_wo32(dev, *gpuobj, 5, 0x00010000); ++ nv_wo32(*gpuobj, 0, class); ++ nv_wo32(*gpuobj, 20, 0x00010000); + } else { + switch (class) { + case NV_CLASS_NULL: +- nv_wo32(dev, *gpuobj, 0, 0x00001030); +- nv_wo32(dev, *gpuobj, 1, 0xFFFFFFFF); ++ nv_wo32(*gpuobj, 0, 0x00001030); ++ nv_wo32(*gpuobj, 4, 0xFFFFFFFF); + break; + default: + if (dev_priv->card_type >= NV_40) { +- nv_wo32(dev, *gpuobj, 0, class); ++ nv_wo32(*gpuobj, 0, class); + #ifdef __BIG_ENDIAN +- nv_wo32(dev, *gpuobj, 2, 0x01000000); ++ nv_wo32(*gpuobj, 8, 0x01000000); + #endif + } else { + #ifdef __BIG_ENDIAN +- nv_wo32(dev, *gpuobj, 0, class | 0x00080000); ++ nv_wo32(*gpuobj, 0, class | 0x00080000); + #else +- nv_wo32(dev, *gpuobj, 0, class); ++ nv_wo32(*gpuobj, 0, class); + #endif } } } @@ -5164,7 +6346,7 @@ index e7c100b..4bf6b33 100644 (*gpuobj)->engine = NVOBJ_ENGINE_GR; (*gpuobj)->class = class; -@@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) +@@ -920,6 +768,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) base = 0; /* PGRAPH context */ @@ -5172,7 +6354,7 @@ index e7c100b..4bf6b33 100644 if (dev_priv->card_type == NV_50) { /* Various fixed table thingos */ -@@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) +@@ -930,12 +779,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) size += 0x8000; /* RAMFC */ size += 0x1000; @@ -5185,7 +6367,7 @@ index e7c100b..4bf6b33 100644 ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, &chan->ramin); if (ret) { -@@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) +@@ -944,8 +789,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) } pramin = chan->ramin->gpuobj; @@ -5195,7 +6377,7 @@ index e7c100b..4bf6b33 100644 if (ret) { NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret); nouveau_gpuobj_ref_del(dev, &chan->ramin); -@@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +@@ -969,15 +813,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); @@ -5216,7 +6398,7 @@ index e7c100b..4bf6b33 100644 } /* NV50 VM -@@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +@@ -988,50 +828,42 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, if (dev_priv->card_type >= NV_50) { uint32_t vm_offset, pde; @@ -5233,9 +6415,14 @@ index e7c100b..4bf6b33 100644 return ret; - } for (i = 0; i < 0x4000; i += 8) { - nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000); - nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe); -@@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +- nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000); +- nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe); ++ nv_wo32(chan->vm_pd, i + 0, 0x00000000); ++ nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); + } + +- pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2; ++ pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8; ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->gart_info.sg_ctxdma, &chan->vm_gart_pt); @@ -5244,10 +6431,15 @@ index e7c100b..4bf6b33 100644 + if (ret) return ret; - } - nv_wo32(dev, chan->vm_pd, pde++, - chan->vm_gart_pt->instance | 0x03); - nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); -@@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +- nv_wo32(dev, chan->vm_pd, pde++, +- chan->vm_gart_pt->instance | 0x03); +- nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); ++ nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->instance | 3); ++ nv_wo32(chan->vm_pd, pde + 4, 0x00000000); + +- pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2; ++ pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8; + for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->vm_vram_pt[i], &chan->vm_vram_pt[i]); @@ -5257,9 +6449,13 @@ index e7c100b..4bf6b33 100644 return ret; - } - nv_wo32(dev, chan->vm_pd, pde++, - chan->vm_vram_pt[i]->instance | 0x61); - nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); +- nv_wo32(dev, chan->vm_pd, pde++, +- chan->vm_vram_pt[i]->instance | 0x61); +- nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); ++ nv_wo32(chan->vm_pd, pde + 0, ++ chan->vm_vram_pt[i]->instance | 0x61); ++ nv_wo32(chan->vm_pd, pde + 4, 0x00000000); ++ pde += 8; } - instmem->finish_access(dev); @@ -5267,7 +6463,7 @@ index e7c100b..4bf6b33 100644 } /* RAMHT */ -@@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) +@@ -1130,8 +962,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); @@ -5278,30 +6474,34 @@ index e7c100b..4bf6b33 100644 if (chan->ramin) nouveau_gpuobj_ref_del(dev, &chan->ramin); -@@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev) +@@ -1164,10 +996,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev) return -ENOMEM; } - dev_priv->engine.instmem.prepare_access(dev, false); - for (i = 0; i < gpuobj->im_pramin->size / 4; i++) - gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i); +- for (i = 0; i < gpuobj->im_pramin->size / 4; i++) +- gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i); - dev_priv->engine.instmem.finish_access(dev); ++ for (i = 0; i < gpuobj->im_pramin->size; i += 4) ++ gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i); } return 0; -@@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) +@@ -1212,10 +1042,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) if (!gpuobj->im_backing_suspend) continue; - dev_priv->engine.instmem.prepare_access(dev, true); - for (i = 0; i < gpuobj->im_pramin->size / 4; i++) - nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]); +- for (i = 0; i < gpuobj->im_pramin->size / 4; i++) +- nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]); - dev_priv->engine.instmem.finish_access(dev); ++ for (i = 0; i < gpuobj->im_pramin->size; i += 4) ++ nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]); + dev_priv->engine.instmem.flush(dev); } nouveau_gpuobj_suspend_cleanup(dev); -@@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, +@@ -1232,7 +1061,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -5309,7 +6509,7 @@ index e7c100b..4bf6b33 100644 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); if (init->handle == ~0) -@@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, +@@ -1283,7 +1111,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -5317,6 +6517,227 @@ index e7c100b..4bf6b33 100644 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); +@@ -1293,3 +1120,17 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, + + return 0; + } ++ ++u32 ++nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) ++{ ++ struct drm_device *dev = gpuobj->dev; ++ return nv_ri32(dev, gpuobj->im_pramin->start + offset); ++} ++ ++void ++nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) ++{ ++ struct drm_device *dev = gpuobj->dev; ++ nv_wi32(dev, gpuobj->im_pramin->start + offset, val); ++} +diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c +new file mode 100644 +index 0000000..e5cc93c +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c +@@ -0,0 +1,160 @@ ++/* ++ * Copyright 2010 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 "drmP.h" ++ ++#include "nouveau_drv.h" ++#include "nouveau_ramht.h" ++ ++static uint32_t ++nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t hash = 0; ++ int i; ++ ++ NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle); ++ ++ for (i = 32; i > 0; i -= dev_priv->ramht_bits) { ++ hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); ++ handle >>= dev_priv->ramht_bits; ++ } ++ ++ if (dev_priv->card_type < NV_50) ++ hash ^= channel << (dev_priv->ramht_bits - 4); ++ hash <<= 3; ++ ++ NV_DEBUG(dev, "hash=0x%08x\n", hash); ++ return hash; ++} ++ ++static int ++nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, ++ uint32_t offset) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t ctx = nv_ro32(ramht, offset + 4); ++ ++ if (dev_priv->card_type < NV_40) ++ return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); ++ return (ctx != 0); ++} ++ ++int ++nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; ++ struct nouveau_channel *chan = ref->channel; ++ struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; ++ uint32_t ctx, co, ho; ++ ++ if (!ramht) { ++ NV_ERROR(dev, "No hash table!\n"); ++ return -EINVAL; ++ } ++ ++ if (dev_priv->card_type < NV_40) { ++ ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | ++ (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | ++ (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); ++ } else ++ if (dev_priv->card_type < NV_50) { ++ ctx = (ref->instance >> 4) | ++ (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | ++ (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); ++ } else { ++ if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { ++ ctx = (ref->instance << 10) | 2; ++ } else { ++ ctx = (ref->instance >> 4) | ++ ((ref->gpuobj->engine << ++ NV40_RAMHT_CONTEXT_ENGINE_SHIFT)); ++ } ++ } ++ ++ co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); ++ do { ++ if (!nouveau_ramht_entry_valid(dev, ramht, co)) { ++ NV_DEBUG(dev, ++ "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", ++ chan->id, co, ref->handle, ctx); ++ nv_wo32(ramht, co + 0, ref->handle); ++ nv_wo32(ramht, co + 4, ctx); ++ ++ list_add_tail(&ref->list, &chan->ramht_refs); ++ instmem->flush(dev); ++ return 0; ++ } ++ NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n", ++ chan->id, co, nv_ro32(ramht, co)); ++ ++ co += 8; ++ if (co >= dev_priv->ramht_size) ++ co = 0; ++ } while (co != ho); ++ ++ NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); ++ return -ENOMEM; ++} ++ ++void ++nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; ++ struct nouveau_channel *chan = ref->channel; ++ struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; ++ uint32_t co, ho; ++ ++ if (!ramht) { ++ NV_ERROR(dev, "No hash table!\n"); ++ return; ++ } ++ ++ co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); ++ do { ++ if (nouveau_ramht_entry_valid(dev, ramht, co) && ++ (ref->handle == nv_ro32(ramht, co))) { ++ NV_DEBUG(dev, ++ "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", ++ chan->id, co, ref->handle, ++ nv_ro32(ramht, co + 4)); ++ nv_wo32(ramht, co + 0, 0x00000000); ++ nv_wo32(ramht, co + 4, 0x00000000); ++ ++ list_del(&ref->list); ++ instmem->flush(dev); ++ return; ++ } ++ ++ co += 8; ++ if (co >= dev_priv->ramht_size) ++ co = 0; ++ } while (co != ho); ++ list_del(&ref->list); ++ ++ NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", ++ chan->id, ref->handle); ++} +diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h +new file mode 100644 +index 0000000..e10455c +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright 2010 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 ++ */ ++ ++#ifndef __NOUVEAU_RAMHT_H__ ++#define __NOUVEAU_RAMHT_H__ ++ ++extern int nouveau_ramht_insert(struct drm_device *, struct nouveau_gpuobj_ref *); ++extern void nouveau_ramht_remove(struct drm_device *, struct nouveau_gpuobj_ref *); ++ ++#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 6ca80a3..21a6e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -5479,7 +6900,7 @@ index 6ca80a3..21a6e45 100644 #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -index 1d6ee8b..491767f 100644 +index 1d6ee8b..630988a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) @@ -5490,7 +6911,24 @@ index 1d6ee8b..491767f 100644 pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT); nvbe->pte_start = pte; for (i = 0; i < nvbe->nr_pages; i++) { -@@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) +@@ -106,34 +105,23 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + uint32_t offset_h = upper_32_bits(dma_offset); + + for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { +- if (dev_priv->card_type < NV_50) +- nv_wo32(dev, gpuobj, pte++, offset_l | 3); +- else { +- nv_wo32(dev, gpuobj, pte++, offset_l | 0x21); +- nv_wo32(dev, gpuobj, pte++, offset_h & 0xff); ++ if (dev_priv->card_type < NV_50) { ++ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); ++ pte += 1; ++ } else { ++ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21); ++ nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff); ++ pte += 2; + } + dma_offset += NV_CTXDMA_PAGE_SIZE; } } @@ -5518,7 +6956,7 @@ index 1d6ee8b..491767f 100644 } nvbe->bound = true; -@@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be) +@@ -154,40 +142,28 @@ nouveau_sgdma_unbind(struct ttm_backend *be) if (!nvbe->bound) return 0; @@ -5526,7 +6964,22 @@ index 1d6ee8b..491767f 100644 pte = nvbe->pte_start; for (i = 0; i < nvbe->nr_pages; i++) { dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus; -@@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be) + + for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { +- if (dev_priv->card_type < NV_50) +- nv_wo32(dev, gpuobj, pte++, dma_offset | 3); +- else { +- nv_wo32(dev, gpuobj, pte++, dma_offset | 0x21); +- nv_wo32(dev, gpuobj, pte++, 0x00000000); ++ if (dev_priv->card_type < NV_50) { ++ nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3); ++ pte += 1; ++ } else { ++ nv_wo32(gpuobj, (pte * 4), dma_offset | 0x21); ++ nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000); ++ pte += 2; + } + dma_offset += NV_CTXDMA_PAGE_SIZE; } } @@ -5554,16 +7007,64 @@ index 1d6ee8b..491767f 100644 } nvbe->bound = false; -@@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev) - pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, +@@ -242,6 +218,7 @@ int + nouveau_sgdma_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct pci_dev *pdev = dev->pdev; + struct nouveau_gpuobj *gpuobj = NULL; + uint32_t aper_size, obj_size; + int i, ret; +@@ -267,34 +244,42 @@ nouveau_sgdma_init(struct drm_device *dev) + + dev_priv->gart_info.sg_dummy_page = + alloc_page(GFP_KERNEL|__GFP_DMA32); ++ if (!dev_priv->gart_info.sg_dummy_page) { ++ nouveau_gpuobj_del(dev, &gpuobj); ++ return -ENOMEM; ++ } ++ + set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags); + dev_priv->gart_info.sg_dummy_bus = +- pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, ++ pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { ++ nouveau_gpuobj_del(dev, &gpuobj); ++ return -EFAULT; ++ } - dev_priv->engine.instmem.prepare_access(dev, true); if (dev_priv->card_type < NV_50) { /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE -@@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev) - nv_wo32(dev, gpuobj, (i+4)/4, 0); + * on those cards? */ +- nv_wo32(dev, gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | +- (1 << 12) /* PT present */ | +- (0 << 13) /* PT *not* linear */ | +- (NV_DMA_ACCESS_RW << 14) | +- (NV_DMA_TARGET_PCI << 16)); +- nv_wo32(dev, gpuobj, 1, aper_size - 1); ++ nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | ++ (1 << 12) /* PT present */ | ++ (0 << 13) /* PT *not* linear */ | ++ (NV_DMA_ACCESS_RW << 14) | ++ (NV_DMA_TARGET_PCI << 16)); ++ nv_wo32(gpuobj, 4, aper_size - 1); + for (i = 2; i < 2 + (aper_size >> 12); i++) { +- nv_wo32(dev, gpuobj, i, +- dev_priv->gart_info.sg_dummy_bus | 3); ++ nv_wo32(gpuobj, i * 4, ++ dev_priv->gart_info.sg_dummy_bus | 3); + } + } else { + for (i = 0; i < obj_size; i += 8) { +- nv_wo32(dev, gpuobj, (i+0)/4, +- dev_priv->gart_info.sg_dummy_bus | 0x21); +- nv_wo32(dev, gpuobj, (i+4)/4, 0); ++ nv_wo32(gpuobj, i + 0, ++ dev_priv->gart_info.sg_dummy_bus | 0x21); ++ nv_wo32(gpuobj, i + 4, 0); } } - dev_priv->engine.instmem.finish_access(dev); @@ -5571,18 +7072,20 @@ index 1d6ee8b..491767f 100644 dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; dev_priv->gart_info.aper_base = 0; -@@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) +@@ -325,14 +310,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; - struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; int pte; - pte = (offset >> NV_CTXDMA_PAGE_SHIFT); +- pte = (offset >> NV_CTXDMA_PAGE_SHIFT); ++ pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2; if (dev_priv->card_type < NV_50) { - instmem->prepare_access(dev, false); - *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK; +- *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK; - instmem->finish_access(dev); ++ *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK; return 0; } @@ -6196,7 +7699,7 @@ index b02a231..989322b 100644 default: NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c -index eba687f..08c7e07 100644 +index eba687f..291a4cb 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -6228,8 +7731,25 @@ index eba687f..08c7e07 100644 regp->crtc_830 = mode->crtc_vdisplay - 3; regp->crtc_834 = mode->crtc_vdisplay - 1; +@@ -710,6 +718,7 @@ static void nv_crtc_destroy(struct drm_crtc *crtc) + + drm_crtc_cleanup(crtc); + ++ nouveau_bo_unmap(nv_crtc->cursor.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); + kfree(nv_crtc); + } +@@ -820,7 +829,7 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX); + crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX); + +- if (dev_priv->card_type >= NV_30) { ++ if (dev_priv->card_type >= NV_20) { + regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8; + crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47); + } diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c -index 1cb19e3..ea36270 100644 +index 1cb19e3..9cc560c 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) @@ -6271,7 +7791,16 @@ index 1cb19e3..ea36270 100644 /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ routput = (saved_routput & 0xfffffece) | head << 8; -@@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) +@@ -291,6 +291,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) + msleep(5); + + sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); ++ /* do it again just in case it's a residual current */ ++ sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); + + temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, +@@ -304,8 +306,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); @@ -6282,7 +7811,7 @@ index 1cb19e3..ea36270 100644 return sample; } -@@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -315,9 +317,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; @@ -6297,7 +7826,7 @@ index 1cb19e3..ea36270 100644 NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; -@@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, +@@ -330,6 +335,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -6307,7 +7836,24 @@ index 1cb19e3..ea36270 100644 return true; } -@@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) +@@ -344,15 +352,9 @@ static void nv04_dac_prepare(struct drm_encoder *encoder) + helper->dpms(encoder, DRM_MODE_DPMS_OFF); + + nv04_dfp_disable(dev, head); +- +- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f) +- * at LCD__INDEX which we don't alter +- */ +- if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44)) +- crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0; ++ crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0; + } + +- + static void nv04_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +@@ -428,6 +430,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) } } @@ -6325,7 +7871,7 @@ index 1cb19e3..ea36270 100644 static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; -@@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { +@@ -501,11 +514,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { .destroy = nv04_dac_destroy, }; @@ -6341,7 +7887,7 @@ index 1cb19e3..ea36270 100644 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); if (!nv_encoder) -@@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -527,5 +542,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -6349,7 +7895,7 @@ index 1cb19e3..ea36270 100644 return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c -index 41634d4..a5dcf76 100644 +index 41634d4..e331b4f 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -34,6 +34,8 @@ @@ -6398,30 +7944,118 @@ index 41634d4..a5dcf76 100644 static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) -@@ -413,10 +445,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -221,26 +253,21 @@ static void nv04_dfp_prepare(struct drm_encoder *encoder) + + nv04_dfp_prepare_sel_clk(dev, nv_encoder, head); + +- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f) +- * at LCD__INDEX which we don't alter +- */ +- if (!(*cr_lcd & 0x44)) { +- *cr_lcd = 0x3; +- +- if (nv_two_heads(dev)) { +- if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP) +- *cr_lcd |= head ? 0x0 : 0x8; +- else { +- *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30; +- if (nv_encoder->dcb->type == OUTPUT_LVDS) +- *cr_lcd |= 0x30; +- if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) { +- /* avoid being connected to both crtcs */ +- *cr_lcd_oth &= ~0x30; +- NVWriteVgaCrtc(dev, head ^ 1, +- NV_CIO_CRE_LCD__INDEX, +- *cr_lcd_oth); +- } ++ *cr_lcd = 0x3; ++ ++ if (nv_two_heads(dev)) { ++ if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP) ++ *cr_lcd |= head ? 0x0 : 0x8; ++ else { ++ *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30; ++ if (nv_encoder->dcb->type == OUTPUT_LVDS) ++ *cr_lcd |= 0x30; ++ if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) { ++ /* avoid being connected to both crtcs */ ++ *cr_lcd_oth &= ~0x30; ++ NVWriteVgaCrtc(dev, head ^ 1, ++ NV_CIO_CRE_LCD__INDEX, ++ *cr_lcd_oth); + } + } + } +@@ -412,10 +439,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct dcb_entry *dcbe = nv_encoder->dcb; int head = nouveau_crtc(encoder->crtc)->index; - +- - NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), - nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); -- ++ struct drm_encoder *slave_encoder; + if (dcbe->type == OUTPUT_TMDS) run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); - else if (dcbe->type == OUTPUT_LVDS) -@@ -433,6 +461,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -433,6 +457,12 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) else NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); + /* Init external transmitters */ -+ if (get_tmds_slave(encoder)) -+ get_slave_funcs(get_tmds_slave(encoder))->mode_set( -+ encoder, &nv_encoder->mode, &nv_encoder->mode); ++ slave_encoder = get_tmds_slave(encoder); ++ if (slave_encoder) ++ get_slave_funcs(slave_encoder)->mode_set( ++ slave_encoder, &nv_encoder->mode, &nv_encoder->mode); + helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", -@@ -554,10 +587,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) +@@ -440,6 +470,27 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) + nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); + } + ++static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) ++{ ++#ifdef __powerpc__ ++ struct drm_device *dev = encoder->dev; ++ ++ /* BIOS scripts usually take care of the backlight, thanks ++ * Apple for your consistency. ++ */ ++ if (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || ++ dev->pci_device == 0x0329) { ++ if (mode == DRM_MODE_DPMS_ON) { ++ nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31); ++ nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 1); ++ } else { ++ nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0); ++ nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 0); ++ } ++ } ++#endif ++} ++ + static inline bool is_powersaving_dpms(int mode) + { + return (mode != DRM_MODE_DPMS_ON); +@@ -487,6 +538,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) + LVDS_PANEL_OFF, 0); + } + ++ nv04_dfp_update_backlight(encoder, mode); + nv04_dfp_update_fp_control(encoder, mode); + + if (mode == DRM_MODE_DPMS_ON) +@@ -510,6 +562,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) + NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n", + mode, nv_encoder->dcb->index); + ++ nv04_dfp_update_backlight(encoder, mode); + nv04_dfp_update_fp_control(encoder, mode); + } + +@@ -554,10 +607,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) NV_DEBUG_KMS(encoder->dev, "\n"); @@ -6464,7 +8098,7 @@ index 41634d4..a5dcf76 100644 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { .dpms = nv04_lvds_dpms, .save = nv04_dfp_save, -@@ -584,11 +649,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { +@@ -584,11 +669,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { .destroy = nv04_dfp_destroy, }; @@ -6479,7 +8113,7 @@ index 41634d4..a5dcf76 100644 int type; switch (entry->type) { -@@ -613,11 +679,16 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -613,11 +699,16 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; @@ -6691,9 +8325,24 @@ index c7898b4..9e28cf7 100644 } diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c -index 66fe559..06cedd9 100644 +index 66fe559..bbb87ef 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c +@@ -38,10 +38,10 @@ + #define NV04_RAMFC_ENGINE 0x14 + #define NV04_RAMFC_PULL1_ENGINE 0x18 + +-#define RAMFC_WR(offset, val) nv_wo32(dev, chan->ramfc->gpuobj, \ +- NV04_RAMFC_##offset/4, (val)) +-#define RAMFC_RD(offset) nv_ro32(dev, chan->ramfc->gpuobj, \ +- NV04_RAMFC_##offset/4) ++#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc->gpuobj, \ ++ NV04_RAMFC_##offset, (val)) ++#define RAMFC_RD(offset) nv_ro32(chan->ramfc->gpuobj, \ ++ NV04_RAMFC_##offset) + + void + nv04_fifo_disable(struct drm_device *dev) @@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev) NV03_PFIFO_CACHE1_PUSH1_CHID_MASK; } @@ -7544,7 +9193,7 @@ index 2e58c33..0000000 - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c -index 74c8803..44fefb0 100644 +index 74c8803..703c188 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) @@ -7577,7 +9226,7 @@ index 74c8803..44fefb0 100644 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); -@@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) +@@ -110,12 +111,31 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); @@ -7593,10 +9242,14 @@ index 74c8803..44fefb0 100644 +get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) +{ + /* Zotac FX5200 */ -+ if (dev->pdev->device == 0x0322 && -+ dev->pdev->subsystem_vendor == 0x19da && -+ (dev->pdev->subsystem_device == 0x1035 || -+ dev->pdev->subsystem_device == 0x2035)) { ++ if (nv_match_device(dev, 0x0322, 0x19da, 0x1035) || ++ nv_match_device(dev, 0x0322, 0x19da, 0x2035)) { ++ *pin_mask = 0xc; ++ return false; ++ } ++ ++ /* MSI nForce2 IGP */ ++ if (nv_match_device(dev, 0x01f0, 0x1462, 0x5710)) { + *pin_mask = 0xc; + return false; + } @@ -7607,7 +9260,7 @@ index 74c8803..44fefb0 100644 static enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { -@@ -124,12 +140,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -124,12 +144,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); struct dcb_entry *dcb = tv_enc->base.dcb; @@ -7633,7 +9286,7 @@ index 74c8803..44fefb0 100644 switch (tv_enc->pin_mask) { case 0x2: -@@ -154,7 +178,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) +@@ -154,7 +182,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) conf->tv_subconnector_property, tv_enc->subconnector); @@ -7644,7 +9297,7 @@ index 74c8803..44fefb0 100644 NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; -@@ -296,6 +322,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, +@@ -296,6 +326,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, { struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); @@ -7654,7 +9307,7 @@ index 74c8803..44fefb0 100644 if (tv_norm->kind == CTV_ENC_MODE) adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock; else -@@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, +@@ -307,6 +340,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -7663,7 +9316,7 @@ index 74c8803..44fefb0 100644 struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); -@@ -331,8 +362,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) +@@ -331,8 +366,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) nv_load_ptv(dev, regs, 200); @@ -7674,7 +9327,27 @@ index 74c8803..44fefb0 100644 nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } -@@ -744,8 +775,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { +@@ -373,15 +408,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) + + } + +- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f) +- * at LCD__INDEX which we don't alter +- */ +- if (!(*cr_lcd & 0x44)) { +- if (tv_norm->kind == CTV_ENC_MODE) +- *cr_lcd = 0x1 | (head ? 0x0 : 0x8); +- else +- *cr_lcd = 0; +- } ++ if (tv_norm->kind == CTV_ENC_MODE) ++ *cr_lcd = 0x1 | (head ? 0x0 : 0x8); ++ else ++ *cr_lcd = 0; + + /* Set the DACCLK register */ + dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1; +@@ -744,8 +774,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { .destroy = nv17_tv_destroy, }; @@ -7686,7 +9359,7 @@ index 74c8803..44fefb0 100644 struct drm_encoder *encoder; struct nv17_tv_encoder *tv_enc = NULL; -@@ -774,5 +807,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -774,5 +806,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -7695,9 +9368,573 @@ index 74c8803..44fefb0 100644 return 0; } diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c -index d6fc0a8..191c15c 100644 +index d6fc0a8..cc876ef 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c +@@ -37,49 +37,49 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x033c/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x047c/4, 0x00000101); +- nv_wo32(dev, ctx, 0x0490/4, 0x00000111); +- nv_wo32(dev, ctx, 0x04a8/4, 0x44400000); ++ nv_wo32(ctx, 0x033c, 0xffff0000); ++ nv_wo32(ctx, 0x03a0, 0x0fff0000); ++ nv_wo32(ctx, 0x03a4, 0x0fff0000); ++ nv_wo32(ctx, 0x047c, 0x00000101); ++ nv_wo32(ctx, 0x0490, 0x00000111); ++ nv_wo32(ctx, 0x04a8, 0x44400000); + for (i = 0x04d4; i <= 0x04e0; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x04f4; i <= 0x0500; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080000); ++ nv_wo32(ctx, i, 0x00080000); + for (i = 0x050c; i <= 0x0518; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x051c; i <= 0x0528; i += 4) +- nv_wo32(dev, ctx, i/4, 0x000105b8); ++ nv_wo32(ctx, i, 0x000105b8); + for (i = 0x052c; i <= 0x0538; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); ++ nv_wo32(ctx, i, 0x00080008); + for (i = 0x055c; i <= 0x0598; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x05fc/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0604/4, 0x00004000); +- nv_wo32(dev, ctx, 0x0610/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0618/4, 0x00040000); +- nv_wo32(dev, ctx, 0x061c/4, 0x00010000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x05a4, 0x4b7fffff); ++ nv_wo32(ctx, 0x05fc, 0x00000001); ++ nv_wo32(ctx, 0x0604, 0x00004000); ++ nv_wo32(ctx, 0x0610, 0x00000001); ++ nv_wo32(ctx, 0x0618, 0x00040000); ++ nv_wo32(ctx, 0x061c, 0x00010000); + for (i = 0x1c1c; i <= 0x248c; i += 16) { +- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9); +- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c); +- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b); ++ nv_wo32(ctx, (i + 0), 0x10700ff9); ++ nv_wo32(ctx, (i + 4), 0x0436086c); ++ nv_wo32(ctx, (i + 8), 0x000c001b); + } +- nv_wo32(dev, ctx, 0x281c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2830/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x285c/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2860/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2864/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x286c/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2870/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2878/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x2880/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x34a4/4, 0x000fe000); +- nv_wo32(dev, ctx, 0x3530/4, 0x000003f8); +- nv_wo32(dev, ctx, 0x3540/4, 0x002fe000); ++ nv_wo32(ctx, 0x281c, 0x3f800000); ++ nv_wo32(ctx, 0x2830, 0x3f800000); ++ nv_wo32(ctx, 0x285c, 0x40000000); ++ nv_wo32(ctx, 0x2860, 0x3f800000); ++ nv_wo32(ctx, 0x2864, 0x3f000000); ++ nv_wo32(ctx, 0x286c, 0x40000000); ++ nv_wo32(ctx, 0x2870, 0x3f800000); ++ nv_wo32(ctx, 0x2878, 0xbf800000); ++ nv_wo32(ctx, 0x2880, 0xbf800000); ++ nv_wo32(ctx, 0x34a4, 0x000fe000); ++ nv_wo32(ctx, 0x3530, 0x000003f8); ++ nv_wo32(ctx, 0x3540, 0x002fe000); + for (i = 0x355c; i <= 0x3578; i += 4) +- nv_wo32(dev, ctx, i/4, 0x001c527c); ++ nv_wo32(ctx, i, 0x001c527c); + } + + static void +@@ -87,58 +87,58 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x035c/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x03c0/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x03c4/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x049c/4, 0x00000101); +- nv_wo32(dev, ctx, 0x04b0/4, 0x00000111); +- nv_wo32(dev, ctx, 0x04c8/4, 0x00000080); +- nv_wo32(dev, ctx, 0x04cc/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x04d0/4, 0x00000001); +- nv_wo32(dev, ctx, 0x04e4/4, 0x44400000); +- nv_wo32(dev, ctx, 0x04fc/4, 0x4b800000); ++ nv_wo32(ctx, 0x035c, 0xffff0000); ++ nv_wo32(ctx, 0x03c0, 0x0fff0000); ++ nv_wo32(ctx, 0x03c4, 0x0fff0000); ++ nv_wo32(ctx, 0x049c, 0x00000101); ++ nv_wo32(ctx, 0x04b0, 0x00000111); ++ nv_wo32(ctx, 0x04c8, 0x00000080); ++ nv_wo32(ctx, 0x04cc, 0xffff0000); ++ nv_wo32(ctx, 0x04d0, 0x00000001); ++ nv_wo32(ctx, 0x04e4, 0x44400000); ++ nv_wo32(ctx, 0x04fc, 0x4b800000); + for (i = 0x0510; i <= 0x051c; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x0530; i <= 0x053c; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080000); ++ nv_wo32(ctx, i, 0x00080000); + for (i = 0x0548; i <= 0x0554; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x0558; i <= 0x0564; i += 4) +- nv_wo32(dev, ctx, i/4, 0x000105b8); ++ nv_wo32(ctx, i, 0x000105b8); + for (i = 0x0568; i <= 0x0574; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); ++ nv_wo32(ctx, i, 0x00080008); + for (i = 0x0598; i <= 0x05d4; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x05e0/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x0620/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0624/4, 0x30201000); +- nv_wo32(dev, ctx, 0x0628/4, 0x70605040); +- nv_wo32(dev, ctx, 0x062c/4, 0xb0a09080); +- nv_wo32(dev, ctx, 0x0630/4, 0xf0e0d0c0); +- nv_wo32(dev, ctx, 0x0664/4, 0x00000001); +- nv_wo32(dev, ctx, 0x066c/4, 0x00004000); +- nv_wo32(dev, ctx, 0x0678/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0680/4, 0x00040000); +- nv_wo32(dev, ctx, 0x0684/4, 0x00010000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x05e0, 0x4b7fffff); ++ nv_wo32(ctx, 0x0620, 0x00000080); ++ nv_wo32(ctx, 0x0624, 0x30201000); ++ nv_wo32(ctx, 0x0628, 0x70605040); ++ nv_wo32(ctx, 0x062c, 0xb0a09080); ++ nv_wo32(ctx, 0x0630, 0xf0e0d0c0); ++ nv_wo32(ctx, 0x0664, 0x00000001); ++ nv_wo32(ctx, 0x066c, 0x00004000); ++ nv_wo32(ctx, 0x0678, 0x00000001); ++ nv_wo32(ctx, 0x0680, 0x00040000); ++ nv_wo32(ctx, 0x0684, 0x00010000); + for (i = 0x1b04; i <= 0x2374; i += 16) { +- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9); +- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c); +- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b); ++ nv_wo32(ctx, (i + 0), 0x10700ff9); ++ nv_wo32(ctx, (i + 4), 0x0436086c); ++ nv_wo32(ctx, (i + 8), 0x000c001b); + } +- nv_wo32(dev, ctx, 0x2704/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2718/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2744/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2748/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x274c/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x2754/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2758/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2760/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x2768/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x308c/4, 0x000fe000); +- nv_wo32(dev, ctx, 0x3108/4, 0x000003f8); +- nv_wo32(dev, ctx, 0x3468/4, 0x002fe000); ++ nv_wo32(ctx, 0x2704, 0x3f800000); ++ nv_wo32(ctx, 0x2718, 0x3f800000); ++ nv_wo32(ctx, 0x2744, 0x40000000); ++ nv_wo32(ctx, 0x2748, 0x3f800000); ++ nv_wo32(ctx, 0x274c, 0x3f000000); ++ nv_wo32(ctx, 0x2754, 0x40000000); ++ nv_wo32(ctx, 0x2758, 0x3f800000); ++ nv_wo32(ctx, 0x2760, 0xbf800000); ++ nv_wo32(ctx, 0x2768, 0xbf800000); ++ nv_wo32(ctx, 0x308c, 0x000fe000); ++ nv_wo32(ctx, 0x3108, 0x000003f8); ++ nv_wo32(ctx, 0x3468, 0x002fe000); + for (i = 0x3484; i <= 0x34a0; i += 4) +- nv_wo32(dev, ctx, i/4, 0x001c527c); ++ nv_wo32(ctx, i, 0x001c527c); + } + + static void +@@ -146,49 +146,49 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x033c/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x047c/4, 0x00000101); +- nv_wo32(dev, ctx, 0x0490/4, 0x00000111); +- nv_wo32(dev, ctx, 0x04a8/4, 0x44400000); ++ nv_wo32(ctx, 0x033c, 0xffff0000); ++ nv_wo32(ctx, 0x03a0, 0x0fff0000); ++ nv_wo32(ctx, 0x03a4, 0x0fff0000); ++ nv_wo32(ctx, 0x047c, 0x00000101); ++ nv_wo32(ctx, 0x0490, 0x00000111); ++ nv_wo32(ctx, 0x04a8, 0x44400000); + for (i = 0x04d4; i <= 0x04e0; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x04f4; i <= 0x0500; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080000); ++ nv_wo32(ctx, i, 0x00080000); + for (i = 0x050c; i <= 0x0518; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x051c; i <= 0x0528; i += 4) +- nv_wo32(dev, ctx, i/4, 0x000105b8); ++ nv_wo32(ctx, i, 0x000105b8); + for (i = 0x052c; i <= 0x0538; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); ++ nv_wo32(ctx, i, 0x00080008); + for (i = 0x055c; i <= 0x0598; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x05fc/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0604/4, 0x00004000); +- nv_wo32(dev, ctx, 0x0610/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0618/4, 0x00040000); +- nv_wo32(dev, ctx, 0x061c/4, 0x00010000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x05a4, 0x4b7fffff); ++ nv_wo32(ctx, 0x05fc, 0x00000001); ++ nv_wo32(ctx, 0x0604, 0x00004000); ++ nv_wo32(ctx, 0x0610, 0x00000001); ++ nv_wo32(ctx, 0x0618, 0x00040000); ++ nv_wo32(ctx, 0x061c, 0x00010000); + for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ +- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9); +- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c); +- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b); ++ nv_wo32(ctx, (i + 0), 0x10700ff9); ++ nv_wo32(ctx, (i + 4), 0x0436086c); ++ nv_wo32(ctx, (i + 8), 0x000c001b); + } +- nv_wo32(dev, ctx, 0x269c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x26b0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x26dc/4, 0x40000000); +- nv_wo32(dev, ctx, 0x26e0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x26e4/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x26ec/4, 0x40000000); +- nv_wo32(dev, ctx, 0x26f0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x26f8/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x2700/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x3024/4, 0x000fe000); +- nv_wo32(dev, ctx, 0x30a0/4, 0x000003f8); +- nv_wo32(dev, ctx, 0x33fc/4, 0x002fe000); ++ nv_wo32(ctx, 0x269c, 0x3f800000); ++ nv_wo32(ctx, 0x26b0, 0x3f800000); ++ nv_wo32(ctx, 0x26dc, 0x40000000); ++ nv_wo32(ctx, 0x26e0, 0x3f800000); ++ nv_wo32(ctx, 0x26e4, 0x3f000000); ++ nv_wo32(ctx, 0x26ec, 0x40000000); ++ nv_wo32(ctx, 0x26f0, 0x3f800000); ++ nv_wo32(ctx, 0x26f8, 0xbf800000); ++ nv_wo32(ctx, 0x2700, 0xbf800000); ++ nv_wo32(ctx, 0x3024, 0x000fe000); ++ nv_wo32(ctx, 0x30a0, 0x000003f8); ++ nv_wo32(ctx, 0x33fc, 0x002fe000); + for (i = 0x341c; i <= 0x3438; i += 4) +- nv_wo32(dev, ctx, i/4, 0x001c527c); ++ nv_wo32(ctx, i, 0x001c527c); + } + + static void +@@ -196,57 +196,57 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x0410/4, 0x00000101); +- nv_wo32(dev, ctx, 0x0424/4, 0x00000111); +- nv_wo32(dev, ctx, 0x0428/4, 0x00000060); +- nv_wo32(dev, ctx, 0x0444/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0448/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x044c/4, 0x00000001); +- nv_wo32(dev, ctx, 0x0460/4, 0x44400000); +- nv_wo32(dev, ctx, 0x048c/4, 0xffff0000); ++ nv_wo32(ctx, 0x0410, 0x00000101); ++ nv_wo32(ctx, 0x0424, 0x00000111); ++ nv_wo32(ctx, 0x0428, 0x00000060); ++ nv_wo32(ctx, 0x0444, 0x00000080); ++ nv_wo32(ctx, 0x0448, 0xffff0000); ++ nv_wo32(ctx, 0x044c, 0x00000001); ++ nv_wo32(ctx, 0x0460, 0x44400000); ++ nv_wo32(ctx, 0x048c, 0xffff0000); + for (i = 0x04e0; i < 0x04e8; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x04ec/4, 0x00011100); ++ nv_wo32(ctx, i, 0x0fff0000); ++ nv_wo32(ctx, 0x04ec, 0x00011100); + for (i = 0x0508; i < 0x0548; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x0550/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x058c/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0590/4, 0x30201000); +- nv_wo32(dev, ctx, 0x0594/4, 0x70605040); +- nv_wo32(dev, ctx, 0x0598/4, 0xb8a89888); +- nv_wo32(dev, ctx, 0x059c/4, 0xf8e8d8c8); +- nv_wo32(dev, ctx, 0x05b0/4, 0xb0000000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x0550, 0x4b7fffff); ++ nv_wo32(ctx, 0x058c, 0x00000080); ++ nv_wo32(ctx, 0x0590, 0x30201000); ++ nv_wo32(ctx, 0x0594, 0x70605040); ++ nv_wo32(ctx, 0x0598, 0xb8a89888); ++ nv_wo32(ctx, 0x059c, 0xf8e8d8c8); ++ nv_wo32(ctx, 0x05b0, 0xb0000000); + for (i = 0x0600; i < 0x0640; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00010588); ++ nv_wo32(ctx, i, 0x00010588); + for (i = 0x0640; i < 0x0680; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x06c0; i < 0x0700; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0008aae4); ++ nv_wo32(ctx, i, 0x0008aae4); + for (i = 0x0700; i < 0x0740; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x0740; i < 0x0780; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); +- nv_wo32(dev, ctx, 0x085c/4, 0x00040000); +- nv_wo32(dev, ctx, 0x0860/4, 0x00010000); ++ nv_wo32(ctx, i, 0x00080008); ++ nv_wo32(ctx, 0x085c, 0x00040000); ++ nv_wo32(ctx, 0x0860, 0x00010000); + for (i = 0x0864; i < 0x0874; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00040004); ++ nv_wo32(ctx, i, 0x00040004); + for (i = 0x1f18; i <= 0x3088 ; i += 16) { +- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9); +- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c); +- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b); ++ nv_wo32(ctx, i + 0, 0x10700ff9); ++ nv_wo32(ctx, i + 1, 0x0436086c); ++ nv_wo32(ctx, i + 2, 0x000c001b); + } + for (i = 0x30b8; i < 0x30c8; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0000ffff); +- nv_wo32(dev, ctx, 0x344c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3808/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x381c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3848/4, 0x40000000); +- nv_wo32(dev, ctx, 0x384c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3850/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x3858/4, 0x40000000); +- nv_wo32(dev, ctx, 0x385c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3864/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x386c/4, 0xbf800000); ++ nv_wo32(ctx, i, 0x0000ffff); ++ nv_wo32(ctx, 0x344c, 0x3f800000); ++ nv_wo32(ctx, 0x3808, 0x3f800000); ++ nv_wo32(ctx, 0x381c, 0x3f800000); ++ nv_wo32(ctx, 0x3848, 0x40000000); ++ nv_wo32(ctx, 0x384c, 0x3f800000); ++ nv_wo32(ctx, 0x3850, 0x3f000000); ++ nv_wo32(ctx, 0x3858, 0x40000000); ++ nv_wo32(ctx, 0x385c, 0x3f800000); ++ nv_wo32(ctx, 0x3864, 0xbf800000); ++ nv_wo32(ctx, 0x386c, 0xbf800000); + } + + static void +@@ -254,57 +254,57 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x040c/4, 0x01000101); +- nv_wo32(dev, ctx, 0x0420/4, 0x00000111); +- nv_wo32(dev, ctx, 0x0424/4, 0x00000060); +- nv_wo32(dev, ctx, 0x0440/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0444/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x0448/4, 0x00000001); +- nv_wo32(dev, ctx, 0x045c/4, 0x44400000); +- nv_wo32(dev, ctx, 0x0480/4, 0xffff0000); ++ nv_wo32(ctx, 0x040c, 0x01000101); ++ nv_wo32(ctx, 0x0420, 0x00000111); ++ nv_wo32(ctx, 0x0424, 0x00000060); ++ nv_wo32(ctx, 0x0440, 0x00000080); ++ nv_wo32(ctx, 0x0444, 0xffff0000); ++ nv_wo32(ctx, 0x0448, 0x00000001); ++ nv_wo32(ctx, 0x045c, 0x44400000); ++ nv_wo32(ctx, 0x0480, 0xffff0000); + for (i = 0x04d4; i < 0x04dc; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x04e0/4, 0x00011100); ++ nv_wo32(ctx, i, 0x0fff0000); ++ nv_wo32(ctx, 0x04e0, 0x00011100); + for (i = 0x04fc; i < 0x053c; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x0544/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x057c/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0580/4, 0x30201000); +- nv_wo32(dev, ctx, 0x0584/4, 0x70605040); +- nv_wo32(dev, ctx, 0x0588/4, 0xb8a89888); +- nv_wo32(dev, ctx, 0x058c/4, 0xf8e8d8c8); +- nv_wo32(dev, ctx, 0x05a0/4, 0xb0000000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x0544, 0x4b7fffff); ++ nv_wo32(ctx, 0x057c, 0x00000080); ++ nv_wo32(ctx, 0x0580, 0x30201000); ++ nv_wo32(ctx, 0x0584, 0x70605040); ++ nv_wo32(ctx, 0x0588, 0xb8a89888); ++ nv_wo32(ctx, 0x058c, 0xf8e8d8c8); ++ nv_wo32(ctx, 0x05a0, 0xb0000000); + for (i = 0x05f0; i < 0x0630; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00010588); ++ nv_wo32(ctx, i, 0x00010588); + for (i = 0x0630; i < 0x0670; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x06b0; i < 0x06f0; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0008aae4); ++ nv_wo32(ctx, i, 0x0008aae4); + for (i = 0x06f0; i < 0x0730; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x0730; i < 0x0770; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); +- nv_wo32(dev, ctx, 0x0850/4, 0x00040000); +- nv_wo32(dev, ctx, 0x0854/4, 0x00010000); ++ nv_wo32(ctx, i, 0x00080008); ++ nv_wo32(ctx, 0x0850, 0x00040000); ++ nv_wo32(ctx, 0x0854, 0x00010000); + for (i = 0x0858; i < 0x0868; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00040004); ++ nv_wo32(ctx, i, 0x00040004); + for (i = 0x15ac; i <= 0x271c ; i += 16) { +- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9); +- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c); +- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b); ++ nv_wo32(ctx, i + 0, 0x10700ff9); ++ nv_wo32(ctx, i + 1, 0x0436086c); ++ nv_wo32(ctx, i + 2, 0x000c001b); + } + for (i = 0x274c; i < 0x275c; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0000ffff); +- nv_wo32(dev, ctx, 0x2ae0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2e9c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2eb0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2edc/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2ee0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2ee4/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x2eec/4, 0x40000000); +- nv_wo32(dev, ctx, 0x2ef0/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x2ef8/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x2f00/4, 0xbf800000); ++ nv_wo32(ctx, i, 0x0000ffff); ++ nv_wo32(ctx, 0x2ae0, 0x3f800000); ++ nv_wo32(ctx, 0x2e9c, 0x3f800000); ++ nv_wo32(ctx, 0x2eb0, 0x3f800000); ++ nv_wo32(ctx, 0x2edc, 0x40000000); ++ nv_wo32(ctx, 0x2ee0, 0x3f800000); ++ nv_wo32(ctx, 0x2ee4, 0x3f000000); ++ nv_wo32(ctx, 0x2eec, 0x40000000); ++ nv_wo32(ctx, 0x2ef0, 0x3f800000); ++ nv_wo32(ctx, 0x2ef8, 0xbf800000); ++ nv_wo32(ctx, 0x2f00, 0xbf800000); + } + + static void +@@ -312,57 +312,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) + { + int i; + +- nv_wo32(dev, ctx, 0x040c/4, 0x00000101); +- nv_wo32(dev, ctx, 0x0420/4, 0x00000111); +- nv_wo32(dev, ctx, 0x0424/4, 0x00000060); +- nv_wo32(dev, ctx, 0x0440/4, 0x00000080); +- nv_wo32(dev, ctx, 0x0444/4, 0xffff0000); +- nv_wo32(dev, ctx, 0x0448/4, 0x00000001); +- nv_wo32(dev, ctx, 0x045c/4, 0x44400000); +- nv_wo32(dev, ctx, 0x0488/4, 0xffff0000); ++ nv_wo32(ctx, 0x040c, 0x00000101); ++ nv_wo32(ctx, 0x0420, 0x00000111); ++ nv_wo32(ctx, 0x0424, 0x00000060); ++ nv_wo32(ctx, 0x0440, 0x00000080); ++ nv_wo32(ctx, 0x0444, 0xffff0000); ++ nv_wo32(ctx, 0x0448, 0x00000001); ++ nv_wo32(ctx, 0x045c, 0x44400000); ++ nv_wo32(ctx, 0x0488, 0xffff0000); + for (i = 0x04dc; i < 0x04e4; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0fff0000); +- nv_wo32(dev, ctx, 0x04e8/4, 0x00011100); ++ nv_wo32(ctx, i, 0x0fff0000); ++ nv_wo32(ctx, 0x04e8, 0x00011100); + for (i = 0x0504; i < 0x0544; i += 4) +- nv_wo32(dev, ctx, i/4, 0x07ff0000); +- nv_wo32(dev, ctx, 0x054c/4, 0x4b7fffff); +- nv_wo32(dev, ctx, 0x0588/4, 0x00000080); +- nv_wo32(dev, ctx, 0x058c/4, 0x30201000); +- nv_wo32(dev, ctx, 0x0590/4, 0x70605040); +- nv_wo32(dev, ctx, 0x0594/4, 0xb8a89888); +- nv_wo32(dev, ctx, 0x0598/4, 0xf8e8d8c8); +- nv_wo32(dev, ctx, 0x05ac/4, 0xb0000000); ++ nv_wo32(ctx, i, 0x07ff0000); ++ nv_wo32(ctx, 0x054c, 0x4b7fffff); ++ nv_wo32(ctx, 0x0588, 0x00000080); ++ nv_wo32(ctx, 0x058c, 0x30201000); ++ nv_wo32(ctx, 0x0590, 0x70605040); ++ nv_wo32(ctx, 0x0594, 0xb8a89888); ++ nv_wo32(ctx, 0x0598, 0xf8e8d8c8); ++ nv_wo32(ctx, 0x05ac, 0xb0000000); + for (i = 0x0604; i < 0x0644; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00010588); ++ nv_wo32(ctx, i, 0x00010588); + for (i = 0x0644; i < 0x0684; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00030303); ++ nv_wo32(ctx, i, 0x00030303); + for (i = 0x06c4; i < 0x0704; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0008aae4); ++ nv_wo32(ctx, i, 0x0008aae4); + for (i = 0x0704; i < 0x0744; i += 4) +- nv_wo32(dev, ctx, i/4, 0x01012000); ++ nv_wo32(ctx, i, 0x01012000); + for (i = 0x0744; i < 0x0784; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00080008); +- nv_wo32(dev, ctx, 0x0860/4, 0x00040000); +- nv_wo32(dev, ctx, 0x0864/4, 0x00010000); ++ nv_wo32(ctx, i, 0x00080008); ++ nv_wo32(ctx, 0x0860, 0x00040000); ++ nv_wo32(ctx, 0x0864, 0x00010000); + for (i = 0x0868; i < 0x0878; i += 4) +- nv_wo32(dev, ctx, i/4, 0x00040004); ++ nv_wo32(ctx, i, 0x00040004); + for (i = 0x1f1c; i <= 0x308c ; i += 16) { +- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9); +- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c); +- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b); ++ nv_wo32(ctx, i + 0, 0x10700ff9); ++ nv_wo32(ctx, i + 4, 0x0436086c); ++ nv_wo32(ctx, i + 8, 0x000c001b); + } + for (i = 0x30bc; i < 0x30cc; i += 4) +- nv_wo32(dev, ctx, i/4, 0x0000ffff); +- nv_wo32(dev, ctx, 0x3450/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x380c/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3820/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x384c/4, 0x40000000); +- nv_wo32(dev, ctx, 0x3850/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3854/4, 0x3f000000); +- nv_wo32(dev, ctx, 0x385c/4, 0x40000000); +- nv_wo32(dev, ctx, 0x3860/4, 0x3f800000); +- nv_wo32(dev, ctx, 0x3868/4, 0xbf800000); +- nv_wo32(dev, ctx, 0x3870/4, 0xbf800000); ++ nv_wo32(ctx, i, 0x0000ffff); ++ nv_wo32(ctx, 0x3450, 0x3f800000); ++ nv_wo32(ctx, 0x380c, 0x3f800000); ++ nv_wo32(ctx, 0x3820, 0x3f800000); ++ nv_wo32(ctx, 0x384c, 0x40000000); ++ nv_wo32(ctx, 0x3850, 0x3f800000); ++ nv_wo32(ctx, 0x3854, 0x3f000000); ++ nv_wo32(ctx, 0x385c, 0x40000000); ++ nv_wo32(ctx, 0x3860, 0x3f800000); ++ nv_wo32(ctx, 0x3868, 0xbf800000); ++ nv_wo32(ctx, 0x3870, 0xbf800000); + } + + int @@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; @@ -7705,7 +9942,8 @@ index d6fc0a8..191c15c 100644 + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); - unsigned int ctx_size; - unsigned int idoffs = 0x28/4; +- unsigned int idoffs = 0x28/4; ++ unsigned int idoffs = 0x28; int ret; switch (dev_priv->chipset) { @@ -7762,15 +10000,17 @@ index d6fc0a8..191c15c 100644 ctx_init(dev, chan->ramin_grctx->gpuobj); /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ - nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs, - (chan->id << 24) | 0x1); /* CTX_USER */ +- nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs, +- (chan->id << 24) | 0x1); /* CTX_USER */ ++ nv_wo32(chan->ramin_grctx->gpuobj, idoffs, ++ (chan->id << 24) | 0x1); /* CTX_USER */ - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, - chan->ramin_grctx->instance >> 4); - - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, -+ chan->ramin_grctx->instance >> 4); ++ nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4, ++ chan->ramin_grctx->instance >> 4); return 0; } @@ -7786,7 +10026,7 @@ index d6fc0a8..191c15c 100644 - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0); - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0); ++ nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4, 0); } int @@ -8059,7 +10299,7 @@ index 500ccfd..2b67f18 100644 nv40_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c -index 704a25d..ef550ce 100644 +index 704a25d..f7b59ad 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) @@ -8085,14 +10325,16 @@ index 704a25d..ef550ce 100644 - } else { - nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj); - } +- nv_wo32(dev, chan->ramin_grctx->gpuobj, 0, +- chan->ramin_grctx->gpuobj->im_pramin->start); +- dev_priv->engine.instmem.finish_access(dev); + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; + ctx.data = chan->ramin_grctx->gpuobj; + nv40_grctx_init(&ctx); + - nv_wo32(dev, chan->ramin_grctx->gpuobj, 0, - chan->ramin_grctx->gpuobj->im_pramin->start); -- dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(chan->ramin_grctx->gpuobj, 0, ++ chan->ramin_grctx->gpuobj->im_pramin->start); return 0; } @@ -8160,6 +10402,27 @@ index 704a25d..ef550ce 100644 } struct nouveau_pgraph_object_class nv40_graph_grclass[] = { +diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c +index 9b5c974..ce58509 100644 +--- a/drivers/gpu/drm/nouveau/nv40_grctx.c ++++ b/drivers/gpu/drm/nouveau/nv40_grctx.c +@@ -596,13 +596,13 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx) + + offset += 0x0280/4; + for (i = 0; i < 16; i++, offset += 2) +- nv_wo32(dev, obj, offset, 0x3f800000); ++ nv_wo32(obj, offset * 4, 0x3f800000); + + for (vs = 0; vs < vs_nr; vs++, offset += vs_len) { + for (i = 0; i < vs_nr_b0 * 6; i += 6) +- nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001); ++ nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); + for (i = 0; i < vs_nr_b1 * 4; i += 4) +- nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000); ++ nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); + } + } + diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c index 2a3495e..e4e72c1 100644 --- a/drivers/gpu/drm/nouveau/nv40_mc.c @@ -8174,7 +10437,7 @@ index 2a3495e..e4e72c1 100644 nv_wr32(dev, NV40_PMC_1704, 0); nv_wr32(dev, NV40_PMC_1708, 0); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c -index b4e4a3b..a438e56 100644 +index b4e4a3b..2423c92 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update) @@ -8224,7 +10487,17 @@ index b4e4a3b..a438e56 100644 } return 0; -@@ -440,47 +457,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) +@@ -321,7 +338,9 @@ nv50_crtc_destroy(struct drm_crtc *crtc) + + nv50_cursor_fini(nv_crtc); + ++ nouveau_bo_unmap(nv_crtc->lut.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); ++ nouveau_bo_unmap(nv_crtc->cursor.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); + kfree(nv_crtc->mode); + kfree(nv_crtc); +@@ -440,47 +459,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -8272,7 +10545,7 @@ index b4e4a3b..a438e56 100644 struct drm_device *dev = crtc->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; -@@ -491,20 +476,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) +@@ -491,20 +478,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) nv50_crtc_blank(nv_crtc, false); @@ -8406,30 +10679,43 @@ index 1fd9537..1bc0859 100644 } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c -index 580a5d1..612fa6d 100644 +index 580a5d1..435d2b7 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c -@@ -71,14 +71,16 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, +@@ -42,6 +42,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan) + *pchan = NULL; + + nouveau_gpuobj_channel_takedown(chan); ++ nouveau_bo_unmap(chan->pushbuf_bo); + nouveau_bo_ref(NULL, &chan->pushbuf_bo); + + if (chan->user) +@@ -71,14 +72,16 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, return ret; } - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); - nv_wo32(dev, obj, 1, limit); - nv_wo32(dev, obj, 2, offset); - nv_wo32(dev, obj, 3, 0x00000000); - nv_wo32(dev, obj, 4, 0x00000000); +- nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); +- nv_wo32(dev, obj, 1, limit); +- nv_wo32(dev, obj, 2, offset); +- nv_wo32(dev, obj, 3, 0x00000000); +- nv_wo32(dev, obj, 4, 0x00000000); - nv_wo32(dev, obj, 5, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); ++ nv_wo32(obj, 4, limit); ++ nv_wo32(obj, 8, offset); ++ nv_wo32(obj, 12, 0x00000000); ++ nv_wo32(obj, 16, 0x00000000); + if (dev_priv->card_type < NV_C0) -+ nv_wo32(dev, obj, 5, 0x00010000); ++ nv_wo32(obj, 20, 0x00010000); + else -+ nv_wo32(dev, obj, 5, 0x00020000); ++ nv_wo32(obj, 20, 0x00020000); + dev_priv->engine.instmem.flush(dev); return 0; } -@@ -110,8 +112,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) +@@ -110,8 +113,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) return ret; } @@ -8440,7 +10726,7 @@ index 580a5d1..612fa6d 100644 if (ret) { NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); nv50_evo_channel_del(pchan); -@@ -179,13 +181,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) +@@ -179,13 +182,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) } int @@ -8467,7 +10753,7 @@ index 580a5d1..612fa6d 100644 uint64_t start; int ret, i; -@@ -366,26 +380,13 @@ nv50_display_init(struct drm_device *dev) +@@ -366,26 +381,13 @@ nv50_display_init(struct drm_device *dev) NV50_PDISPLAY_INTR_EN_CLK_UNK40)); /* enable hotplug interrupts */ @@ -8495,7 +10781,7 @@ index 580a5d1..612fa6d 100644 } return 0; -@@ -465,6 +466,7 @@ int nv50_display_create(struct drm_device *dev) +@@ -465,6 +467,7 @@ int nv50_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; @@ -8503,7 +10789,7 @@ index 580a5d1..612fa6d 100644 int ret, i; NV_DEBUG_KMS(dev, "\n"); -@@ -507,14 +509,18 @@ int nv50_display_create(struct drm_device *dev) +@@ -507,14 +510,18 @@ int nv50_display_create(struct drm_device *dev) continue; } @@ -8524,7 +10810,7 @@ index 580a5d1..612fa6d 100644 break; default: NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); -@@ -522,11 +528,13 @@ int nv50_display_create(struct drm_device *dev) +@@ -522,11 +529,13 @@ int nv50_display_create(struct drm_device *dev) } } @@ -8543,7 +10829,7 @@ index 580a5d1..612fa6d 100644 } ret = nv50_display_init(dev); -@@ -538,7 +546,8 @@ int nv50_display_create(struct drm_device *dev) +@@ -538,7 +547,8 @@ int nv50_display_create(struct drm_device *dev) return 0; } @@ -8553,7 +10839,7 @@ index 580a5d1..612fa6d 100644 { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -548,135 +557,30 @@ int nv50_display_destroy(struct drm_device *dev) +@@ -548,135 +558,30 @@ int nv50_display_destroy(struct drm_device *dev) nv50_display_disable(dev); nv50_evo_channel_del(&dev_priv->evo); @@ -8696,7 +10982,7 @@ index 580a5d1..612fa6d 100644 case OUTPUT_LVDS: script = (mc >> 8) & 0xf; if (bios->fp_no_ddc) { -@@ -767,17 +671,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) +@@ -767,17 +672,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) static void nv50_display_unk10_handler(struct drm_device *dev) { @@ -8791,7 +11077,7 @@ index 580a5d1..612fa6d 100644 ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); nv_wr32(dev, 0x610030, 0x80000000); -@@ -817,33 +792,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) +@@ -817,33 +793,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) static void nv50_display_unk20_handler(struct drm_device *dev) { @@ -8913,7 +11199,7 @@ index 580a5d1..612fa6d 100644 tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); tmp &= ~0x00000f0f; if (script & 0x0100) -@@ -853,24 +898,61 @@ nv50_display_unk20_handler(struct drm_device *dev) +@@ -853,24 +899,61 @@ nv50_display_unk20_handler(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); } @@ -9000,11 +11286,58 @@ index 581d405..c551f0b 100644 int nv50_crtc_blank(struct nouveau_crtc *, bool blank); int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); +diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c +index 32611bd..ad267c5 100644 +--- a/drivers/gpu/drm/nouveau/nv50_fb.c ++++ b/drivers/gpu/drm/nouveau/nv50_fb.c +@@ -36,3 +36,42 @@ void + nv50_fb_takedown(struct drm_device *dev) + { + } ++ ++void ++nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 trap[6], idx, chinst; ++ int i, ch; ++ ++ idx = nv_rd32(dev, 0x100c90); ++ if (!(idx & 0x80000000)) ++ return; ++ idx &= 0x00ffffff; ++ ++ for (i = 0; i < 6; i++) { ++ nv_wr32(dev, 0x100c90, idx | i << 24); ++ trap[i] = nv_rd32(dev, 0x100c94); ++ } ++ nv_wr32(dev, 0x100c90, idx | 0x80000000); ++ ++ if (!display) ++ return; ++ ++ chinst = (trap[2] << 16) | trap[1]; ++ for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { ++ struct nouveau_channel *chan = dev_priv->fifos[ch]; ++ ++ if (!chan || !chan->ramin) ++ continue; ++ ++ if (chinst == chan->ramin->instance >> 12) ++ break; ++ } ++ ++ NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " ++ "channel %d (0x%08x)\n", ++ name, (trap[5] & 0x100 ? "read" : "write"), ++ trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, ++ trap[0], ch, chinst); ++} diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c -index e20c0e2..fb0281a 100644 +index e20c0e2..38dbcda 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c -@@ -28,41 +28,33 @@ +@@ -28,41 +28,35 @@ #include "drm.h" #include "nouveau_drv.h" @@ -9035,8 +11368,12 @@ index e20c0e2..fb0281a 100644 /* We never schedule channel 0 or 127 */ - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 1, nr = 0; i < 127; i++) { - if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) - nv_wo32(dev, cur->gpuobj, nr++, i); +- if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) +- nv_wo32(dev, cur->gpuobj, nr++, i); ++ if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) { ++ nv_wo32(cur->gpuobj, (nr * 4), i); ++ nr++; ++ } } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); @@ -9053,7 +11390,7 @@ index e20c0e2..fb0281a 100644 { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->fifos[channel]; -@@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) +@@ -70,37 +64,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) NV_DEBUG(dev, "ch%d\n", channel); @@ -9097,7 +11434,7 @@ index e20c0e2..fb0281a 100644 } static void -@@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) +@@ -133,12 +118,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { if (dev_priv->fifos[i]) @@ -9113,7 +11450,7 @@ index e20c0e2..fb0281a 100644 } static void -@@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev) +@@ -162,41 +147,38 @@ nv50_fifo_init_regs(struct drm_device *dev) nv_wr32(dev, 0x3270, 0); /* Enable dummy channels setup by nv50_instmem.c */ @@ -9167,7 +11504,7 @@ index e20c0e2..fb0281a 100644 return ret; } -@@ -216,18 +196,15 @@ void +@@ -216,18 +198,15 @@ void nv50_fifo_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -9190,7 +11527,7 @@ index e20c0e2..fb0281a 100644 } int -@@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) +@@ -248,7 +227,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); @@ -9199,31 +11536,50 @@ index e20c0e2..fb0281a 100644 uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start; uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start; -@@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) +@@ -281,39 +260,31 @@ nv50_fifo_create_context(struct nouveau_channel *chan) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - dev_priv->engine.instmem.prepare_access(dev, true); - - nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); +- nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); - nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); -+ nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ | -+ (4 << 24) /* SEARCH_FULL */ | -+ (chan->ramht->instance >> 4)); - nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); - nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); - nv_wo32(dev, ramfc, 0x40/4, 0x00000000); -@@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) - chan->dma.ib_base * 4); - nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16); - +- nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); +- nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); +- nv_wo32(dev, ramfc, 0x40/4, 0x00000000); +- nv_wo32(dev, ramfc, 0x7c/4, 0x30000001); +- nv_wo32(dev, ramfc, 0x78/4, 0x00000000); +- nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078); +- nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base + +- chan->dma.ib_base * 4); +- nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16); +- - if (!IS_G80) { +- nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); +- nv_wo32(dev, chan->ramin->gpuobj, 1, +- chan->ramfc->instance >> 8); +- +- nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10); +- nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12); ++ nv_wo32(ramfc, 0x48, chan->pushbuf->instance >> 4); ++ nv_wo32(ramfc, 0x80, (0 << 27) /* 4KiB */ | ++ (4 << 24) /* SEARCH_FULL */ | ++ (chan->ramht->instance >> 4)); ++ nv_wo32(ramfc, 0x44, 0x2101ffff); ++ nv_wo32(ramfc, 0x60, 0x7fffffff); ++ nv_wo32(ramfc, 0x40, 0x00000000); ++ nv_wo32(ramfc, 0x7c, 0x30000001); ++ nv_wo32(ramfc, 0x78, 0x00000000); ++ nv_wo32(ramfc, 0x3c, 0x403f6078); ++ nv_wo32(ramfc, 0x50, chan->pushbuf_base + chan->dma.ib_base * 4); ++ nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16); ++ + if (dev_priv->chipset != 0x50) { - nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); - nv_wo32(dev, chan->ramin->gpuobj, 1, - chan->ramfc->instance >> 8); -@@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) - nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12); ++ nv_wo32(chan->ramin->gpuobj, 0, chan->id); ++ nv_wo32(chan->ramin->gpuobj, 4, chan->ramfc->instance >> 8); ++ ++ nv_wo32(ramfc, 0x88, chan->cache->instance >> 10); ++ nv_wo32(ramfc, 0x98, chan->ramin->instance >> 12); } - dev_priv->engine.instmem.finish_access(dev); @@ -9257,26 +11613,106 @@ index e20c0e2..fb0281a 100644 nouveau_gpuobj_ref_del(dev, &ramfc); nouveau_gpuobj_ref_del(dev, &chan->cache); -@@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) +@@ -349,63 +321,59 @@ nv50_fifo_load_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - dev_priv->engine.instmem.prepare_access(dev, false); - - nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4)); - nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4)); - nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4)); -@@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan) +- nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4)); +- nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4)); +- nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4)); +- nv_wr32(dev, 0x3320, nv_ro32(dev, ramfc, 0x0c/4)); +- nv_wr32(dev, 0x3244, nv_ro32(dev, ramfc, 0x10/4)); +- nv_wr32(dev, 0x3328, nv_ro32(dev, ramfc, 0x14/4)); +- nv_wr32(dev, 0x3368, nv_ro32(dev, ramfc, 0x18/4)); +- nv_wr32(dev, 0x336c, nv_ro32(dev, ramfc, 0x1c/4)); +- nv_wr32(dev, 0x3370, nv_ro32(dev, ramfc, 0x20/4)); +- nv_wr32(dev, 0x3374, nv_ro32(dev, ramfc, 0x24/4)); +- nv_wr32(dev, 0x3378, nv_ro32(dev, ramfc, 0x28/4)); +- nv_wr32(dev, 0x337c, nv_ro32(dev, ramfc, 0x2c/4)); +- nv_wr32(dev, 0x3228, nv_ro32(dev, ramfc, 0x30/4)); +- nv_wr32(dev, 0x3364, nv_ro32(dev, ramfc, 0x34/4)); +- nv_wr32(dev, 0x32a0, nv_ro32(dev, ramfc, 0x38/4)); +- nv_wr32(dev, 0x3224, nv_ro32(dev, ramfc, 0x3c/4)); +- nv_wr32(dev, 0x324c, nv_ro32(dev, ramfc, 0x40/4)); +- nv_wr32(dev, 0x2044, nv_ro32(dev, ramfc, 0x44/4)); +- nv_wr32(dev, 0x322c, nv_ro32(dev, ramfc, 0x48/4)); +- nv_wr32(dev, 0x3234, nv_ro32(dev, ramfc, 0x4c/4)); +- nv_wr32(dev, 0x3340, nv_ro32(dev, ramfc, 0x50/4)); +- nv_wr32(dev, 0x3344, nv_ro32(dev, ramfc, 0x54/4)); +- nv_wr32(dev, 0x3280, nv_ro32(dev, ramfc, 0x58/4)); +- nv_wr32(dev, 0x3254, nv_ro32(dev, ramfc, 0x5c/4)); +- nv_wr32(dev, 0x3260, nv_ro32(dev, ramfc, 0x60/4)); +- nv_wr32(dev, 0x3264, nv_ro32(dev, ramfc, 0x64/4)); +- nv_wr32(dev, 0x3268, nv_ro32(dev, ramfc, 0x68/4)); +- nv_wr32(dev, 0x326c, nv_ro32(dev, ramfc, 0x6c/4)); +- nv_wr32(dev, 0x32e4, nv_ro32(dev, ramfc, 0x70/4)); +- nv_wr32(dev, 0x3248, nv_ro32(dev, ramfc, 0x74/4)); +- nv_wr32(dev, 0x2088, nv_ro32(dev, ramfc, 0x78/4)); +- nv_wr32(dev, 0x2058, nv_ro32(dev, ramfc, 0x7c/4)); +- nv_wr32(dev, 0x2210, nv_ro32(dev, ramfc, 0x80/4)); +- +- cnt = nv_ro32(dev, ramfc, 0x84/4); ++ nv_wr32(dev, 0x3330, nv_ro32(ramfc, 0x00)); ++ nv_wr32(dev, 0x3334, nv_ro32(ramfc, 0x04)); ++ nv_wr32(dev, 0x3240, nv_ro32(ramfc, 0x08)); ++ nv_wr32(dev, 0x3320, nv_ro32(ramfc, 0x0c)); ++ nv_wr32(dev, 0x3244, nv_ro32(ramfc, 0x10)); ++ nv_wr32(dev, 0x3328, nv_ro32(ramfc, 0x14)); ++ nv_wr32(dev, 0x3368, nv_ro32(ramfc, 0x18)); ++ nv_wr32(dev, 0x336c, nv_ro32(ramfc, 0x1c)); ++ nv_wr32(dev, 0x3370, nv_ro32(ramfc, 0x20)); ++ nv_wr32(dev, 0x3374, nv_ro32(ramfc, 0x24)); ++ nv_wr32(dev, 0x3378, nv_ro32(ramfc, 0x28)); ++ nv_wr32(dev, 0x337c, nv_ro32(ramfc, 0x2c)); ++ nv_wr32(dev, 0x3228, nv_ro32(ramfc, 0x30)); ++ nv_wr32(dev, 0x3364, nv_ro32(ramfc, 0x34)); ++ nv_wr32(dev, 0x32a0, nv_ro32(ramfc, 0x38)); ++ nv_wr32(dev, 0x3224, nv_ro32(ramfc, 0x3c)); ++ nv_wr32(dev, 0x324c, nv_ro32(ramfc, 0x40)); ++ nv_wr32(dev, 0x2044, nv_ro32(ramfc, 0x44)); ++ nv_wr32(dev, 0x322c, nv_ro32(ramfc, 0x48)); ++ nv_wr32(dev, 0x3234, nv_ro32(ramfc, 0x4c)); ++ nv_wr32(dev, 0x3340, nv_ro32(ramfc, 0x50)); ++ nv_wr32(dev, 0x3344, nv_ro32(ramfc, 0x54)); ++ nv_wr32(dev, 0x3280, nv_ro32(ramfc, 0x58)); ++ nv_wr32(dev, 0x3254, nv_ro32(ramfc, 0x5c)); ++ nv_wr32(dev, 0x3260, nv_ro32(ramfc, 0x60)); ++ nv_wr32(dev, 0x3264, nv_ro32(ramfc, 0x64)); ++ nv_wr32(dev, 0x3268, nv_ro32(ramfc, 0x68)); ++ nv_wr32(dev, 0x326c, nv_ro32(ramfc, 0x6c)); ++ nv_wr32(dev, 0x32e4, nv_ro32(ramfc, 0x70)); ++ nv_wr32(dev, 0x3248, nv_ro32(ramfc, 0x74)); ++ nv_wr32(dev, 0x2088, nv_ro32(ramfc, 0x78)); ++ nv_wr32(dev, 0x2058, nv_ro32(ramfc, 0x7c)); ++ nv_wr32(dev, 0x2210, nv_ro32(ramfc, 0x80)); ++ ++ cnt = nv_ro32(ramfc, 0x84); + for (ptr = 0; ptr < cnt; ptr++) { + nv_wr32(dev, NV40_PFIFO_CACHE1_METHOD(ptr), +- nv_ro32(dev, cache, (ptr * 2) + 0)); ++ nv_ro32(cache, (ptr * 8) + 0)); + nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr), +- nv_ro32(dev, cache, (ptr * 2) + 1)); ++ nv_ro32(cache, (ptr * 8) + 4)); + } + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2); nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); /* guessing that all the 0x34xx regs aren't on NV50 */ - if (!IS_G80) { +- nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4)); +- nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4)); +- nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4)); +- nv_wr32(dev, 0x3408, nv_ro32(dev, ramfc, 0x94/4)); +- nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4)); + if (dev_priv->chipset != 0x50) { - nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4)); - nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4)); - nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4)); -@@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) - nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4)); ++ nv_wr32(dev, 0x340c, nv_ro32(ramfc, 0x88)); ++ nv_wr32(dev, 0x3400, nv_ro32(ramfc, 0x8c)); ++ nv_wr32(dev, 0x3404, nv_ro32(ramfc, 0x90)); ++ nv_wr32(dev, 0x3408, nv_ro32(ramfc, 0x94)); ++ nv_wr32(dev, 0x3410, nv_ro32(ramfc, 0x98)); } - dev_priv->engine.instmem.finish_access(dev); @@ -9284,26 +11720,110 @@ index e20c0e2..fb0281a 100644 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } -@@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev) +@@ -434,64 +402,63 @@ nv50_fifo_unload_context(struct drm_device *dev) ramfc = chan->ramfc->gpuobj; cache = chan->cache->gpuobj; - dev_priv->engine.instmem.prepare_access(dev, true); - - nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330)); - nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334)); - nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240)); -@@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev) +- nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330)); +- nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334)); +- nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240)); +- nv_wo32(dev, ramfc, 0x0c/4, nv_rd32(dev, 0x3320)); +- nv_wo32(dev, ramfc, 0x10/4, nv_rd32(dev, 0x3244)); +- nv_wo32(dev, ramfc, 0x14/4, nv_rd32(dev, 0x3328)); +- nv_wo32(dev, ramfc, 0x18/4, nv_rd32(dev, 0x3368)); +- nv_wo32(dev, ramfc, 0x1c/4, nv_rd32(dev, 0x336c)); +- nv_wo32(dev, ramfc, 0x20/4, nv_rd32(dev, 0x3370)); +- nv_wo32(dev, ramfc, 0x24/4, nv_rd32(dev, 0x3374)); +- nv_wo32(dev, ramfc, 0x28/4, nv_rd32(dev, 0x3378)); +- nv_wo32(dev, ramfc, 0x2c/4, nv_rd32(dev, 0x337c)); +- nv_wo32(dev, ramfc, 0x30/4, nv_rd32(dev, 0x3228)); +- nv_wo32(dev, ramfc, 0x34/4, nv_rd32(dev, 0x3364)); +- nv_wo32(dev, ramfc, 0x38/4, nv_rd32(dev, 0x32a0)); +- nv_wo32(dev, ramfc, 0x3c/4, nv_rd32(dev, 0x3224)); +- nv_wo32(dev, ramfc, 0x40/4, nv_rd32(dev, 0x324c)); +- nv_wo32(dev, ramfc, 0x44/4, nv_rd32(dev, 0x2044)); +- nv_wo32(dev, ramfc, 0x48/4, nv_rd32(dev, 0x322c)); +- nv_wo32(dev, ramfc, 0x4c/4, nv_rd32(dev, 0x3234)); +- nv_wo32(dev, ramfc, 0x50/4, nv_rd32(dev, 0x3340)); +- nv_wo32(dev, ramfc, 0x54/4, nv_rd32(dev, 0x3344)); +- nv_wo32(dev, ramfc, 0x58/4, nv_rd32(dev, 0x3280)); +- nv_wo32(dev, ramfc, 0x5c/4, nv_rd32(dev, 0x3254)); +- nv_wo32(dev, ramfc, 0x60/4, nv_rd32(dev, 0x3260)); +- nv_wo32(dev, ramfc, 0x64/4, nv_rd32(dev, 0x3264)); +- nv_wo32(dev, ramfc, 0x68/4, nv_rd32(dev, 0x3268)); +- nv_wo32(dev, ramfc, 0x6c/4, nv_rd32(dev, 0x326c)); +- nv_wo32(dev, ramfc, 0x70/4, nv_rd32(dev, 0x32e4)); +- nv_wo32(dev, ramfc, 0x74/4, nv_rd32(dev, 0x3248)); +- nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088)); +- nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058)); +- nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210)); ++ nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330)); ++ nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334)); ++ nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240)); ++ nv_wo32(ramfc, 0x0c, nv_rd32(dev, 0x3320)); ++ nv_wo32(ramfc, 0x10, nv_rd32(dev, 0x3244)); ++ nv_wo32(ramfc, 0x14, nv_rd32(dev, 0x3328)); ++ nv_wo32(ramfc, 0x18, nv_rd32(dev, 0x3368)); ++ nv_wo32(ramfc, 0x1c, nv_rd32(dev, 0x336c)); ++ nv_wo32(ramfc, 0x20, nv_rd32(dev, 0x3370)); ++ nv_wo32(ramfc, 0x24, nv_rd32(dev, 0x3374)); ++ nv_wo32(ramfc, 0x28, nv_rd32(dev, 0x3378)); ++ nv_wo32(ramfc, 0x2c, nv_rd32(dev, 0x337c)); ++ nv_wo32(ramfc, 0x30, nv_rd32(dev, 0x3228)); ++ nv_wo32(ramfc, 0x34, nv_rd32(dev, 0x3364)); ++ nv_wo32(ramfc, 0x38, nv_rd32(dev, 0x32a0)); ++ nv_wo32(ramfc, 0x3c, nv_rd32(dev, 0x3224)); ++ nv_wo32(ramfc, 0x40, nv_rd32(dev, 0x324c)); ++ nv_wo32(ramfc, 0x44, nv_rd32(dev, 0x2044)); ++ nv_wo32(ramfc, 0x48, nv_rd32(dev, 0x322c)); ++ nv_wo32(ramfc, 0x4c, nv_rd32(dev, 0x3234)); ++ nv_wo32(ramfc, 0x50, nv_rd32(dev, 0x3340)); ++ nv_wo32(ramfc, 0x54, nv_rd32(dev, 0x3344)); ++ nv_wo32(ramfc, 0x58, nv_rd32(dev, 0x3280)); ++ nv_wo32(ramfc, 0x5c, nv_rd32(dev, 0x3254)); ++ nv_wo32(ramfc, 0x60, nv_rd32(dev, 0x3260)); ++ nv_wo32(ramfc, 0x64, nv_rd32(dev, 0x3264)); ++ nv_wo32(ramfc, 0x68, nv_rd32(dev, 0x3268)); ++ nv_wo32(ramfc, 0x6c, nv_rd32(dev, 0x326c)); ++ nv_wo32(ramfc, 0x70, nv_rd32(dev, 0x32e4)); ++ nv_wo32(ramfc, 0x74, nv_rd32(dev, 0x3248)); ++ nv_wo32(ramfc, 0x78, nv_rd32(dev, 0x2088)); ++ nv_wo32(ramfc, 0x7c, nv_rd32(dev, 0x2058)); ++ nv_wo32(ramfc, 0x80, nv_rd32(dev, 0x2210)); + + put = (nv_rd32(dev, NV03_PFIFO_CACHE1_PUT) & 0x7ff) >> 2; + get = (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) & 0x7ff) >> 2; + ptr = 0; + while (put != get) { +- nv_wo32(dev, cache, ptr++, +- nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get))); +- nv_wo32(dev, cache, ptr++, +- nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get))); ++ nv_wo32(cache, ptr + 0, ++ nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get))); ++ nv_wo32(cache, ptr + 4, ++ nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get))); + get = (get + 1) & 0x1ff; ++ ptr += 8; } /* guessing that all the 0x34xx regs aren't on NV50 */ - if (!IS_G80) { +- nv_wo32(dev, ramfc, 0x84/4, ptr >> 1); +- nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c)); +- nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400)); +- nv_wo32(dev, ramfc, 0x90/4, nv_rd32(dev, 0x3404)); +- nv_wo32(dev, ramfc, 0x94/4, nv_rd32(dev, 0x3408)); +- nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410)); + if (dev_priv->chipset != 0x50) { - nv_wo32(dev, ramfc, 0x84/4, ptr >> 1); - nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c)); - nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400)); -@@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev) - nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410)); ++ nv_wo32(ramfc, 0x84, ptr >> 3); ++ nv_wo32(ramfc, 0x88, nv_rd32(dev, 0x340c)); ++ nv_wo32(ramfc, 0x8c, nv_rd32(dev, 0x3400)); ++ nv_wo32(ramfc, 0x90, nv_rd32(dev, 0x3404)); ++ nv_wo32(ramfc, 0x94, nv_rd32(dev, 0x3408)); ++ nv_wo32(ramfc, 0x98, nv_rd32(dev, 0x3410)); } - dev_priv->engine.instmem.finish_access(dev); @@ -9355,7 +11875,7 @@ index bb47ad7..b2fab2b 100644 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c -index b203d06..1413028 100644 +index b203d06..17a8d78 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -30,8 +30,6 @@ @@ -9446,23 +11966,21 @@ index b203d06..1413028 100644 int hdr, ret; NV_DEBUG(dev, "ch%d\n", chan->id); -@@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) +@@ -223,32 +217,25 @@ nv50_graph_create_context(struct nouveau_channel *chan) NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); if (ret) return ret; - ctx = chan->ramin_grctx->gpuobj; -+ obj = chan->ramin_grctx->gpuobj; - +- - hdr = IS_G80 ? 0x200 : 0x20; - dev_priv->engine.instmem.prepare_access(dev, true); -+ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; - nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002); - nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + - pgraph->grctx_size - 1); -@@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan) - nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0); - nv_wo32(dev, ramin, (hdr + 0x10)/4, 0); - nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000); +- nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002); +- nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + +- pgraph->grctx_size - 1); +- nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance); +- nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0); +- nv_wo32(dev, ramin, (hdr + 0x10)/4, 0); +- nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); - - dev_priv->engine.instmem.prepare_access(dev, true); @@ -9477,14 +11995,24 @@ index b203d06..1413028 100644 - } - nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); - dev_priv->engine.instmem.finish_access(dev); - ++ obj = chan->ramin_grctx->gpuobj; ++ ++ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; ++ nv_wo32(ramin, hdr + 0x00, 0x00190002); ++ nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->instance + ++ pgraph->grctx_size - 1); ++ nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->instance); ++ nv_wo32(ramin, hdr + 0x0c, 0); ++ nv_wo32(ramin, hdr + 0x10, 0); ++ nv_wo32(ramin, hdr + 0x14, 0x00010000); ++ + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; + ctx.data = obj; + nv50_grctx_init(&ctx); + -+ nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12); -+ ++ nv_wo32(obj, 0x00000, chan->ramin->instance >> 12); + + dev_priv->engine.instmem.flush(dev); return 0; } @@ -9503,14 +12031,3813 @@ index b203d06..1413028 100644 - dev_priv->engine.instmem.prepare_access(dev, true); for (i = hdr; i < hdr + 24; i += 4) - nv_wo32(dev, chan->ramin->gpuobj, i/4, 0); +- nv_wo32(dev, chan->ramin->gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(chan->ramin->gpuobj, i, 0); + dev_priv->engine.instmem.flush(dev); nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); } +diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c +index 42a8fb2..336aab2 100644 +--- a/drivers/gpu/drm/nouveau/nv50_grctx.c ++++ b/drivers/gpu/drm/nouveau/nv50_grctx.c +@@ -103,6 +103,9 @@ + #include "nouveau_drv.h" + #include "nouveau_grctx.h" + ++#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) ++#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) ++ + /* + * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's + * the GPU itself that does context-switching, but it needs a special +@@ -182,6 +185,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx) + case 0xa8: + case 0xaa: + case 0xac: ++ case 0xaf: + break; + default: + NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for " +@@ -268,6 +272,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx) + */ + + static void ++nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx); ++ ++static void + nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +@@ -286,7 +293,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + gr_def(ctx, 0x400840, 0xffe806a8); + } + gr_def(ctx, 0x400844, 0x00000002); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) ++ if (IS_NVA3F(dev_priv->chipset)) + gr_def(ctx, 0x400894, 0x00001000); + gr_def(ctx, 0x4008e8, 0x00000003); + gr_def(ctx, 0x4008ec, 0x00001000); +@@ -299,13 +306,15 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + + if (dev_priv->chipset >= 0xa0) + cp_ctx(ctx, 0x400b00, 0x1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { ++ if (IS_NVA3F(dev_priv->chipset)) { + cp_ctx(ctx, 0x400b10, 0x1); + gr_def(ctx, 0x400b10, 0x0001629d); + cp_ctx(ctx, 0x400b20, 0x1); + gr_def(ctx, 0x400b20, 0x0001629d); + } + ++ nv50_graph_construct_mmio_ddata(ctx); ++ + /* 0C00: VFETCH */ + cp_ctx(ctx, 0x400c08, 0x2); + gr_def(ctx, 0x400c08, 0x0000fe0c); +@@ -314,7 +323,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + if (dev_priv->chipset < 0xa0) { + cp_ctx(ctx, 0x401008, 0x4); + gr_def(ctx, 0x401014, 0x00001000); +- } else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) { ++ } else if (!IS_NVA3F(dev_priv->chipset)) { + cp_ctx(ctx, 0x401008, 0x5); + gr_def(ctx, 0x401018, 0x00001000); + } else { +@@ -368,10 +377,13 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + case 0xa3: + case 0xa5: + case 0xa8: ++ case 0xaf: + gr_def(ctx, 0x401c00, 0x142500df); + break; + } + ++ /* 2000 */ ++ + /* 2400 */ + cp_ctx(ctx, 0x402400, 0x1); + if (dev_priv->chipset == 0x50) +@@ -380,12 +392,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + cp_ctx(ctx, 0x402408, 0x2); + gr_def(ctx, 0x402408, 0x00000600); + +- /* 2800 */ ++ /* 2800: CSCHED */ + cp_ctx(ctx, 0x402800, 0x1); + if (dev_priv->chipset == 0x50) + gr_def(ctx, 0x402800, 0x00000006); + +- /* 2C00 */ ++ /* 2C00: ZCULL */ + cp_ctx(ctx, 0x402c08, 0x6); + if (dev_priv->chipset != 0x50) + gr_def(ctx, 0x402c14, 0x01000000); +@@ -396,23 +408,23 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + cp_ctx(ctx, 0x402ca0, 0x2); + if (dev_priv->chipset < 0xa0) + gr_def(ctx, 0x402ca0, 0x00000400); +- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) ++ else if (!IS_NVA3F(dev_priv->chipset)) + gr_def(ctx, 0x402ca0, 0x00000800); + else + gr_def(ctx, 0x402ca0, 0x00000400); + cp_ctx(ctx, 0x402cac, 0x4); + +- /* 3000 */ ++ /* 3000: ENG2D */ + cp_ctx(ctx, 0x403004, 0x1); + gr_def(ctx, 0x403004, 0x00000001); + +- /* 3404 */ ++ /* 3400 */ + if (dev_priv->chipset >= 0xa0) { + cp_ctx(ctx, 0x403404, 0x1); + gr_def(ctx, 0x403404, 0x00000001); + } + +- /* 5000 */ ++ /* 5000: CCACHE */ + cp_ctx(ctx, 0x405000, 0x1); + switch (dev_priv->chipset) { + case 0x50: +@@ -425,6 +437,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + case 0xa8: + case 0xaa: + case 0xac: ++ case 0xaf: + gr_def(ctx, 0x405000, 0x000e0080); + break; + case 0x86: +@@ -441,210 +454,6 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + cp_ctx(ctx, 0x405024, 0x1); + cp_ctx(ctx, 0x40502c, 0x1); + +- /* 5400 or maybe 4800 */ +- if (dev_priv->chipset == 0x50) { +- offset = 0x405400; +- cp_ctx(ctx, 0x405400, 0xea); +- } else if (dev_priv->chipset < 0x94) { +- offset = 0x405400; +- cp_ctx(ctx, 0x405400, 0xcb); +- } else if (dev_priv->chipset < 0xa0) { +- offset = 0x405400; +- cp_ctx(ctx, 0x405400, 0xcc); +- } else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- offset = 0x404800; +- cp_ctx(ctx, 0x404800, 0xda); +- } else { +- offset = 0x405400; +- cp_ctx(ctx, 0x405400, 0xd4); +- } +- gr_def(ctx, offset + 0x0c, 0x00000002); +- gr_def(ctx, offset + 0x10, 0x00000001); +- if (dev_priv->chipset >= 0x94) +- offset += 4; +- gr_def(ctx, offset + 0x1c, 0x00000001); +- gr_def(ctx, offset + 0x20, 0x00000100); +- gr_def(ctx, offset + 0x38, 0x00000002); +- gr_def(ctx, offset + 0x3c, 0x00000001); +- gr_def(ctx, offset + 0x40, 0x00000001); +- gr_def(ctx, offset + 0x50, 0x00000001); +- gr_def(ctx, offset + 0x54, 0x003fffff); +- gr_def(ctx, offset + 0x58, 0x00001fff); +- gr_def(ctx, offset + 0x60, 0x00000001); +- gr_def(ctx, offset + 0x64, 0x00000001); +- gr_def(ctx, offset + 0x6c, 0x00000001); +- gr_def(ctx, offset + 0x70, 0x00000001); +- gr_def(ctx, offset + 0x74, 0x00000001); +- gr_def(ctx, offset + 0x78, 0x00000004); +- gr_def(ctx, offset + 0x7c, 0x00000001); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- offset += 4; +- gr_def(ctx, offset + 0x80, 0x00000001); +- gr_def(ctx, offset + 0x84, 0x00000001); +- gr_def(ctx, offset + 0x88, 0x00000007); +- gr_def(ctx, offset + 0x8c, 0x00000001); +- gr_def(ctx, offset + 0x90, 0x00000007); +- gr_def(ctx, offset + 0x94, 0x00000001); +- gr_def(ctx, offset + 0x98, 0x00000001); +- gr_def(ctx, offset + 0x9c, 0x00000001); +- if (dev_priv->chipset == 0x50) { +- gr_def(ctx, offset + 0xb0, 0x00000001); +- gr_def(ctx, offset + 0xb4, 0x00000001); +- gr_def(ctx, offset + 0xbc, 0x00000001); +- gr_def(ctx, offset + 0xc0, 0x0000000a); +- gr_def(ctx, offset + 0xd0, 0x00000040); +- gr_def(ctx, offset + 0xd8, 0x00000002); +- gr_def(ctx, offset + 0xdc, 0x00000100); +- gr_def(ctx, offset + 0xe0, 0x00000001); +- gr_def(ctx, offset + 0xe4, 0x00000100); +- gr_def(ctx, offset + 0x100, 0x00000001); +- gr_def(ctx, offset + 0x124, 0x00000004); +- gr_def(ctx, offset + 0x13c, 0x00000001); +- gr_def(ctx, offset + 0x140, 0x00000100); +- gr_def(ctx, offset + 0x148, 0x00000001); +- gr_def(ctx, offset + 0x154, 0x00000100); +- gr_def(ctx, offset + 0x158, 0x00000001); +- gr_def(ctx, offset + 0x15c, 0x00000100); +- gr_def(ctx, offset + 0x164, 0x00000001); +- gr_def(ctx, offset + 0x170, 0x00000100); +- gr_def(ctx, offset + 0x174, 0x00000001); +- gr_def(ctx, offset + 0x17c, 0x00000001); +- gr_def(ctx, offset + 0x188, 0x00000002); +- gr_def(ctx, offset + 0x190, 0x00000001); +- gr_def(ctx, offset + 0x198, 0x00000001); +- gr_def(ctx, offset + 0x1ac, 0x00000003); +- offset += 0xd0; +- } else { +- gr_def(ctx, offset + 0xb0, 0x00000001); +- gr_def(ctx, offset + 0xb4, 0x00000100); +- gr_def(ctx, offset + 0xbc, 0x00000001); +- gr_def(ctx, offset + 0xc8, 0x00000100); +- gr_def(ctx, offset + 0xcc, 0x00000001); +- gr_def(ctx, offset + 0xd0, 0x00000100); +- gr_def(ctx, offset + 0xd8, 0x00000001); +- gr_def(ctx, offset + 0xe4, 0x00000100); +- } +- gr_def(ctx, offset + 0xf8, 0x00000004); +- gr_def(ctx, offset + 0xfc, 0x00000070); +- gr_def(ctx, offset + 0x100, 0x00000080); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- offset += 4; +- gr_def(ctx, offset + 0x114, 0x0000000c); +- if (dev_priv->chipset == 0x50) +- offset -= 4; +- gr_def(ctx, offset + 0x11c, 0x00000008); +- gr_def(ctx, offset + 0x120, 0x00000014); +- if (dev_priv->chipset == 0x50) { +- gr_def(ctx, offset + 0x124, 0x00000026); +- offset -= 0x18; +- } else { +- gr_def(ctx, offset + 0x128, 0x00000029); +- gr_def(ctx, offset + 0x12c, 0x00000027); +- gr_def(ctx, offset + 0x130, 0x00000026); +- gr_def(ctx, offset + 0x134, 0x00000008); +- gr_def(ctx, offset + 0x138, 0x00000004); +- gr_def(ctx, offset + 0x13c, 0x00000027); +- } +- gr_def(ctx, offset + 0x148, 0x00000001); +- gr_def(ctx, offset + 0x14c, 0x00000002); +- gr_def(ctx, offset + 0x150, 0x00000003); +- gr_def(ctx, offset + 0x154, 0x00000004); +- gr_def(ctx, offset + 0x158, 0x00000005); +- gr_def(ctx, offset + 0x15c, 0x00000006); +- gr_def(ctx, offset + 0x160, 0x00000007); +- gr_def(ctx, offset + 0x164, 0x00000001); +- gr_def(ctx, offset + 0x1a8, 0x000000cf); +- if (dev_priv->chipset == 0x50) +- offset -= 4; +- gr_def(ctx, offset + 0x1d8, 0x00000080); +- gr_def(ctx, offset + 0x1dc, 0x00000004); +- gr_def(ctx, offset + 0x1e0, 0x00000004); +- if (dev_priv->chipset == 0x50) +- offset -= 4; +- else +- gr_def(ctx, offset + 0x1e4, 0x00000003); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- gr_def(ctx, offset + 0x1ec, 0x00000003); +- offset += 8; +- } +- gr_def(ctx, offset + 0x1e8, 0x00000001); +- if (dev_priv->chipset == 0x50) +- offset -= 4; +- gr_def(ctx, offset + 0x1f4, 0x00000012); +- gr_def(ctx, offset + 0x1f8, 0x00000010); +- gr_def(ctx, offset + 0x1fc, 0x0000000c); +- gr_def(ctx, offset + 0x200, 0x00000001); +- gr_def(ctx, offset + 0x210, 0x00000004); +- gr_def(ctx, offset + 0x214, 0x00000002); +- gr_def(ctx, offset + 0x218, 0x00000004); +- if (dev_priv->chipset >= 0xa0) +- offset += 4; +- gr_def(ctx, offset + 0x224, 0x003fffff); +- gr_def(ctx, offset + 0x228, 0x00001fff); +- if (dev_priv->chipset == 0x50) +- offset -= 0x20; +- else if (dev_priv->chipset >= 0xa0) { +- gr_def(ctx, offset + 0x250, 0x00000001); +- gr_def(ctx, offset + 0x254, 0x00000001); +- gr_def(ctx, offset + 0x258, 0x00000002); +- offset += 0x10; +- } +- gr_def(ctx, offset + 0x250, 0x00000004); +- gr_def(ctx, offset + 0x254, 0x00000014); +- gr_def(ctx, offset + 0x258, 0x00000001); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- offset += 4; +- gr_def(ctx, offset + 0x264, 0x00000002); +- if (dev_priv->chipset >= 0xa0) +- offset += 8; +- gr_def(ctx, offset + 0x270, 0x00000001); +- gr_def(ctx, offset + 0x278, 0x00000002); +- gr_def(ctx, offset + 0x27c, 0x00001000); +- if (dev_priv->chipset == 0x50) +- offset -= 0xc; +- else { +- gr_def(ctx, offset + 0x280, 0x00000e00); +- gr_def(ctx, offset + 0x284, 0x00001000); +- gr_def(ctx, offset + 0x288, 0x00001e00); +- } +- gr_def(ctx, offset + 0x290, 0x00000001); +- gr_def(ctx, offset + 0x294, 0x00000001); +- gr_def(ctx, offset + 0x298, 0x00000001); +- gr_def(ctx, offset + 0x29c, 0x00000001); +- gr_def(ctx, offset + 0x2a0, 0x00000001); +- gr_def(ctx, offset + 0x2b0, 0x00000200); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- gr_def(ctx, offset + 0x2b4, 0x00000200); +- offset += 4; +- } +- if (dev_priv->chipset < 0xa0) { +- gr_def(ctx, offset + 0x2b8, 0x00000001); +- gr_def(ctx, offset + 0x2bc, 0x00000070); +- gr_def(ctx, offset + 0x2c0, 0x00000080); +- gr_def(ctx, offset + 0x2cc, 0x00000001); +- gr_def(ctx, offset + 0x2d0, 0x00000070); +- gr_def(ctx, offset + 0x2d4, 0x00000080); +- } else { +- gr_def(ctx, offset + 0x2b8, 0x00000001); +- gr_def(ctx, offset + 0x2bc, 0x000000f0); +- gr_def(ctx, offset + 0x2c0, 0x000000ff); +- gr_def(ctx, offset + 0x2cc, 0x00000001); +- gr_def(ctx, offset + 0x2d0, 0x000000f0); +- gr_def(ctx, offset + 0x2d4, 0x000000ff); +- gr_def(ctx, offset + 0x2dc, 0x00000009); +- offset += 4; +- } +- gr_def(ctx, offset + 0x2e4, 0x00000001); +- gr_def(ctx, offset + 0x2e8, 0x000000cf); +- gr_def(ctx, offset + 0x2f0, 0x00000001); +- gr_def(ctx, offset + 0x300, 0x000000cf); +- gr_def(ctx, offset + 0x308, 0x00000002); +- gr_def(ctx, offset + 0x310, 0x00000001); +- gr_def(ctx, offset + 0x318, 0x00000001); +- gr_def(ctx, offset + 0x320, 0x000000cf); +- gr_def(ctx, offset + 0x324, 0x000000cf); +- gr_def(ctx, offset + 0x328, 0x00000001); +- + /* 6000? */ + if (dev_priv->chipset == 0x50) + cp_ctx(ctx, 0x4063e0, 0x1); +@@ -661,7 +470,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + gr_def(ctx, 0x406818, 0x00000f80); + else + gr_def(ctx, 0x406818, 0x00001f80); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) ++ if (IS_NVA3F(dev_priv->chipset)) + gr_def(ctx, 0x40681c, 0x00000030); + cp_ctx(ctx, 0x406830, 0x3); + } +@@ -706,7 +515,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + + if (dev_priv->chipset < 0xa0) + cp_ctx(ctx, 0x407094 + (i<<8), 1); +- else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) ++ else if (!IS_NVA3F(dev_priv->chipset)) + cp_ctx(ctx, 0x407094 + (i<<8), 3); + else { + cp_ctx(ctx, 0x407094 + (i<<8), 4); +@@ -799,6 +608,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + case 0xa8: + case 0xaa: + case 0xac: ++ case 0xaf: + gr_def(ctx, offset + 0x1c, 0x300c0000); + break; + } +@@ -825,7 +635,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + gr_def(ctx, base + 0x304, 0x00007070); + else if (dev_priv->chipset < 0xa0) + gr_def(ctx, base + 0x304, 0x00027070); +- else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) ++ else if (!IS_NVA3F(dev_priv->chipset)) + gr_def(ctx, base + 0x304, 0x01127070); + else + gr_def(ctx, base + 0x304, 0x05127070); +@@ -849,7 +659,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + if (dev_priv->chipset < 0xa0) { + cp_ctx(ctx, base + 0x340, 9); + offset = base + 0x340; +- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) { ++ } else if (!IS_NVA3F(dev_priv->chipset)) { + cp_ctx(ctx, base + 0x33c, 0xb); + offset = base + 0x344; + } else { +@@ -880,7 +690,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + gr_def(ctx, offset + 0x0, 0x000001f0); + gr_def(ctx, offset + 0x4, 0x00000001); + gr_def(ctx, offset + 0x8, 0x00000003); +- if (dev_priv->chipset == 0x50 || dev_priv->chipset >= 0xaa) ++ if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset)) + gr_def(ctx, offset + 0xc, 0x00008000); + gr_def(ctx, offset + 0x14, 0x00039e00); + cp_ctx(ctx, offset + 0x1c, 2); +@@ -892,7 +702,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + + if (dev_priv->chipset >= 0xa0) { + cp_ctx(ctx, base + 0x54c, 2); +- if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) ++ if (!IS_NVA3F(dev_priv->chipset)) + gr_def(ctx, base + 0x54c, 0x003fe006); + else + gr_def(ctx, base + 0x54c, 0x003fe007); +@@ -948,6 +758,336 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + } + } + ++static void ++dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) { ++ int i; ++ if (val && ctx->mode == NOUVEAU_GRCTX_VALS) ++ for (i = 0; i < num; i++) ++ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); ++ ctx->ctxvals_pos += num; ++} ++ ++static void ++nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx) ++{ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ int base, num; ++ base = ctx->ctxvals_pos; ++ ++ /* tesla state */ ++ dd_emit(ctx, 1, 0); /* 00000001 UNK0F90 */ ++ dd_emit(ctx, 1, 0); /* 00000001 UNK135C */ ++ ++ /* SRC_TIC state */ ++ dd_emit(ctx, 1, 0); /* 00000007 SRC_TILE_MODE_Z */ ++ dd_emit(ctx, 1, 2); /* 00000007 SRC_TILE_MODE_Y */ ++ dd_emit(ctx, 1, 1); /* 00000001 SRC_LINEAR #1 */ ++ dd_emit(ctx, 1, 0); /* 000000ff SRC_ADDRESS_HIGH */ ++ dd_emit(ctx, 1, 0); /* 00000001 SRC_SRGB */ ++ if (dev_priv->chipset >= 0x94) ++ dd_emit(ctx, 1, 0); /* 00000003 eng2d UNK0258 */ ++ dd_emit(ctx, 1, 1); /* 00000fff SRC_DEPTH */ ++ dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */ ++ ++ /* turing state */ ++ dd_emit(ctx, 1, 0); /* 0000000f TEXTURES_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 0000000f SAMPLERS_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */ ++ dd_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */ ++ dd_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */ ++ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */ ++ dd_emit(ctx, 1, 1); /* 0000ffff BLOCK_ALLOC_THREADS */ ++ dd_emit(ctx, 1, 1); /* 00000001 LANES32 */ ++ dd_emit(ctx, 1, 0); /* 000000ff UNK370 */ ++ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_UNK */ ++ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_COUNT */ ++ dd_emit(ctx, 1, 1); /* 000000ff UNK384 bits 8-15 */ ++ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ ++ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ ++ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */ ++ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_X */ ++ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_XMY */ ++ dd_emit(ctx, 1, 0); /* 00000001 BLOCKDIM_XMY_OVERFLOW */ ++ dd_emit(ctx, 1, 1); /* 0003ffff BLOCKDIM_XMYMZ */ ++ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_Y */ ++ dd_emit(ctx, 1, 1); /* 0000007f BLOCKDIM_Z */ ++ dd_emit(ctx, 1, 4); /* 000000ff CP_REG_ALLOC_TEMP */ ++ dd_emit(ctx, 1, 1); /* 00000001 BLOCKDIM_DIRTY */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ dd_emit(ctx, 1, 0); /* 00000003 UNK03E8 */ ++ dd_emit(ctx, 1, 1); /* 0000007f BLOCK_ALLOC_HALFWARPS */ ++ dd_emit(ctx, 1, 1); /* 00000007 LOCAL_WARPS_NO_CLAMP */ ++ dd_emit(ctx, 1, 7); /* 00000007 LOCAL_WARPS_LOG_ALLOC */ ++ dd_emit(ctx, 1, 1); /* 00000007 STACK_WARPS_NO_CLAMP */ ++ dd_emit(ctx, 1, 7); /* 00000007 STACK_WARPS_LOG_ALLOC */ ++ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */ ++ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */ ++ dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */ ++ ++ /* compat 2d state */ ++ if (dev_priv->chipset == 0x50) { ++ dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */ ++ ++ dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */ ++ ++ dd_emit(ctx, 1, 1); /* ffffffff pattern COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff pattern SHAPE */ ++ dd_emit(ctx, 1, 1); /* ffffffff pattern PATTERN_SELECT */ ++ ++ dd_emit(ctx, 1, 0xa); /* ffffffff surf2d SRC_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff surf2d DMA_SRC */ ++ dd_emit(ctx, 1, 0); /* 000000ff surf2d SRC_ADDRESS_HIGH */ ++ dd_emit(ctx, 1, 0); /* ffffffff surf2d SRC_ADDRESS_LOW */ ++ dd_emit(ctx, 1, 0x40); /* 0000ffff surf2d SRC_PITCH */ ++ dd_emit(ctx, 1, 0); /* 0000000f surf2d SRC_TILE_MODE_Z */ ++ dd_emit(ctx, 1, 2); /* 0000000f surf2d SRC_TILE_MODE_Y */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_HEIGHT */ ++ dd_emit(ctx, 1, 1); /* 00000001 surf2d SRC_LINEAR */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_WIDTH */ ++ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_X */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_Y */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_X */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_Y */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_X */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_Y */ ++ dd_emit(ctx, 1, 1); /* ffffffff gdirect COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff gdirect OPERATION */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_X */ ++ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_Y */ ++ ++ dd_emit(ctx, 1, 0); /* 0000ffff blit SRC_Y */ ++ dd_emit(ctx, 1, 0); /* ffffffff blit OPERATION */ ++ ++ dd_emit(ctx, 1, 0); /* ffffffff ifc OPERATION */ ++ ++ dd_emit(ctx, 1, 0); /* ffffffff iifc INDEX_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff iifc LUT_OFFSET */ ++ dd_emit(ctx, 1, 4); /* ffffffff iifc COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff iifc OPERATION */ ++ } ++ ++ /* m2mf state */ ++ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_COUNT */ ++ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_LENGTH_IN */ ++ dd_emit(ctx, 2, 0); /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */ ++ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_OUT */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_OUT */ ++ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_OUT_Z */ ++ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_OUT */ ++ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_OUT */ ++ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_IN */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_IN */ ++ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_IN_Z */ ++ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_IN */ ++ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_IN_X, Y */ ++ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */ ++ ++ /* more compat 2d state */ ++ if (dev_priv->chipset == 0x50) { ++ dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */ ++ ++ dd_emit(ctx, 1, 1); /* ffffffff triangle COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff triangle OPERATION */ ++ ++ dd_emit(ctx, 1, 0); /* 0000000f sifm TILE_MODE_Z */ ++ dd_emit(ctx, 1, 2); /* 0000000f sifm TILE_MODE_Y */ ++ dd_emit(ctx, 1, 0); /* 000000ff sifm FORMAT_FILTER */ ++ dd_emit(ctx, 1, 1); /* 000000ff sifm FORMAT_ORIGIN */ ++ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_PITCH */ ++ dd_emit(ctx, 1, 1); /* 00000001 sifm SRC_LINEAR */ ++ dd_emit(ctx, 1, 0); /* 000000ff sifm SRC_OFFSET_HIGH */ ++ dd_emit(ctx, 1, 0); /* ffffffff sifm SRC_OFFSET */ ++ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_HEIGHT */ ++ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_WIDTH */ ++ dd_emit(ctx, 1, 3); /* ffffffff sifm COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff sifm OPERATION */ ++ ++ dd_emit(ctx, 1, 0); /* ffffffff sifc OPERATION */ ++ } ++ ++ /* tesla state */ ++ dd_emit(ctx, 1, 0); /* 0000000f GP_TEXTURES_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 0000000f GP_SAMPLERS_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* ffffffff */ ++ dd_emit(ctx, 1, 4); /* 000000ff UNK12B0_0 */ ++ dd_emit(ctx, 1, 0x70); /* 000000ff UNK12B0_1 */ ++ dd_emit(ctx, 1, 0x80); /* 000000ff UNK12B0_3 */ ++ dd_emit(ctx, 1, 0); /* 000000ff UNK12B0_2 */ ++ dd_emit(ctx, 1, 0); /* 0000000f FP_TEXTURES_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 0000000f FP_SAMPLERS_LOG2 */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ dd_emit(ctx, 1, 0); /* ffffffff */ ++ dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */ ++ } else { ++ dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */ ++ } ++ dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */ ++ if (dev_priv->chipset != 0x50) ++ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */ ++ dd_emit(ctx, 1, 8); /* 000000ff SEMANTIC_COLOR.COLR_NR */ ++ dd_emit(ctx, 1, 0x14); /* 000000ff SEMANTIC_COLOR.FFC0_ID */ ++ if (dev_priv->chipset == 0x50) { ++ dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */ ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ } else { ++ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_PTSZ.ENABLE */ ++ dd_emit(ctx, 1, 0x29); /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */ ++ dd_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM */ ++ dd_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ ++ dd_emit(ctx, 1, 8); /* 0000000f SMENATIC_CLIP.CLIP_HIGH */ ++ dd_emit(ctx, 1, 4); /* 000000ff SEMANTIC_CLIP.CLIP_LO */ ++ dd_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */ ++ dd_emit(ctx, 1, 0); /* 00000001 UNK1900 */ ++ } ++ dd_emit(ctx, 1, 0); /* 00000007 RT_CONTROL_MAP0 */ ++ dd_emit(ctx, 1, 1); /* 00000007 RT_CONTROL_MAP1 */ ++ dd_emit(ctx, 1, 2); /* 00000007 RT_CONTROL_MAP2 */ ++ dd_emit(ctx, 1, 3); /* 00000007 RT_CONTROL_MAP3 */ ++ dd_emit(ctx, 1, 4); /* 00000007 RT_CONTROL_MAP4 */ ++ dd_emit(ctx, 1, 5); /* 00000007 RT_CONTROL_MAP5 */ ++ dd_emit(ctx, 1, 6); /* 00000007 RT_CONTROL_MAP6 */ ++ dd_emit(ctx, 1, 7); /* 00000007 RT_CONTROL_MAP7 */ ++ dd_emit(ctx, 1, 1); /* 0000000f RT_CONTROL_COUNT */ ++ dd_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_UNK */ ++ dd_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */ ++ dd_emit(ctx, 1, 0xcf); /* 000000ff RT_FORMAT */ ++ dd_emit(ctx, 7, 0); /* 000000ff RT_FORMAT */ ++ if (dev_priv->chipset != 0x50) ++ dd_emit(ctx, 3, 0); /* 1, 1, 1 */ ++ else ++ dd_emit(ctx, 2, 0); /* 1, 1 */ ++ dd_emit(ctx, 1, 0); /* ffffffff GP_ENABLE */ ++ dd_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/ ++ dd_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ ++ dd_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ dd_emit(ctx, 1, 3); /* 00000003 */ ++ dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */ ++ } ++ if (dev_priv->chipset != 0x50) ++ dd_emit(ctx, 1, 3); /* 00000003 UNK15AC */ ++ dd_emit(ctx, 1, 1); /* ffffffff RASTERIZE_ENABLE */ ++ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.EXPORTS_Z */ ++ if (dev_priv->chipset != 0x50) ++ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */ ++ dd_emit(ctx, 1, 0x12); /* 000000ff FP_INTERPOLANT_CTRL.COUNT */ ++ dd_emit(ctx, 1, 0x10); /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */ ++ dd_emit(ctx, 1, 0xc); /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */ ++ dd_emit(ctx, 1, 1); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */ ++ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */ ++ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */ ++ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */ ++ dd_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */ ++ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */ ++ dd_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ ++ if (dev_priv->chipset >= 0xa0) ++ dd_emit(ctx, 1, 0); /* ffffffff */ ++ dd_emit(ctx, 1, 0); /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */ ++ dd_emit(ctx, 1, 0); /* ffffffff STRMOUT_ENABLE */ ++ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ ++ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ ++ dd_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE*/ ++ if (dev_priv->chipset != 0x50) ++ dd_emit(ctx, 8, 0); /* 00000001 */ ++ if (dev_priv->chipset >= 0xa0) { ++ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.COMP */ ++ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.SIZE */ ++ dd_emit(ctx, 1, 2); /* 00000007 VTX_ATTR_DEFINE.TYPE */ ++ dd_emit(ctx, 1, 0); /* 000000ff VTX_ATTR_DEFINE.ATTR */ ++ } ++ dd_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ dd_emit(ctx, 1, 0x14); /* 0000001f ZETA_FORMAT */ ++ dd_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ dd_emit(ctx, 1, 0); /* 0000000f VP_TEXTURES_LOG2 */ ++ dd_emit(ctx, 1, 0); /* 0000000f VP_SAMPLERS_LOG2 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */ ++ if (dev_priv->chipset >= 0xa0) ++ dd_emit(ctx, 1, 0); /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */ ++ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */ ++ if (dev_priv->chipset >= 0xa0) ++ dd_emit(ctx, 1, 0); /* 00000003 */ ++ dd_emit(ctx, 1, 0); /* 00000001 CULL_FACE_ENABLE */ ++ dd_emit(ctx, 1, 1); /* 00000003 CULL_FACE */ ++ dd_emit(ctx, 1, 0); /* 00000001 FRONT_FACE */ ++ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_FRONT */ ++ dd_emit(ctx, 1, 0x1000); /* 00007fff UNK141C */ ++ if (dev_priv->chipset != 0x50) { ++ dd_emit(ctx, 1, 0xe00); /* 7fff */ ++ dd_emit(ctx, 1, 0x1000); /* 7fff */ ++ dd_emit(ctx, 1, 0x1e00); /* 7fff */ ++ } ++ dd_emit(ctx, 1, 0); /* 00000001 BEGIN_END_ACTIVE */ ++ dd_emit(ctx, 1, 1); /* 00000001 POLYGON_MODE_??? */ ++ dd_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */ ++ dd_emit(ctx, 1, 1); /* 000000ff FP_REG_ALLOC_TEMP... without /4? */ ++ dd_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */ ++ dd_emit(ctx, 1, 1); /* 00000001 */ ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */ ++ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */ ++ dd_emit(ctx, 1, 0x200); /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ dd_emit(ctx, 1, 0x200); ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ if (dev_priv->chipset < 0xa0) { ++ dd_emit(ctx, 1, 1); /* 00000001 */ ++ dd_emit(ctx, 1, 0x70); /* 000000ff */ ++ dd_emit(ctx, 1, 0x80); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ dd_emit(ctx, 1, 1); /* 00000001 */ ++ dd_emit(ctx, 1, 0x70); /* 000000ff */ ++ dd_emit(ctx, 1, 0x80); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 000000ff */ ++ } else { ++ dd_emit(ctx, 1, 1); /* 00000001 */ ++ dd_emit(ctx, 1, 0xf0); /* 000000ff */ ++ dd_emit(ctx, 1, 0xff); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 00000001 */ ++ dd_emit(ctx, 1, 1); /* 00000001 */ ++ dd_emit(ctx, 1, 0xf0); /* 000000ff */ ++ dd_emit(ctx, 1, 0xff); /* 000000ff */ ++ dd_emit(ctx, 1, 0); /* 000000ff */ ++ dd_emit(ctx, 1, 9); /* 0000003f UNK114C.COMP,SIZE */ ++ } ++ ++ /* eng2d state */ ++ dd_emit(ctx, 1, 0); /* 00000001 eng2d COLOR_KEY_ENABLE */ ++ dd_emit(ctx, 1, 0); /* 00000007 eng2d COLOR_KEY_FORMAT */ ++ dd_emit(ctx, 1, 1); /* ffffffff eng2d DST_DEPTH */ ++ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DST_FORMAT */ ++ dd_emit(ctx, 1, 0); /* ffffffff eng2d DST_LAYER */ ++ dd_emit(ctx, 1, 1); /* 00000001 eng2d DST_LINEAR */ ++ dd_emit(ctx, 1, 0); /* 00000007 eng2d PATTERN_COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0); /* 00000007 eng2d OPERATION */ ++ dd_emit(ctx, 1, 0); /* 00000003 eng2d PATTERN_SELECT */ ++ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SIFC_FORMAT */ ++ dd_emit(ctx, 1, 0); /* 00000001 eng2d SIFC_BITMAP_ENABLE */ ++ dd_emit(ctx, 1, 2); /* 00000003 eng2d SIFC_BITMAP_UNK808 */ ++ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DU_DX_FRACT */ ++ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DU_DX_INT */ ++ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DV_DY_FRACT */ ++ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DV_DY_INT */ ++ dd_emit(ctx, 1, 0); /* 00000001 eng2d BLIT_CONTROL_FILTER */ ++ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DRAW_COLOR_FORMAT */ ++ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SRC_FORMAT */ ++ dd_emit(ctx, 1, 1); /* 00000001 eng2d SRC_LINEAR #2 */ ++ ++ num = ctx->ctxvals_pos - base; ++ ctx->ctxvals_pos = base; ++ if (IS_NVA3F(dev_priv->chipset)) ++ cp_ctx(ctx, 0x404800, num); ++ else ++ cp_ctx(ctx, 0x405400, num); ++} ++ + /* + * xfer areas. These are a pain. + * +@@ -990,28 +1130,33 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) + * without the help of ctxprog. + */ + +-static inline void ++static void + xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) { + int i; + if (val && ctx->mode == NOUVEAU_GRCTX_VALS) + for (i = 0; i < num; i++) +- nv_wo32(ctx->dev, ctx->data, ctx->ctxvals_pos + (i << 3), val); ++ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + ctx->ctxvals_pos += num << 3; + } + + /* Gene declarations... */ + ++static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx); + static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx); +-static void nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx); ++static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx); + static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx); + static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx); + +@@ -1030,102 +1175,32 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) + if (dev_priv->chipset < 0xa0) { + /* Strand 0 */ + ctx->ctxvals_pos = offset; +- switch (dev_priv->chipset) { +- case 0x50: +- xf_emit(ctx, 0x99, 0); +- break; +- case 0x84: +- case 0x86: +- xf_emit(ctx, 0x384, 0); +- break; +- case 0x92: +- case 0x94: +- case 0x96: +- case 0x98: +- xf_emit(ctx, 0x380, 0); +- break; +- } +- nv50_graph_construct_gene_m2mf (ctx); +- switch (dev_priv->chipset) { +- case 0x50: +- case 0x84: +- case 0x86: +- case 0x98: +- xf_emit(ctx, 0x4c4, 0); +- break; +- case 0x92: +- case 0x94: +- case 0x96: +- xf_emit(ctx, 0x984, 0); +- break; +- } +- nv50_graph_construct_gene_unk5(ctx); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 0xa, 0); +- else +- xf_emit(ctx, 0xb, 0); +- nv50_graph_construct_gene_unk4(ctx); +- nv50_graph_construct_gene_unk3(ctx); ++ nv50_graph_construct_gene_dispatch(ctx); ++ nv50_graph_construct_gene_m2mf(ctx); ++ nv50_graph_construct_gene_unk24xx(ctx); ++ nv50_graph_construct_gene_clipid(ctx); ++ nv50_graph_construct_gene_zcull(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 1 */ + ctx->ctxvals_pos = offset + 0x1; +- nv50_graph_construct_gene_unk6(ctx); +- nv50_graph_construct_gene_unk7(ctx); +- nv50_graph_construct_gene_unk8(ctx); +- switch (dev_priv->chipset) { +- case 0x50: +- case 0x92: +- xf_emit(ctx, 0xfb, 0); +- break; +- case 0x84: +- xf_emit(ctx, 0xd3, 0); +- break; +- case 0x94: +- case 0x96: +- xf_emit(ctx, 0xab, 0); +- break; +- case 0x86: +- case 0x98: +- xf_emit(ctx, 0x6b, 0); +- break; +- } +- xf_emit(ctx, 2, 0x4e3bfdf); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 0xb, 0); +- xf_emit(ctx, 2, 0x4e3bfdf); ++ nv50_graph_construct_gene_vfetch(ctx); ++ nv50_graph_construct_gene_eng2d(ctx); ++ nv50_graph_construct_gene_csched(ctx); ++ nv50_graph_construct_gene_ropm1(ctx); ++ nv50_graph_construct_gene_ropm2(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 2 */ + ctx->ctxvals_pos = offset + 0x2; +- switch (dev_priv->chipset) { +- case 0x50: +- case 0x92: +- xf_emit(ctx, 0xa80, 0); +- break; +- case 0x84: +- xf_emit(ctx, 0xa7e, 0); +- break; +- case 0x94: +- case 0x96: +- xf_emit(ctx, 0xa7c, 0); +- break; +- case 0x86: +- case 0x98: +- xf_emit(ctx, 0xa7a, 0); +- break; +- } +- xf_emit(ctx, 1, 0x3fffff); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x1fff); +- xf_emit(ctx, 0xe, 0); +- nv50_graph_construct_gene_unk9(ctx); +- nv50_graph_construct_gene_unk2(ctx); +- nv50_graph_construct_gene_unk1(ctx); +- nv50_graph_construct_gene_unk10(ctx); ++ nv50_graph_construct_gene_ccache(ctx); ++ nv50_graph_construct_gene_unk1cxx(ctx); ++ nv50_graph_construct_gene_strmout(ctx); ++ nv50_graph_construct_gene_unk14xx(ctx); ++ nv50_graph_construct_gene_unk10xx(ctx); ++ nv50_graph_construct_gene_unk34xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + +@@ -1150,86 +1225,46 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) + } else { + /* Strand 0 */ + ctx->ctxvals_pos = offset; +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x385, 0); +- else +- xf_emit(ctx, 0x384, 0); ++ nv50_graph_construct_gene_dispatch(ctx); + nv50_graph_construct_gene_m2mf(ctx); +- xf_emit(ctx, 0x950, 0); +- nv50_graph_construct_gene_unk10(ctx); +- xf_emit(ctx, 1, 0x0fac6881); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 3, 0); +- } +- nv50_graph_construct_gene_unk8(ctx); +- if (dev_priv->chipset == 0xa0) +- xf_emit(ctx, 0x189, 0); +- else if (dev_priv->chipset == 0xa3) +- xf_emit(ctx, 0xd5, 0); +- else if (dev_priv->chipset == 0xa5) +- xf_emit(ctx, 0x99, 0); +- else if (dev_priv->chipset == 0xaa) +- xf_emit(ctx, 0x65, 0); +- else +- xf_emit(ctx, 0x6d, 0); +- nv50_graph_construct_gene_unk9(ctx); ++ nv50_graph_construct_gene_unk34xx(ctx); ++ nv50_graph_construct_gene_csched(ctx); ++ nv50_graph_construct_gene_unk1cxx(ctx); ++ nv50_graph_construct_gene_strmout(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 1 */ + ctx->ctxvals_pos = offset + 1; +- nv50_graph_construct_gene_unk1(ctx); ++ nv50_graph_construct_gene_unk10xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 2 */ + ctx->ctxvals_pos = offset + 2; +- if (dev_priv->chipset == 0xa0) { +- nv50_graph_construct_gene_unk2(ctx); +- } +- xf_emit(ctx, 0x36, 0); +- nv50_graph_construct_gene_unk5(ctx); ++ if (dev_priv->chipset == 0xa0) ++ nv50_graph_construct_gene_unk14xx(ctx); ++ nv50_graph_construct_gene_unk24xx(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 3 */ + ctx->ctxvals_pos = offset + 3; +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- nv50_graph_construct_gene_unk6(ctx); ++ nv50_graph_construct_gene_vfetch(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 4 */ + ctx->ctxvals_pos = offset + 4; +- if (dev_priv->chipset == 0xa0) +- xf_emit(ctx, 0xa80, 0); +- else if (dev_priv->chipset == 0xa3) +- xf_emit(ctx, 0xa7c, 0); +- else +- xf_emit(ctx, 0xa7a, 0); +- xf_emit(ctx, 1, 0x3fffff); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x1fff); ++ nv50_graph_construct_gene_ccache(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + + /* Strand 5 */ + ctx->ctxvals_pos = offset + 5; +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 0xb, 0); +- xf_emit(ctx, 2, 0x4e3bfdf); +- xf_emit(ctx, 3, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 0x4e3bfdf); +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 0); ++ nv50_graph_construct_gene_ropm2(ctx); ++ nv50_graph_construct_gene_ropm1(ctx); ++ /* per-ROP context */ + for (i = 0; i < 8; i++) + if (units & (1<<(i+16))) + nv50_graph_construct_gene_ropc(ctx); +@@ -1238,10 +1273,9 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) + + /* Strand 6 */ + ctx->ctxvals_pos = offset + 6; +- nv50_graph_construct_gene_unk3(ctx); +- xf_emit(ctx, 0xb, 0); +- nv50_graph_construct_gene_unk4(ctx); +- nv50_graph_construct_gene_unk7(ctx); ++ nv50_graph_construct_gene_zcull(ctx); ++ nv50_graph_construct_gene_clipid(ctx); ++ nv50_graph_construct_gene_eng2d(ctx); + if (units & (1 << 0)) + nv50_graph_construct_xfer_tp(ctx); + if (units & (1 << 1)) +@@ -1269,7 +1303,7 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) + if (units & (1 << 9)) + nv50_graph_construct_xfer_tp(ctx); + } else { +- nv50_graph_construct_gene_unk2(ctx); ++ nv50_graph_construct_gene_unk14xx(ctx); + } + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; +@@ -1290,9 +1324,70 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) + */ + + static void ++nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx) ++{ ++ /* start of strand 0 */ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ /* SEEK */ ++ if (dev_priv->chipset == 0x50) ++ xf_emit(ctx, 5, 0); ++ else if (!IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 6, 0); ++ else ++ xf_emit(ctx, 4, 0); ++ /* SEEK */ ++ /* the PGRAPH's internal FIFO */ ++ if (dev_priv->chipset == 0x50) ++ xf_emit(ctx, 8*3, 0); ++ else ++ xf_emit(ctx, 0x100*3, 0); ++ /* and another bonus slot?!? */ ++ xf_emit(ctx, 3, 0); ++ /* and YET ANOTHER bonus slot? */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 3, 0); ++ /* SEEK */ ++ /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */ ++ xf_emit(ctx, 9, 0); ++ /* SEEK */ ++ xf_emit(ctx, 9, 0); ++ /* SEEK */ ++ xf_emit(ctx, 9, 0); ++ /* SEEK */ ++ xf_emit(ctx, 9, 0); ++ /* SEEK */ ++ if (dev_priv->chipset < 0x90) ++ xf_emit(ctx, 4, 0); ++ /* SEEK */ ++ xf_emit(ctx, 2, 0); ++ /* SEEK */ ++ xf_emit(ctx, 6*2, 0); ++ xf_emit(ctx, 2, 0); ++ /* SEEK */ ++ xf_emit(ctx, 2, 0); ++ /* SEEK */ ++ xf_emit(ctx, 6*2, 0); ++ xf_emit(ctx, 2, 0); ++ /* SEEK */ ++ if (dev_priv->chipset == 0x50) ++ xf_emit(ctx, 0x1c, 0); ++ else if (dev_priv->chipset < 0xa0) ++ xf_emit(ctx, 0x1e, 0); ++ else ++ xf_emit(ctx, 0x22, 0); ++ /* SEEK */ ++ xf_emit(ctx, 0x15, 0); ++} ++ ++static void + nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx) + { +- /* m2mf state */ ++ /* Strand 0, right after dispatch */ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ int smallm2mf = 0; ++ if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98) ++ smallm2mf = 1; ++ /* SEEK */ + xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */ + xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */ + xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */ +@@ -1319,427 +1414,975 @@ nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx) + xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */ + xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */ + xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */ ++ /* SEEK */ ++ if (smallm2mf) ++ xf_emit(ctx, 0x40, 0); /* 20 * ffffffff, 3ffff */ ++ else ++ xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */ ++ xf_emit(ctx, 4, 0); /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */ ++ /* SEEK */ ++ if (smallm2mf) ++ xf_emit(ctx, 0x400, 0); /* ffffffff */ ++ else ++ xf_emit(ctx, 0x800, 0); /* ffffffff */ ++ xf_emit(ctx, 4, 0); /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */ ++ /* SEEK */ ++ xf_emit(ctx, 0x40, 0); /* 20 * bits ffffffff, 3ffff */ ++ xf_emit(ctx, 0x6, 0); /* 1f, 0, 1f, 0, 1f, 0 */ + } + + static void +-nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* end of area 2 on pre-NVA0, area 1 on NVAx */ +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 1, 0); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0x3ff); +- else +- xf_emit(ctx, 1, 0x7ff); ++ xf_emit(ctx, 2, 0); /* RO */ ++ xf_emit(ctx, 0x800, 0); /* ffffffff */ + switch (dev_priv->chipset) { + case 0x50: +- case 0x86: +- case 0x98: +- case 0xaa: +- case 0xac: +- xf_emit(ctx, 0x542, 0); ++ case 0x92: ++ case 0xa0: ++ xf_emit(ctx, 0x2b, 0); + break; + case 0x84: +- case 0x92: ++ xf_emit(ctx, 0x29, 0); ++ break; + case 0x94: + case 0x96: +- xf_emit(ctx, 0x942, 0); +- break; +- case 0xa0: + case 0xa3: +- xf_emit(ctx, 0x2042, 0); ++ xf_emit(ctx, 0x27, 0); + break; ++ case 0x86: ++ case 0x98: + case 0xa5: + case 0xa8: +- xf_emit(ctx, 0x842, 0); ++ case 0xaa: ++ case 0xac: ++ case 0xaf: ++ xf_emit(ctx, 0x25, 0); + break; + } +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x27); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x26); +- xf_emit(ctx, 3, 0); ++ /* CB bindings, 0x80 of them. first word is address >> 8, second is ++ * size >> 4 | valid << 24 */ ++ xf_emit(ctx, 0x100, 0); /* ffffffff CB_DEF */ ++ xf_emit(ctx, 1, 0); /* 0000007f CB_ADDR_BUFFER */ ++ xf_emit(ctx, 1, 0); /* 0 */ ++ xf_emit(ctx, 0x30, 0); /* ff SET_PROGRAM_CB */ ++ xf_emit(ctx, 1, 0); /* 3f last SET_PROGRAM_CB */ ++ xf_emit(ctx, 4, 0); /* RO */ ++ xf_emit(ctx, 0x100, 0); /* ffffffff */ ++ xf_emit(ctx, 8, 0); /* 1f, 0, 0, ... */ ++ xf_emit(ctx, 8, 0); /* ffffffff */ ++ xf_emit(ctx, 4, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 3 */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CODE_CB */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TIC */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TSC */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */ ++ xf_emit(ctx, 1, 0); /* 000000ff TIC_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff TIC_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */ ++ xf_emit(ctx, 1, 0); /* 000000ff TSC_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff TSC_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */ ++ xf_emit(ctx, 1, 0); /* 000000ff VP_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff VP_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 00ffffff VP_START_ID */ ++ xf_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 000000ff GP_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff GP_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 00ffffff GP_START_ID */ ++ xf_emit(ctx, 1, 0); /* 000000ff FP_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 00ffffff FP_START_ID */ + } + + static void +-nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx) + { ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ int i; + /* end of area 2 on pre-NVA0, area 1 on NVAx */ +- xf_emit(ctx, 0x10, 0x04000000); +- xf_emit(ctx, 0x24, 0); +- xf_emit(ctx, 2, 0x04e3bfdf); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x1fe21); ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ ++ if (dev_priv->chipset == 0x50) ++ xf_emit(ctx, 1, 0x3ff); ++ else ++ xf_emit(ctx, 1, 0x7ff); /* 000007ff */ ++ xf_emit(ctx, 1, 0); /* 111/113 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ for (i = 0; i < 8; i++) { ++ switch (dev_priv->chipset) { ++ case 0x50: ++ case 0x86: ++ case 0x98: ++ case 0xaa: ++ case 0xac: ++ xf_emit(ctx, 0xa0, 0); /* ffffffff */ ++ break; ++ case 0x84: ++ case 0x92: ++ case 0x94: ++ case 0x96: ++ xf_emit(ctx, 0x120, 0); ++ break; ++ case 0xa5: ++ case 0xa8: ++ xf_emit(ctx, 0x100, 0); /* ffffffff */ ++ break; ++ case 0xa0: ++ case 0xa3: ++ case 0xaf: ++ xf_emit(ctx, 0x400, 0); /* ffffffff */ ++ break; ++ } ++ xf_emit(ctx, 4, 0); /* 3f, 0, 0, 0 */ ++ xf_emit(ctx, 4, 0); /* ffffffff */ ++ } ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_TEMP */ ++ xf_emit(ctx, 1, 1); /* 00000001 RASTERIZE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++} ++ ++static void ++nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx) ++{ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ /* end of area 2 on pre-NVA0, area 1 on NVAx */ ++ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000003 VIEWPORT_CLIP_MODE */ ++ xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */ ++ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */ ++ xf_emit(ctx, 0x20, 0); /* ffffffff POLYGON_STIPPLE */ ++ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */ ++ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */ ++ if (dev_priv->chipset >= 0xa0) ++ xf_emit(ctx, 1, 0x0fac6881); ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 3, 0); ++ } + } + + static void +-nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */ + if (dev_priv->chipset != 0x50) { +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x804); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0x8100c12); ++ xf_emit(ctx, 5, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 2, 4); /* 7f, ff */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + } +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x10); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 3, 0); +- else +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x804); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x1a); ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 000000ff VP_CLIP_DISTANCE_ENABLE */ + if (dev_priv->chipset != 0x50) +- xf_emit(ctx, 1, 0x7f); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 6, 0); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0x3ff); +- else +- xf_emit(ctx, 1, 0x7ff); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 0x38, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 0x38, 0); +- xf_emit(ctx, 2, 0x88); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 0x16, 0); +- xf_emit(ctx, 1, 0x26); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x3f800000); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 4, 0); +- else +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x1a); +- xf_emit(ctx, 1, 0x10); ++ xf_emit(ctx, 1, 0); /* 3ff */ ++ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1940 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */ ++ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */ ++ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ + if (dev_priv->chipset != 0x50) +- xf_emit(ctx, 0x28, 0); ++ xf_emit(ctx, 1, 0x7f); /* 000000ff tesla UNK0FFC */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 1); /* 00000001 SHADE_MODEL */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0F8C */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ if (dev_priv->chipset == 0x50) ++ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ + else +- xf_emit(ctx, 0x25, 0); +- xf_emit(ctx, 1, 0x52); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x26); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x1a); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x00ffff00); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ ++ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */ ++ xf_emit(ctx, 3, 0); /* f, 0, 0 */ ++ xf_emit(ctx, 3, 0); /* ffffffff last VIEWPORT_SCALE? */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ ++ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_TRANSLATE */ ++ xf_emit(ctx, 3, 0); /* f, 0, 0 */ ++ xf_emit(ctx, 3, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 2, 0x88); /* 000001ff tesla UNK19D8 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ ++ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ ++ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ ++ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ ++ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ ++ if (dev_priv->chipset != 0x50) { ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ } ++ xf_emit(ctx, 0x20, 0); /* 10xbits ffffffff, 3fffff. SCISSOR_* */ ++ xf_emit(ctx, 1, 0); /* f */ ++ xf_emit(ctx, 1, 0); /* 0? */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 003fffff */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ + } + + static void +-nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* end of area 0 on pre-NVA0, beginning of area 6 on NVAx */ +- xf_emit(ctx, 1, 0x3f); +- xf_emit(ctx, 0xa, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 0x04000000); +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 4); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 0x10, 0); +- else +- xf_emit(ctx, 0x11, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x1001); +- xf_emit(ctx, 4, 0xffff); +- xf_emit(ctx, 0x20, 0); +- xf_emit(ctx, 0x10, 0x3f800000); +- xf_emit(ctx, 1, 0x10); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0); +- else +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 2, 0); ++ /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */ ++ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ ++ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */ ++ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ ++ xf_emit(ctx, 1, 0); /* 0000ffff */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK0FB0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ if (dev_priv->chipset != 0x50) ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1108 */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */ ++ /* SEEK */ ++ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ ++ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ ++ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ ++ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */ ++ xf_emit(ctx, 1, 3); /* 00000003 FP_CTRL_UNK196C */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1968 */ ++ if (dev_priv->chipset != 0x50) ++ xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */ + } + + static void +-nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx) + { +- /* middle of area 0 on pre-NVA0, middle of area 6 on NVAx */ +- xf_emit(ctx, 2, 0x04000000); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 1, 0); ++ /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000007 UNK0FB4 */ ++ /* SEEK */ ++ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_HORIZ */ ++ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_VERT */ ++ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ ++ xf_emit(ctx, 2, 0x04000000); /* 07ffffff UNK1508 */ ++ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */ ++ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_WIDTH */ ++ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ID */ ++ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff CLIPID_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_HEIGHT */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CLIPID */ + } + + static void +-nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* middle of area 0 on pre-NVA0 [after m2mf], end of area 2 on NVAx */ +- xf_emit(ctx, 2, 4); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x1c4d, 0); ++ int i; ++ /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */ ++ /* SEEK */ ++ xf_emit(ctx, 0x33, 0); ++ /* SEEK */ ++ xf_emit(ctx, 2, 0); ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 4, 0); /* RO */ ++ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ ++ xf_emit(ctx, 1, 0); /* 1ff */ ++ xf_emit(ctx, 8, 0); /* 0? */ ++ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */ ++ ++ xf_emit(ctx, 4, 0); /* RO */ ++ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ ++ xf_emit(ctx, 1, 0); /* 1ff */ ++ xf_emit(ctx, 8, 0); /* 0? */ ++ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */ ++ } + else +- xf_emit(ctx, 0x1c4b, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0x8100c12); ++ { ++ xf_emit(ctx, 0xc, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ ++ xf_emit(ctx, 1, 0); /* 1ff */ ++ xf_emit(ctx, 8, 0); /* 0? */ ++ ++ /* SEEK */ ++ xf_emit(ctx, 0xc, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ ++ xf_emit(ctx, 1, 0); /* 1ff */ ++ xf_emit(ctx, 8, 0); /* 0? */ ++ } ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ + if (dev_priv->chipset != 0x50) +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 1); /* 00000001 */ ++ /* SEEK */ + if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0x80c14); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 1, 0x27); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x3c1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x16, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 2, 4); /* 000000ff */ ++ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM_ID */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 1); /* 00000001 */ ++ for (i = 0; i < 10; i++) { ++ /* SEEK */ ++ xf_emit(ctx, 0x40, 0); /* ffffffff */ ++ xf_emit(ctx, 0x10, 0); /* 3, 0, 0.... */ ++ xf_emit(ctx, 0x10, 0); /* ffffffff */ ++ } ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_CTRL */ ++ xf_emit(ctx, 1, 1); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */ ++ xf_emit(ctx, 0x10, 0); /* 00ffffff POINT_COORD_REPLACE_MAP */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ if (dev_priv->chipset != 0x50) ++ xf_emit(ctx, 1, 0); /* 000003ff */ + } + + static void +-nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* beginning of area 1 on pre-NVA0 [after m2mf], area 3 on NVAx */ +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0xf); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 8, 0); +- else +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x20); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x11, 0); ++ int acnt = 0x10, rep, i; ++ /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ acnt = 0x20; ++ /* SEEK */ ++ if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */ ++ xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */ ++ } ++ xf_emit(ctx, 1, 0); /* ffffffff VERTEX_BUFFER_FIRST */ ++ xf_emit(ctx, 1, 0); /* 00000001 PRIMITIVE_RESTART_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK0DE8 */ ++ xf_emit(ctx, 1, 0); /* ffffffff PRIMITIVE_RESTART_INDEX */ ++ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATR_MASK_UNK0DD0 */ ++ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ ++ xf_emit(ctx, 1, 0x20); /* 0000ffff tesla UNK129C */ ++ xf_emit(ctx, 1, 0); /* 000000ff turing UNK370??? */ ++ xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0xb, 0); /* RO */ + else if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 0xf, 0); ++ xf_emit(ctx, 0x9, 0); /* RO */ + else +- xf_emit(ctx, 0xe, 0); +- xf_emit(ctx, 1, 0x1a); +- xf_emit(ctx, 0xd, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 8); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 0x8, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 00000001 EDGE_FLAG */ ++ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ ++ /* SEEK */ ++ xf_emit(ctx, 0xc, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 7f/ff */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ ++ xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */ ++ xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0x3ff); ++ xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */ + else +- xf_emit(ctx, 1, 0x7ff); ++ xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */ + if (dev_priv->chipset == 0xa8) +- xf_emit(ctx, 1, 0x1e00); +- xf_emit(ctx, 0xc, 0); +- xf_emit(ctx, 1, 0xf); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 0x125, 0); +- else if (dev_priv->chipset < 0xa0) +- xf_emit(ctx, 0x126, 0); +- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) +- xf_emit(ctx, 0x124, 0); ++ xf_emit(ctx, 1, 0x1e00); /* 7fff */ ++ /* SEEK */ ++ xf_emit(ctx, 0xc, 0); /* RO or close */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ ++ if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0) ++ xf_emit(ctx, 2, 0); /* ffffffff */ + else +- xf_emit(ctx, 0x1f7, 0); +- xf_emit(ctx, 1, 0xf); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 3, 0); ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0FD8 */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 0x10, 0); /* 0? */ ++ xf_emit(ctx, 2, 0); /* weird... */ ++ xf_emit(ctx, 2, 0); /* RO */ ++ } else { ++ xf_emit(ctx, 8, 0); /* 0? */ ++ xf_emit(ctx, 1, 0); /* weird... */ ++ xf_emit(ctx, 2, 0); /* RO */ ++ } ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* ffffffff VB_ELEMENT_BASE */ ++ xf_emit(ctx, 1, 0); /* ffffffff UNK1438 */ ++ xf_emit(ctx, acnt, 0); /* 1 tesla UNK1000 */ ++ if (dev_priv->chipset >= 0xa0) ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */ ++ xf_emit(ctx, 1, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */ ++ xf_emit(ctx, 1, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* RO */ ++ xf_emit(ctx, 2, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK111C? */ ++ xf_emit(ctx, 1, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 000000ff UNK15F4_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff UNK15F4_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 000000ff UNK0F84_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff UNK0F84_ADDRESS_LOW */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* 00000fff VERTEX_ARRAY_STRIDE */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_LOW */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_ARRAY_HIGH */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_LIMIT_LOW */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, acnt, 0); /* f */ ++ xf_emit(ctx, 3, 0); /* f/1f */ ++ } ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 2, 0); /* RO */ ++ else ++ xf_emit(ctx, 5, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* ffff DMA_VTXBUF */ ++ /* SEEK */ ++ if (dev_priv->chipset < 0xa0) { ++ xf_emit(ctx, 0x41, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 0x11, 0); /* RO */ ++ } else if (!IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x50, 0); /* RO */ + else +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0xa1, 0); ++ xf_emit(ctx, 0x58, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, 1, 1); /* 1 UNK0DEC */ ++ /* SEEK */ ++ xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */ ++ xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x1d, 0); /* RO */ + else +- xf_emit(ctx, 0x5a, 0); +- xf_emit(ctx, 1, 0xf); ++ xf_emit(ctx, 0x16, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ ++ /* SEEK */ + if (dev_priv->chipset < 0xa0) +- xf_emit(ctx, 0x834, 0); +- else if (dev_priv->chipset == 0xa0) +- xf_emit(ctx, 0x1873, 0); +- else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x8ba, 0); ++ xf_emit(ctx, 8, 0); /* RO */ ++ else if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0xc, 0); /* RO */ ++ else ++ xf_emit(ctx, 7, 0); /* RO */ ++ /* SEEK */ ++ xf_emit(ctx, 0xa, 0); /* RO */ ++ if (dev_priv->chipset == 0xa0) ++ rep = 0xc; ++ else ++ rep = 4; ++ for (i = 0; i < rep; i++) { ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x20, 0); /* ffffffff */ ++ xf_emit(ctx, 0x200, 0); /* ffffffff */ ++ xf_emit(ctx, 4, 0); /* 7f/ff, 0, 0, 0 */ ++ xf_emit(ctx, 4, 0); /* ffffffff */ ++ } ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 113/111 */ ++ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */ ++ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATTR_MASK_UNK0DD0 */ ++ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ /* SEEK */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 7, 0); /* weird... */ + else +- xf_emit(ctx, 0x833, 0); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 0xf, 0); ++ xf_emit(ctx, 5, 0); /* weird... */ + } + + static void +-nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 6 on NVAx */ +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 2, 1); +- else +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0x100); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 8); +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 3, 1); +- xf_emit(ctx, 1, 0xcf); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 3, 1); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x15); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x4444480); +- xf_emit(ctx, 0x37, 0); ++ /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */ ++ /* SEEK */ ++ xf_emit(ctx, 2, 0); /* 0001ffff CLIP_X, CLIP_Y */ ++ xf_emit(ctx, 2, 0); /* 0000ffff CLIP_W, CLIP_H */ ++ xf_emit(ctx, 1, 0); /* 00000001 CLIP_ENABLE */ ++ if (dev_priv->chipset < 0xa0) { ++ /* this is useless on everything but the original NV50, ++ * guess they forgot to nuke it. Or just didn't bother. */ ++ xf_emit(ctx, 2, 0); /* 0000ffff IFC_CLIP_X, Y */ ++ xf_emit(ctx, 2, 1); /* 0000ffff IFC_CLIP_W, H */ ++ xf_emit(ctx, 1, 0); /* 00000001 IFC_CLIP_ENABLE */ ++ } ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */ ++ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */ ++ xf_emit(ctx, 1, 0x11); /* 3f[NV50]/7f[NV84+] DST_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 0001ffff DRAW_POINT_X */ ++ xf_emit(ctx, 1, 8); /* 0000000f DRAW_UNK58C */ ++ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_X_FRACT */ ++ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_X_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_Y_FRACT */ ++ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_Y_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DX_DU_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DX_DU_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DY_DV_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DY_DV_INT */ ++ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_WIDTH */ ++ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_HEIGHT */ ++ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */ ++ xf_emit(ctx, 1, 2); /* 00000003 SIFC_BITMAP_UNK808 */ ++ xf_emit(ctx, 1, 0); /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */ ++ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_LSB_FIRST */ ++ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_X */ ++ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_Y */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */ ++ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_W */ ++ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_H */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_X_FRACT */ ++ xf_emit(ctx, 1, 0); /* 0001ffff BLIT_SRC_X_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_Y_FRACT */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK888 */ ++ xf_emit(ctx, 1, 4); /* 0000003f UNK884 */ ++ xf_emit(ctx, 1, 0); /* 00000007 UNK880 */ ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK0FB8 */ ++ xf_emit(ctx, 1, 0x15); /* 000000ff tesla UNK128C */ ++ xf_emit(ctx, 2, 0); /* 00000007, ffff0ff3 */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK260 */ ++ xf_emit(ctx, 1, 0x4444480); /* 1fffffff UNK870 */ ++ /* SEEK */ ++ xf_emit(ctx, 0x10, 0); ++ /* SEEK */ ++ xf_emit(ctx, 0x27, 0); + } + + static void +-nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx) + { +- /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 0 on NVAx */ +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x100); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x10001); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x10001); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x10001); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 2); ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */ ++ /* SEEK */ ++ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* ffffffff turing UNK364 */ ++ xf_emit(ctx, 1, 0); /* 0000000f turing UNK36C */ ++ xf_emit(ctx, 1, 0); /* 0000ffff USER_PARAM_COUNT */ ++ xf_emit(ctx, 1, 0x100); /* 00ffffff turing UNK384 */ ++ xf_emit(ctx, 1, 0); /* 0000000f turing UNK2A0 */ ++ xf_emit(ctx, 1, 0); /* 0000ffff GRIDID */ ++ xf_emit(ctx, 1, 0x10001); /* ffffffff GRIDDIM_XY */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */ ++ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */ ++ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */ ++ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */ ++ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ ++ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ ++ /* SEEK */ ++ xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */ ++ switch (dev_priv->chipset) { ++ case 0x50: ++ case 0x92: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0x80, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 0x10*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0x84: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0x60, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0x94: ++ case 0x96: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0x40, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 8*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0x86: ++ case 0x98: ++ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */ ++ xf_emit(ctx, 0x10, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0xa0: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0xf0, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 0x1e*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0xa3: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0x60, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0xa5: ++ case 0xaf: ++ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */ ++ xf_emit(ctx, 0x30, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 6*2, 0); /* ffffffff, 1f */ ++ break; ++ case 0xaa: ++ xf_emit(ctx, 0x12, 0); ++ break; ++ case 0xa8: ++ case 0xac: ++ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */ ++ xf_emit(ctx, 0x10, 0); /* fff */ ++ xf_emit(ctx, 2, 0); /* ff, fff */ ++ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */ ++ break; ++ } ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 0); /* 00000000 */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 0000001f */ ++ xf_emit(ctx, 4, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 4, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 000000ff */ + } + + static void +-nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx) ++nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- /* middle of area 2 on pre-NVA0 [after m2mf], end of area 0 on NVAx */ +- xf_emit(ctx, 1, 0x3f800000); +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0x1a); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x12, 0); +- xf_emit(ctx, 1, 0x00ffff00); +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 0xf, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 3); ++ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ ++ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */ ++ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */ ++ xf_emit(ctx, 3, 0); /* 00000001 POLYGON_OFFSET_*_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */ ++ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ ++ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_UNITS */ ++ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_FACTOR */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */ ++ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */ ++ xf_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_LINEAR */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */ + else if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 0x04000000); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 5); +- xf_emit(ctx, 1, 0x52); +- if (dev_priv->chipset == 0x50) { +- xf_emit(ctx, 0x13, 0); +- } else { +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x11, 0); +- else +- xf_emit(ctx, 0x10, 0); ++ xf_emit(ctx, 1, 1); /* 00000001 UNK16B4 */ ++ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */ ++ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ ++ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 5); /* 0000000f UNK1408 */ ++ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */ ++ xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */ ++ if (dev_priv->chipset != 0x50) { ++ xf_emit(ctx, 1, 0); /* 3ff */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */ + } +- xf_emit(ctx, 0x10, 0x3f800000); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 0x26, 0); +- xf_emit(ctx, 1, 0x8100c12); +- xf_emit(ctx, 1, 5); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 4, 0xffff); ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */ ++ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ ++ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ ++ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 0x20, 0); /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK187C */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ ++ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 5); /* 0000000f tesla UNK1220 */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1A20 */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ ++ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ + if (dev_priv->chipset != 0x50) +- xf_emit(ctx, 1, 3); ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ + if (dev_priv->chipset < 0xa0) +- xf_emit(ctx, 0x1f, 0); +- else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0xc, 0); +- else +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x00ffff00); +- xf_emit(ctx, 1, 0x1a); ++ xf_emit(ctx, 0x1c, 0); /* RO */ ++ else if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x9, 0); ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ ++ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */ + if (dev_priv->chipset != 0x50) { +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 3); ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */ ++ xf_emit(ctx, 1, 0); /* 3ff */ + } ++ /* XXX: the following block could belong either to unk1cxx, or ++ * to STRMOUT. Rather hard to tell. */ + if (dev_priv->chipset < 0xa0) +- xf_emit(ctx, 0x26, 0); ++ xf_emit(ctx, 0x25, 0); + else +- xf_emit(ctx, 0x3c, 0); +- xf_emit(ctx, 1, 0x102); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 4, 4); +- if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 0x3b, 0); ++} ++ ++static void ++nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx) ++{ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */ ++ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */ ++ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */ ++ if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */ ++ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */ ++ } ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0x3ff); ++ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */ + else +- xf_emit(ctx, 1, 0x7ff); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x102); +- xf_emit(ctx, 9, 0); +- xf_emit(ctx, 4, 4); +- xf_emit(ctx, 0x2c, 0); ++ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */ ++ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */ ++ xf_emit(ctx, 4, 0); /* 000000ff STRMOUT_ADDRESS_HIGH */ ++ xf_emit(ctx, 4, 0); /* ffffffff STRMOUT_ADDRESS_LOW */ ++ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */ ++ if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */ ++ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */ ++ } ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STRMOUT */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ ++ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ ++ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */ ++ xf_emit(ctx, 2, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ /* SEEK */ ++ xf_emit(ctx, 0x20, 0); /* ffffffff STRMOUT_MAP */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 0); /* 00000000? */ ++ xf_emit(ctx, 2, 0); /* ffffffff */ ++} ++ ++static void ++nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx) ++{ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */ ++ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++} ++ ++static void ++nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx) ++{ ++ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 2, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ ++ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 7 */ ++ /* SEEK */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */ ++ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */ ++ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */ ++ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */ ++ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */ ++ xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + } + + static void +@@ -1749,443 +2392,709 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx) + int magic2; + if (dev_priv->chipset == 0x50) { + magic2 = 0x00003e60; +- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) { ++ } else if (!IS_NVA3F(dev_priv->chipset)) { + magic2 = 0x001ffe67; + } else { + magic2 = 0x00087e67; + } +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, magic2); +- xf_emit(ctx, 4, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 7, 0); +- if (dev_priv->chipset >= 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 0x15); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 4, 0); ++ xf_emit(ctx, 1, 0); /* f/7 MUTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0x15); /* 000000ff */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 0x10); /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) { +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0x400); +- xf_emit(ctx, 1, 0x300); +- xf_emit(ctx, 1, 0x1001); ++ xf_emit(ctx, 3, 0); /* ff, ffffffff, ffffffff */ ++ xf_emit(ctx, 1, 4); /* 7 */ ++ xf_emit(ctx, 1, 0x400); /* fffffff */ ++ xf_emit(ctx, 1, 0x300); /* ffff */ ++ xf_emit(ctx, 1, 0x1001); /* 1fff */ + if (dev_priv->chipset != 0xa0) { +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 0); ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */ + else +- xf_emit(ctx, 1, 0x15); ++ xf_emit(ctx, 1, 0x15); /* ff */ + } +- xf_emit(ctx, 3, 0); + } +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x13, 0); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 0x10, 0); +- xf_emit(ctx, 0x10, 0x3f800000); +- xf_emit(ctx, 0x19, 0); +- xf_emit(ctx, 1, 0x10); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x3f); +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ ++ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */ ++ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */ ++ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 2, 0); /* ffff0ff3, ffff */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ + if (dev_priv->chipset >= 0xa0) { + xf_emit(ctx, 2, 0); + xf_emit(ctx, 1, 0x1001); + xf_emit(ctx, 0xb, 0); + } else { +- xf_emit(ctx, 0xc, 0); ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ + } +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x11); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 4, 0); +- else +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 3, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, magic2); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 0x18, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x16, 0); ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ if (dev_priv->chipset != 0x50) { ++ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */ ++ xf_emit(ctx, 1, 0); /* 000000ff */ ++ } ++ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ ++ xf_emit(ctx, 2, 1); /* 00000007 BLEND_EQUATION_RGB, ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK12E4 */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */ ++ xf_emit(ctx, 2, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* 0000000f */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 2, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ } else if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 2, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 2, 0); /* 00000001 */ + } else { +- if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 0x1b, 0); +- else +- xf_emit(ctx, 0x15, 0); ++ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1430 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ + } +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 1); ++ xf_emit(ctx, 4, 0); /* ffffffff CLEAR_COLOR */ ++ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR A R G B */ ++ xf_emit(ctx, 1, 0); /* 00000fff eng2d UNK2B0 */ + if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 4, 0); +- else +- xf_emit(ctx, 3, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 0x10, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 0x10, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 3, 0); ++ xf_emit(ctx, 2, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */ ++ if (dev_priv->chipset >= 0xa0) ++ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK15C4 */ ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */ + } +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x5b, 0); ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ xf_emit(ctx, 1, 0); /* 00000007 PATTERN_COLOR_FORMAT */ ++ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 PATTERN_MONO_FORMAT */ ++ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_BITMAP */ ++ xf_emit(ctx, 1, 0); /* 00000003 PATTERN_SELECT */ ++ xf_emit(ctx, 1, 0); /* 000000ff ROP */ ++ xf_emit(ctx, 1, 0); /* ffffffff BETA1 */ ++ xf_emit(ctx, 1, 0); /* ffffffff BETA4 */ ++ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ ++ xf_emit(ctx, 0x50, 0); /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */ + } + + static void +-nv50_graph_construct_xfer_tp_x1(struct nouveau_grctx *ctx) ++nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + int magic3; +- if (dev_priv->chipset == 0x50) ++ switch (dev_priv->chipset) { ++ case 0x50: + magic3 = 0x1000; +- else if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) ++ break; ++ case 0x86: ++ case 0x98: ++ case 0xa8: ++ case 0xaa: ++ case 0xac: ++ case 0xaf: + magic3 = 0x1e00; +- else ++ break; ++ default: + magic3 = 0; +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 4); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0x24, 0); ++ } ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 111/113[NVA0+] */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x1f, 0); /* ffffffff */ + else if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 0x14, 0); ++ xf_emit(ctx, 0x0f, 0); /* ffffffff */ + else +- xf_emit(ctx, 0x15, 0); +- xf_emit(ctx, 2, 4); ++ xf_emit(ctx, 0x10, 0); /* fffffff VP_RESULT_MAP_1 up */ ++ xf_emit(ctx, 2, 0); /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ + if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 1, 0x03020100); ++ xf_emit(ctx, 1, 0x03020100); /* ffffffff */ + else +- xf_emit(ctx, 1, 0x00608080); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 2, 4); +- xf_emit(ctx, 1, 0x80); ++ xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 2, 0); /* 111/113, 7f/ff */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ + if (magic3) +- xf_emit(ctx, 1, magic3); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 0x24, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0x03020100); +- xf_emit(ctx, 1, 3); ++ xf_emit(ctx, 1, magic3); /* 00007fff tesla UNK141C */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 111/113 */ ++ xf_emit(ctx, 0x1f, 0); /* ffffffff GP_RESULT_MAP_1 up */ ++ xf_emit(ctx, 1, 0); /* 0000001f */ ++ xf_emit(ctx, 1, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0x03020100); /* ffffffff GP_RESULT_MAP_0 */ ++ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ + if (magic3) +- xf_emit(ctx, 1, magic3); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 4); ++ xf_emit(ctx, 1, magic3); /* 7fff tesla UNK141C */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 111/113 */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ ++ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK13A0 */ ++ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ xf_emit(ctx, 1, 0); /* 111/113 */ + if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96) +- xf_emit(ctx, 0x1024, 0); ++ xf_emit(ctx, 0x1020, 0); /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */ + else if (dev_priv->chipset < 0xa0) +- xf_emit(ctx, 0xa24, 0); +- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) +- xf_emit(ctx, 0x214, 0); ++ xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */ ++ else if (!IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x210, 0); /* ffffffff */ + else +- xf_emit(ctx, 0x414, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 2, 0); ++ xf_emit(ctx, 0x410, 0); /* ffffffff */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */ ++ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */ ++ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ + } + + static void +-nv50_graph_construct_xfer_tp_x2(struct nouveau_grctx *ctx) ++nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + int magic1, magic2; + if (dev_priv->chipset == 0x50) { + magic1 = 0x3ff; + magic2 = 0x00003e60; +- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) { ++ } else if (!IS_NVA3F(dev_priv->chipset)) { + magic1 = 0x7ff; + magic2 = 0x001ffe67; + } else { + magic1 = 0x7ff; + magic2 = 0x00087e67; + } +- xf_emit(ctx, 3, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0xc, 0); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 0xb, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 4, 0xffff); +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 1, 0); +- } else if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0xa, 0); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 0x18, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* ffffffff ALPHA_TEST_REF */ ++ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000000f UNK16A0 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK0FDC */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ff[NV50]/3ff[NV84+] */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */ ++ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ ++ xf_emit(ctx, 1, 0); /* 7 */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff COLOR_KEY */ ++ xf_emit(ctx, 1, 0); /* 00000001 COLOR_KEY_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 COLOR_KEY_FORMAT */ ++ xf_emit(ctx, 2, 0); /* ffffffff SIFC_BITMAP_COLOR */ ++ xf_emit(ctx, 1, 1); /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1298 */ ++ } else if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ } else { ++ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ + } +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 3, 0xcf); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0xa, 0); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, magic2); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x11); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 2, 1); +- else +- xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_RGB */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_RGB */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_ALPHA */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ ++ } ++ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ ++ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ ++ xf_emit(ctx, 1, 0); /* 7 */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */ ++ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */ ++ xf_emit(ctx, 1, 0xcf); /* 000000ff DRAW_COLOR_FORMAT */ ++ xf_emit(ctx, 1, 0xcf); /* 000000ff SRC_FORMAT */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ xf_emit(ctx, 1, 0); /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 8, 1); /* 00000001 UNK19E0 */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ + if(dev_priv->chipset == 0x50) +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 1, 0); /* ff */ + else +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, magic1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 0x28, 0); +- xf_emit(ctx, 8, 8); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 8, 0x400); +- xf_emit(ctx, 8, 0x300); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x20); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 0x100); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x40); +- xf_emit(ctx, 1, 0x100); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 4, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, magic2); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 9, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x400); +- xf_emit(ctx, 1, 0x300); +- xf_emit(ctx, 1, 0x1001); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 4, 0); +- else +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 1, 0xf); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 0x15, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 3, 0); +- } else +- xf_emit(ctx, 0x17, 0); ++ xf_emit(ctx, 3, 0); /* 1, 7, 3ff */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */ ++ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */ ++ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, magic1); /* 3ff/7ff tesla UNK0D68 */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 8, 0); /* 0000ffff DMA_COLOR */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_GLOBAL */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_LOCAL */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STACK */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_DST */ ++ xf_emit(ctx, 1, 0); /* 7 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 8, 0); /* 000000ff RT_ADDRESS_HIGH */ ++ xf_emit(ctx, 8, 0); /* ffffffff RT_LAYER_STRIDE */ ++ xf_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */ ++ xf_emit(ctx, 8, 8); /* 0000007f RT_TILE_MODE */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 8, 0x400); /* 0fffffff RT_HORIZ */ ++ xf_emit(ctx, 8, 0x300); /* 0000ffff RT_VERT */ ++ xf_emit(ctx, 1, 1); /* 00001fff RT_ARRAY_MODE */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, 0x20); /* 00000fff DST_TILE_MODE */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */ ++ xf_emit(ctx, 1, 0); /* 000007ff DST_LAYER */ ++ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ ++ xf_emit(ctx, 1, 0); /* ffffffff DST_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0); /* 000000ff DST_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0x40); /* 0007ffff DST_PITCH */ ++ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */ ++ xf_emit(ctx, 1, 0); /* 0000ffff */ ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK15AC */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_ZETA */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 2, 0); /* ffff, ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* ffffffff ZETA_LAYER_STRIDE */ ++ xf_emit(ctx, 1, 0); /* 000000ff ZETA_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff ZETA_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 4); /* 00000007 ZETA_TILE_MODE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ xf_emit(ctx, 1, 0x400); /* 0fffffff ZETA_HORIZ */ ++ xf_emit(ctx, 1, 0x300); /* 0000ffff ZETA_VERT */ ++ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 0); /* 00000001 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */ ++ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */ ++ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ ++ xf_emit(ctx, 1, 0); /* 7 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ } ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ + if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 1, 0x0fac6881); +- xf_emit(ctx, 1, magic2); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 3, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 2, 1); +- else +- xf_emit(ctx, 1, 1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 2, 0); +- else if (dev_priv->chipset != 0x50) +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 1, 0x0fac6881); /* fffffff */ ++ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */ ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */ ++ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* 0000000f tesla UNK15C8 */ ++ } ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */ ++ if (dev_priv->chipset >= 0xa0) { ++ xf_emit(ctx, 3, 0); /* 7/f, 1, ffff0ff3 */ ++ xf_emit(ctx, 1, 0xfac6881); /* fffffff */ ++ xf_emit(ctx, 4, 0); /* 1, 1, 1, 3ff */ ++ xf_emit(ctx, 1, 4); /* 7 */ ++ xf_emit(ctx, 1, 0); /* 1 */ ++ xf_emit(ctx, 2, 1); /* 1 */ ++ xf_emit(ctx, 2, 0); /* 7, f */ ++ xf_emit(ctx, 1, 1); /* 1 */ ++ xf_emit(ctx, 1, 0); /* 7/f */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 0x9, 0); /* 1 */ ++ else ++ xf_emit(ctx, 0x8, 0); /* 1 */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 8, 1); /* 1 */ ++ xf_emit(ctx, 1, 0x11); /* 7f */ ++ xf_emit(ctx, 7, 0); /* 7f */ ++ xf_emit(ctx, 1, 0xfac6881); /* fffffff */ ++ xf_emit(ctx, 1, 0xf); /* f */ ++ xf_emit(ctx, 7, 0); /* f */ ++ xf_emit(ctx, 1, 0x11); /* 7f */ ++ xf_emit(ctx, 1, 1); /* 1 */ ++ xf_emit(ctx, 5, 0); /* 1, 7, 3ff, 3, 7 */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ } ++ } + } + + static void +-nv50_graph_construct_xfer_tp_x3(struct nouveau_grctx *ctx) ++nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */ ++ if (dev_priv->chipset != 0x50) ++ xf_emit(ctx, 1, 0); /* 3 */ ++ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DU_DX_INT */ ++ xf_emit(ctx, 1, 0); /* fffff BLIT_DU_DX_FRACT */ ++ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DV_DY_INT */ ++ xf_emit(ctx, 1, 0); /* fffff BLIT_DV_DY_FRACT */ + if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 2, 0); ++ xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */ + else +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0x2a712488); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x4085c000); +- xf_emit(ctx, 1, 0x40); +- xf_emit(ctx, 1, 0x100); +- xf_emit(ctx, 1, 0x10100); +- xf_emit(ctx, 1, 0x02800000); ++ xf_emit(ctx, 2, 0); /* 3ff, 1 */ ++ xf_emit(ctx, 1, 0x2a712488); /* ffffffff SRC_TIC_0 */ ++ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_1 */ ++ xf_emit(ctx, 1, 0x4085c000); /* ffffffff SRC_TIC_2 */ ++ xf_emit(ctx, 1, 0x40); /* ffffffff SRC_TIC_3 */ ++ xf_emit(ctx, 1, 0x100); /* ffffffff SRC_TIC_4 */ ++ xf_emit(ctx, 1, 0x10100); /* ffffffff SRC_TIC_5 */ ++ xf_emit(ctx, 1, 0x02800000); /* ffffffff SRC_TIC_6 */ ++ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_7 */ ++ if (dev_priv->chipset == 0x50) { ++ xf_emit(ctx, 1, 0); /* 00000001 turing UNK358 */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */ ++ xf_emit(ctx, 1, 0); /* 00000003 turing UNK37C tesla UNK1690 */ ++ xf_emit(ctx, 1, 0); /* 00000003 BLIT_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000001 turing UNK32C tesla UNK0F94 */ ++ } else if (!IS_NVAAF(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1664 / turing UNK03E8 */ ++ xf_emit(ctx, 1, 0); /* 00000003 */ ++ xf_emit(ctx, 1, 0); /* 000003ff */ ++ } else { ++ xf_emit(ctx, 0x6, 0); ++ } ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TEXTURE */ ++ xf_emit(ctx, 1, 0); /* 0000ffff DMA_SRC */ + } + + static void +-nv50_graph_construct_xfer_tp_x4(struct nouveau_grctx *ctx) ++nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- xf_emit(ctx, 2, 0x04e3bfdf); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x00ffff00); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 2, 1); +- else +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 0x00ffff00); +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0x30201000); +- xf_emit(ctx, 1, 0x70605040); +- xf_emit(ctx, 1, 0xb8a89888); +- xf_emit(ctx, 1, 0xf8e8d8c8); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x1a); +-} +- +-static void +-nv50_graph_construct_xfer_tp_x5(struct nouveau_grctx *ctx) +-{ +- struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 0xfac6881); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 2, 0); +- xf_emit(ctx, 1, 1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0xb, 0); +- else +- xf_emit(ctx, 0xa, 0); +- xf_emit(ctx, 8, 1); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0xfac6881); +- xf_emit(ctx, 1, 0xf); +- xf_emit(ctx, 7, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 1); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 6, 0); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 6, 0); +- } else { +- xf_emit(ctx, 0xb, 0); +- } ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 2, 0); /* 7, ffff0ff3 */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */ ++ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */ ++ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK0F98 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */ ++ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */ ++ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */ ++ xf_emit(ctx, 1, 0); /* ffff0ff3 */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */ ++ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */ ++ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */ ++ xf_emit(ctx, 1, 0x30201000); /* ffffffff tesla UNK1670 */ ++ xf_emit(ctx, 1, 0x70605040); /* ffffffff tesla UNK1670 */ ++ xf_emit(ctx, 1, 0xb8a89888); /* ffffffff tesla UNK1670 */ ++ xf_emit(ctx, 1, 0xf8e8d8c8); /* ffffffff tesla UNK1670 */ ++ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */ ++ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */ + } + + static void +@@ -2193,108 +3102,136 @@ nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + if (dev_priv->chipset < 0xa0) { +- nv50_graph_construct_xfer_tp_x1(ctx); +- nv50_graph_construct_xfer_tp_x2(ctx); +- nv50_graph_construct_xfer_tp_x3(ctx); +- if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 0xf, 0); +- else +- xf_emit(ctx, 0x12, 0); +- nv50_graph_construct_xfer_tp_x4(ctx); ++ nv50_graph_construct_xfer_unk84xx(ctx); ++ nv50_graph_construct_xfer_tprop(ctx); ++ nv50_graph_construct_xfer_tex(ctx); ++ nv50_graph_construct_xfer_unk8cxx(ctx); + } else { +- nv50_graph_construct_xfer_tp_x3(ctx); +- if (dev_priv->chipset < 0xaa) +- xf_emit(ctx, 0xc, 0); +- else +- xf_emit(ctx, 0xa, 0); +- nv50_graph_construct_xfer_tp_x2(ctx); +- nv50_graph_construct_xfer_tp_x5(ctx); +- nv50_graph_construct_xfer_tp_x4(ctx); +- nv50_graph_construct_xfer_tp_x1(ctx); ++ nv50_graph_construct_xfer_tex(ctx); ++ nv50_graph_construct_xfer_tprop(ctx); ++ nv50_graph_construct_xfer_unk8cxx(ctx); ++ nv50_graph_construct_xfer_unk84xx(ctx); + } + } + + static void +-nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx) ++nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx) + { + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; +- int i, mpcnt; +- if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa) +- mpcnt = 1; +- else if (dev_priv->chipset < 0xa0 || dev_priv->chipset >= 0xa8) +- mpcnt = 2; +- else +- mpcnt = 3; ++ int i, mpcnt = 2; ++ switch (dev_priv->chipset) { ++ case 0x98: ++ case 0xaa: ++ mpcnt = 1; ++ break; ++ case 0x50: ++ case 0x84: ++ case 0x86: ++ case 0x92: ++ case 0x94: ++ case 0x96: ++ case 0xa8: ++ case 0xac: ++ mpcnt = 2; ++ break; ++ case 0xa0: ++ case 0xa3: ++ case 0xa5: ++ case 0xaf: ++ mpcnt = 3; ++ break; ++ } + for (i = 0; i < mpcnt; i++) { +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x80); +- xf_emit(ctx, 1, 0x80007004); +- xf_emit(ctx, 1, 0x04000400); ++ xf_emit(ctx, 1, 0); /* ff */ ++ xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */ ++ xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */ ++ xf_emit(ctx, 1, 0x04000400); /* ffffffff */ + if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 1, 0xc0); +- xf_emit(ctx, 1, 0x1000); +- xf_emit(ctx, 2, 0); +- if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) { +- xf_emit(ctx, 1, 0xe00); +- xf_emit(ctx, 1, 0x1e00); ++ xf_emit(ctx, 1, 0xc0); /* 00007fff tesla UNK152C */ ++ xf_emit(ctx, 1, 0x1000); /* 0000ffff tesla UNK0D60 */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */ ++ if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0xe00); /* 7fff */ ++ xf_emit(ctx, 1, 0x1e00); /* 7fff */ + } +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0); ++ xf_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP */ ++ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ + if (dev_priv->chipset == 0x50) +- xf_emit(ctx, 2, 0x1000); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 2); +- if (dev_priv->chipset >= 0xaa) +- xf_emit(ctx, 0xb, 0); ++ xf_emit(ctx, 2, 0x1000); /* 7fff tesla UNK141C */ ++ xf_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP */ ++ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */ ++ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */ ++ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ ++ if (IS_NVAAF(dev_priv->chipset)) ++ xf_emit(ctx, 0xb, 0); /* RO */ + else if (dev_priv->chipset >= 0xa0) +- xf_emit(ctx, 0xc, 0); ++ xf_emit(ctx, 0xc, 0); /* RO */ + else +- xf_emit(ctx, 0xa, 0); ++ xf_emit(ctx, 0xa, 0); /* RO */ + } +- xf_emit(ctx, 1, 0x08100c12); +- xf_emit(ctx, 1, 0); ++ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ + if (dev_priv->chipset >= 0xa0) { +- xf_emit(ctx, 1, 0x1fe21); ++ xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */ + } +- xf_emit(ctx, 5, 0); +- xf_emit(ctx, 4, 0xffff); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 2, 0x10001); +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 0x1fe21); +- xf_emit(ctx, 1, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 1); +- xf_emit(ctx, 4, 0); +- xf_emit(ctx, 1, 0x08100c12); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 8, 0); +- xf_emit(ctx, 1, 0xfac6881); +- xf_emit(ctx, 1, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) +- xf_emit(ctx, 1, 3); +- xf_emit(ctx, 3, 0); +- xf_emit(ctx, 1, 4); +- xf_emit(ctx, 9, 0); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 2, 1); +- xf_emit(ctx, 1, 2); +- xf_emit(ctx, 3, 1); +- xf_emit(ctx, 1, 0); +- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) { +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 0x10, 1); +- xf_emit(ctx, 8, 2); +- xf_emit(ctx, 0x18, 1); +- xf_emit(ctx, 3, 0); ++ xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */ ++ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */ ++ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */ ++ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */ ++ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */ ++ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */ ++ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */ ++ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */ ++ xf_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */ ++ xf_emit(ctx, 1, 0x1fe21); /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */ ++ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ ++ xf_emit(ctx, 1, 0); /* ff/3ff */ ++ xf_emit(ctx, 1, 0); /* 1 LINKED_TSC */ ++ xf_emit(ctx, 1, 0); /* ff FP_ADDRESS_HIGH */ ++ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */ ++ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */ ++ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 000000ff FRAG_COLOR_CLAMP_EN */ ++ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */ ++ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */ ++ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 00000007 */ ++ xf_emit(ctx, 1, 0xfac6881); /* 0fffffff RT_CONTROL */ ++ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */ ++ if (IS_NVA3F(dev_priv->chipset)) ++ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */ ++ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */ ++ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */ ++ xf_emit(ctx, 1, 4); /* ffffffff tesla UNK1400 */ ++ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */ ++ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */ ++ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */ ++ if (IS_NVA3F(dev_priv->chipset)) { ++ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */ ++ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */ ++ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */ ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */ ++ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */ + } +- xf_emit(ctx, 1, 4); ++ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */ ++ xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */ ++ /* XXX: demagic this part some day */ + if (dev_priv->chipset == 0x50) + xf_emit(ctx, 0x3a0, 0); + else if (dev_priv->chipset < 0x94) +@@ -2303,9 +3240,9 @@ nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx) + xf_emit(ctx, 0x39f, 0); + else + xf_emit(ctx, 0x3a3, 0); +- xf_emit(ctx, 1, 0x11); +- xf_emit(ctx, 1, 0); +- xf_emit(ctx, 1, 1); ++ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */ ++ xf_emit(ctx, 1, 0); /* 7 OPERATION */ ++ xf_emit(ctx, 1, 1); /* 1 DST_LINEAR */ + xf_emit(ctx, 0x2d, 0); + } + +@@ -2323,52 +3260,56 @@ nv50_graph_construct_xfer2(struct nouveau_grctx *ctx) + if (dev_priv->chipset < 0xa0) { + for (i = 0; i < 8; i++) { + ctx->ctxvals_pos = offset + i; ++ /* that little bugger belongs to csched. No idea ++ * what it's doing here. */ + if (i == 0) +- xf_emit(ctx, 1, 0x08100c12); ++ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */ + if (units & (1 << i)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } + } else { + /* Strand 0: TPs 0, 1 */ + ctx->ctxvals_pos = offset; +- xf_emit(ctx, 1, 0x08100c12); ++ /* that little bugger belongs to csched. No idea ++ * what it's doing here. */ ++ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */ + if (units & (1 << 0)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 1)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + +- /* Strand 0: TPs 2, 3 */ ++ /* Strand 1: TPs 2, 3 */ + ctx->ctxvals_pos = offset + 1; + if (units & (1 << 2)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 3)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + +- /* Strand 0: TPs 4, 5, 6 */ ++ /* Strand 2: TPs 4, 5, 6 */ + ctx->ctxvals_pos = offset + 2; + if (units & (1 << 4)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 5)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 6)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + +- /* Strand 0: TPs 7, 8, 9 */ ++ /* Strand 3: TPs 7, 8, 9 */ + ctx->ctxvals_pos = offset + 3; + if (units & (1 << 7)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 8)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if (units & (1 << 9)) +- nv50_graph_construct_xfer_tp2(ctx); ++ nv50_graph_construct_xfer_mpc(ctx); + if ((ctx->ctxvals_pos-offset)/8 > size) + size = (ctx->ctxvals_pos-offset)/8; + } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c -index 5f21df3..1fd5207 100644 +index 5f21df3..092057b 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -35,8 +35,6 @@ struct nv50_instmem_priv { @@ -9522,7 +15849,15 @@ index 5f21df3..1fd5207 100644 }; #define NV50_INSTMEM_PAGE_SHIFT 12 -@@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev) +@@ -141,13 +139,15 @@ nv50_instmem_init(struct drm_device *dev) + chan->file_priv = (struct drm_file *)-2; + dev_priv->fifos[0] = dev_priv->fifos[127] = chan; + ++ INIT_LIST_HEAD(&chan->ramht_refs); ++ + /* Channel's PRAMIN object + heap */ + ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, + NULL, &chan->ramin); if (ret) return ret; @@ -9531,7 +15866,7 @@ index 5f21df3..1fd5207 100644 return -ENOMEM; /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ -@@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev) +@@ -262,30 +262,25 @@ nv50_instmem_init(struct drm_device *dev) /* Assume that praying isn't enough, check that we can re-read the * entire fake channel back from the PRAMIN BAR */ @@ -9556,7 +15891,15 @@ index 5f21df3..1fd5207 100644 NV_ERROR(dev, "Failed to init RAMIN heap\n"); } -@@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev) + /*XXX: incorrect, but needed to make hash func "work" */ + dev_priv->ramht_offset = 0x10000; + dev_priv->ramht_bits = 9; +- dev_priv->ramht_size = (1 << dev_priv->ramht_bits); ++ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; + return 0; + } + +@@ -321,7 +316,7 @@ nv50_instmem_takedown(struct drm_device *dev) nouveau_gpuobj_del(dev, &chan->vm_pd); nouveau_gpuobj_ref_del(dev, &chan->ramfc); nouveau_gpuobj_ref_del(dev, &chan->ramin); @@ -9565,7 +15908,7 @@ index 5f21df3..1fd5207 100644 dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; kfree(chan); -@@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -436,14 +431,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) return -EINVAL; @@ -9582,15 +15925,18 @@ index 5f21df3..1fd5207 100644 gpuobj->im_pramin->start, pte, pte_end); NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); -@@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -453,27 +448,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) vram |= 0x30; } - dev_priv->engine.instmem.prepare_access(dev, true); while (pte < pte_end) { - nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); - nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); +- nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); +- nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); ++ nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); ++ nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); vram += NV50_INSTMEM_PAGE_SIZE; ++ pte += 2; } - dev_priv->engine.instmem.finish_access(dev); - @@ -9613,14 +15959,17 @@ index 5f21df3..1fd5207 100644 gpuobj->im_bound = 1; return 0; -@@ -492,36 +473,36 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -492,36 +476,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) pte = (gpuobj->im_pramin->start >> 12) << 1; pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; - dev_priv->engine.instmem.prepare_access(dev, true); while (pte < pte_end) { - nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); - nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); +- nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); +- nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); ++ nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 0, 0x00000000); ++ nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 4, 0x00000000); ++ pte += 2; } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); @@ -10096,10 +16445,10 @@ index 0000000..edf2b21 +} diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c new file mode 100644 -index 0000000..b66c913 +index 0000000..9238c73 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c -@@ -0,0 +1,231 @@ +@@ -0,0 +1,234 @@ +/* + * Copyright 2010 Red Hat Inc. + * @@ -10244,14 +16593,16 @@ index 0000000..b66c913 +nvc0_instmem_suspend(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 *buf; + int i; + + dev_priv->susres.ramin_copy = vmalloc(65536); + if (!dev_priv->susres.ramin_copy) + return -ENOMEM; ++ buf = dev_priv->susres.ramin_copy; + -+ for (i = 0x700000; i < 0x710000; i += 4) -+ dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); ++ for (i = 0; i < 65536; i += 4) ++ buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); + return 0; +} + @@ -10259,14 +16610,15 @@ index 0000000..b66c913 +nvc0_instmem_resume(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 *buf = dev_priv->susres.ramin_copy; + u64 chan; + int i; + + chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; + nv_wr32(dev, 0x001700, chan >> 16); + -+ for (i = 0x700000; i < 0x710000; i += 4) -+ nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); ++ for (i = 0; i < 65536; i += 4) ++ nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); + vfree(dev_priv->susres.ramin_copy); + dev_priv->susres.ramin_copy = NULL; + @@ -10323,7 +16675,7 @@ index 0000000..b66c913 + /*XXX: incorrect, but needed to make hash func "work" */ + dev_priv->ramht_offset = 0x10000; + dev_priv->ramht_bits = 9; -+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits); ++ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; + return 0; +} + @@ -10365,5 +16717,5 @@ index 5998c35..ad64673 100644 # define NV_PCRTC_INTR_0_VBLANK (1 << 0) #define NV_PCRTC_INTR_EN_0 0x00600140 -- -1.7.2 +1.7.2.2 diff --git a/kernel.spec b/kernel.spec index 0b9539b92..5685f601e 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 18 +%global baserelease 19 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1900,6 +1900,9 @@ fi # and build. %changelog +* Mon Sep 04 2010 Ben Skeggs 2.6.35.4-19 +- nouveau: misc fixes from upstream + NVAF support + * Fri Sep 03 2010 Kyle McMartin - Restore appleir driver that got lost in the 2.6.35 rebase. From 8ccfe4ce6aa6cd6e49e2ac2824c0d00b248e5344 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 6 Sep 2010 02:10:02 -0400 Subject: [PATCH 035/277] Restore the rest of the appleir driver patch Signed-off-by: Jarod Wilson --- add-appleir-usb-driver.patch | 596 ++++++++++++++++++++++++++++++++--- kernel.spec | 7 +- 2 files changed, 559 insertions(+), 44 deletions(-) diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch index 4d83e70e6..821d200be 100644 --- a/add-appleir-usb-driver.patch +++ b/add-appleir-usb-driver.patch @@ -1,18 +1,97 @@ -appleir usb driver from hadess +commit 92c912df2a0725d719263357176f98b2201a2acd +Author: Bastien Nocera +Date: Wed Apr 21 14:51:58 2010 +0100 ---- - drivers/hid/hid-apple.c | 4 ---- - drivers/hid/hid-core.c | 5 +++-- - drivers/hid/hid-ids.h | 1 + - drivers/input/misc/Kconfig | 13 +++++++++++++ - drivers/input/misc/Makefile | 1 + - 5 files changed, 18 insertions(+), 6 deletions(-) + Input: add appleir USB driver + + This driver was originally written by James McKenzie, updated by + Greg Kroah-Hartman, further updated by myself, with suspend support + added. + + More recent versions of the IR receiver are also supported through + a patch by Alex Karpenko. + + Tested on a MacbookAir1,1 + + Signed-off-by: Bastien Nocera +commit 6ffcbf68913840e9e882db14441576ffee6eba0c +Author: Bastien Nocera +Date: Fri Apr 16 17:19:50 2010 +0100 + + Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE + + Add two quirks to make it possible for usbhid module options to + override whether a device is ignored (HID_QUIRK_NO_IGNORE) and + whether to connect a hiddev device (HID_QUIRK_HIDDEV_FORCE). + + Passing HID_QUIRK_NO_IGNORE for your device means that it will + not be ignored by the HID layer, even if present in a blacklist. + + HID_QUIRK_HIDDEV_FORCE will force the creation of a hiddev for that + device, making it accessible from user-space. + + Tested with an Apple IR Receiver, switching it from using appleir + to using lirc's macmini driver. + + Signed-off-by: Bastien Nocera + +diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt +new file mode 100644 +index 0000000..0267a4b +--- /dev/null ++++ b/Documentation/input/appleir.txt +@@ -0,0 +1,45 @@ ++Apple IR receiver Driver (appleir) ++---------------------------------- ++ Copyright (C) 2009 Bastien Nocera ++ ++The appleir driver is a kernel input driver to handle Apple's IR ++receivers (and associated remotes) in the kernel. ++ ++The driver is an input driver which only handles "official" remotes ++as built and sold by Apple. ++ ++Authors ++------- ++ ++James McKenzie (original driver) ++Alex Karpenko (05ac:8242 support) ++Greg Kroah-Hartman (cleanups and original submission) ++Bastien Nocera (further cleanups and suspend support) ++ ++Supported hardware ++------------------ ++ ++- All Apple laptops and desktops from 2005 onwards, except: ++ - the unibody Macbook (2009) ++ - Mac Pro (all versions) ++- Apple TV (all revisions) ++ ++The remote will only support the 6 buttons of the original remotes ++as sold by Apple. See the next section if you want to use other remotes ++or want to use lirc with the device instead of the kernel driver. ++ ++Using lirc (native) instead of the kernel driver ++------------------------------------------------ ++ ++First, you will need to disable the kernel driver for the receiver. ++ ++This can be achieved by passing quirks to the usbhid driver. ++The quirk line would be: ++usbhid.quirks=0x05ac:0x8242:0x40000010 ++ ++With 0x05ac being the vendor ID (Apple, you shouldn't need to change this) ++With 0x8242 being the product ID (check the output of lsusb for your hardware) ++And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE" ++ ++This should force the creation of a hiddev device for the receiver, and ++make it usable under lirc. diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index bba05d0..0059d5a 100644 +index 5b4d66d..b0e1811 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c -@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev) +@@ -353,10 +353,6 @@ static void apple_remove(struct hid_device *hdev) } static const struct hid_device_id apple_devices[] = { @@ -23,34 +102,11 @@ index bba05d0..0059d5a 100644 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index 866e54e..42c2a27 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -1239,8 +1239,6 @@ static const struct hid_device_id hid_blacklist[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, -@@ -1574,6 +1572,9 @@ static const struct hid_device_id hid_ignore_list[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 31601ee..280b7a8 100644 +index 793691f..9255c1a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -98,6 +98,7 @@ +@@ -93,6 +93,7 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b @@ -59,10 +115,10 @@ index 31601ee..280b7a8 100644 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index c44b9ea..90b85a6 100644 +index 16ec523..4340986 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig -@@ -199,6 +199,19 @@ config INPUT_KEYSPAN_REMOTE +@@ -149,6 +149,19 @@ config INPUT_KEYSPAN_REMOTE To compile this driver as a module, choose M here: the module will be called keyspan_remote. @@ -83,10 +139,10 @@ index c44b9ea..90b85a6 100644 tristate "Griffin PowerMate and Contour Jog support" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index 71fe57d..62a5c60 100644 +index a8b8485..041e6f5 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile -@@ -9,6 +9,7 @@ obj-$(CONFIG_INPUT_AD714X) += ad714x.o +@@ -5,6 +5,7 @@ obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o @@ -94,6 +150,462 @@ index 71fe57d..62a5c60 100644 obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o --- -1.7.2.2 - +diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c +new file mode 100644 +index 0000000..cff4df6 +--- /dev/null ++++ b/drivers/input/misc/appleir.c +@@ -0,0 +1,453 @@ ++/* ++ * appleir: USB driver for the apple ir device ++ * ++ * Original driver written by James McKenzie ++ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman ++ * ++ * Copyright (C) 2006 James McKenzie ++ * Copyright (C) 2008 Greg Kroah-Hartman ++ * Copyright (C) 2008 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation, version 2. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_VERSION "v1.2" ++#define DRIVER_AUTHOR "James McKenzie" ++#define DRIVER_DESC "Apple infrared receiver driver" ++#define DRIVER_LICENSE "GPL" ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE(DRIVER_LICENSE); ++ ++#define USB_VENDOR_ID_APPLE 0x05ac ++#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 ++#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 ++#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 ++ ++#define URB_SIZE 32 ++ ++#define MAX_KEYS 8 ++#define MAX_KEYS_MASK (MAX_KEYS - 1) ++ ++#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); ++ ++/* I have two devices both of which report the following */ ++/* 25 87 ee 83 0a + */ ++/* 25 87 ee 83 0c - */ ++/* 25 87 ee 83 09 << */ ++/* 25 87 ee 83 06 >> */ ++/* 25 87 ee 83 05 >" */ ++/* 25 87 ee 83 03 menu */ ++/* 26 00 00 00 00 for key repeat*/ ++ ++/* Thomas Glanzmann reports the following responses */ ++/* 25 87 ee ca 0b + */ ++/* 25 87 ee ca 0d - */ ++/* 25 87 ee ca 08 << */ ++/* 25 87 ee ca 07 >> */ ++/* 25 87 ee ca 04 >" */ ++/* 25 87 ee ca 02 menu */ ++/* 26 00 00 00 00 for key repeat*/ ++/* He also observes the following event sometimes */ ++/* sent after a key is release, which I interpret */ ++/* as a flat battery message */ ++/* 25 87 e0 ca 06 flat battery */ ++ ++/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */ ++/* 25 87 ee 47 0b + */ ++/* 25 87 ee 47 0d - */ ++/* 25 87 ee 47 08 << */ ++/* 25 87 ee 47 07 >> */ ++/* 25 87 ee 47 04 >" */ ++/* 25 87 ee 47 02 menu */ ++/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */ ++ ++static const unsigned short appleir_key_table[] = { ++ KEY_RESERVED, ++ KEY_MENU, ++ KEY_PLAYPAUSE, ++ KEY_FORWARD, ++ KEY_BACK, ++ KEY_VOLUMEUP, ++ KEY_VOLUMEDOWN, ++ KEY_RESERVED, ++}; ++ ++struct appleir { ++ struct input_dev *input_dev; ++ unsigned short keymap[ARRAY_SIZE(appleir_key_table)]; ++ u8 *data; ++ dma_addr_t dma_buf; ++ struct usb_device *usbdev; ++ unsigned int flags; ++ struct urb *urb; ++ struct timer_list key_up_timer; ++ int current_key; ++ char phys[32]; ++}; ++ ++static DEFINE_MUTEX(appleir_mutex); ++ ++enum { ++ APPLEIR_OPENED = 0x1, ++ APPLEIR_SUSPENDED = 0x2, ++}; ++ ++static struct usb_device_id appleir_ids[] = { ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, ++ {} ++}; ++MODULE_DEVICE_TABLE(usb, appleir_ids); ++ ++static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len) ++{ ++ int i; ++ ++ printk(KERN_ERR "appleir: %s (%d bytes)", msg, len); ++ ++ for (i = 0; i < len; ++i) ++ printk(" %02x", data[i]); ++ printk("\n"); ++} ++ ++static void key_up(struct appleir *appleir, int key) ++{ ++ dbginfo(&appleir->input_dev->dev, "key %d up\n", key); ++ input_report_key(appleir->input_dev, key, 0); ++ input_sync(appleir->input_dev); ++} ++ ++static void key_down(struct appleir *appleir, int key) ++{ ++ dbginfo(&appleir->input_dev->dev, "key %d down\n", key); ++ input_report_key(appleir->input_dev, key, 1); ++ input_sync(appleir->input_dev); ++} ++ ++static void battery_flat(struct appleir *appleir) ++{ ++ dev_err(&appleir->input_dev->dev, "possible flat battery?\n"); ++} ++ ++static void key_up_tick(unsigned long data) ++{ ++ struct appleir *appleir = (struct appleir *)data; ++ ++ if (appleir->current_key) { ++ key_up(appleir, appleir->current_key); ++ appleir->current_key = 0; ++ } ++} ++ ++static void new_data(struct appleir *appleir, u8 *data, int len) ++{ ++ static const u8 keydown[] = { 0x25, 0x87, 0xee }; ++ static const u8 keyrepeat[] = { 0x26, }; ++ static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 }; ++ ++ if (debug) ++ dump_packet(appleir, "received", data, len); ++ ++ if (len != 5) ++ return; ++ ++ if (!memcmp(data, keydown, sizeof(keydown))) { ++ /* If we already have a key down, take it up before marking ++ this one down */ ++ if (appleir->current_key) ++ key_up(appleir, appleir->current_key); ++ appleir->current_key = appleir->keymap[(data[4] >> 1) & MAX_KEYS_MASK]; ++ ++ key_down(appleir, appleir->current_key); ++ /* Remote doesn't do key up, either pull them up, in the test ++ above, or here set a timer which pulls them up after 1/8 s */ ++ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); ++ ++ return; ++ } ++ ++ if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) { ++ key_down(appleir, appleir->current_key); ++ /* Remote doesn't do key up, either pull them up, in the test ++ above, or here set a timer which pulls them up after 1/8 s */ ++ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); ++ return; ++ } ++ ++ if (!memcmp(data, flatbattery, sizeof(flatbattery))) { ++ battery_flat(appleir); ++ /* Fall through */ ++ } ++ ++ dump_packet(appleir, "unknown packet", data, len); ++} ++ ++static void appleir_urb(struct urb *urb) ++{ ++ struct appleir *appleir = urb->context; ++ int status = urb->status; ++ int retval; ++ ++ switch (status) { ++ case 0: ++ new_data(appleir, urb->transfer_buffer, urb->actual_length); ++ break; ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* This urb is terminated, clean up */ ++ dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__, ++ urb->status); ++ return; ++ default: ++ dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__, ++ urb->status); ++ } ++ ++ retval = usb_submit_urb(urb, GFP_ATOMIC); ++ if (retval) ++ err("%s - usb_submit_urb failed with result %d", __func__, ++ retval); ++} ++ ++static int appleir_open(struct input_dev *dev) ++{ ++ struct appleir *appleir = input_get_drvdata(dev); ++ struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0); ++ int r; ++ ++ r = usb_autopm_get_interface(intf); ++ if (r) { ++ dev_err(&intf->dev, ++ "%s(): usb_autopm_get_interface() = %d\n", __func__, r); ++ return r; ++ } ++ ++ mutex_lock(&appleir_mutex); ++ ++ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) { ++ r = -EIO; ++ goto fail; ++ } ++ ++ appleir->flags |= APPLEIR_OPENED; ++ ++ mutex_unlock(&appleir_mutex); ++ ++ usb_autopm_put_interface(intf); ++ ++ return 0; ++fail: ++ mutex_unlock(&appleir_mutex); ++ usb_autopm_put_interface(intf); ++ return r; ++} ++ ++static void appleir_close(struct input_dev *dev) ++{ ++ struct appleir *appleir = input_get_drvdata(dev); ++ ++ mutex_lock(&appleir_mutex); ++ ++ if (!(appleir->flags & APPLEIR_SUSPENDED)) { ++ usb_kill_urb(appleir->urb); ++ del_timer_sync(&appleir->key_up_timer); ++ } ++ ++ appleir->flags &= ~APPLEIR_OPENED; ++ ++ mutex_unlock(&appleir_mutex); ++} ++ ++static int appleir_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ struct usb_endpoint_descriptor *endpoint; ++ struct appleir *appleir = NULL; ++ struct input_dev *input_dev; ++ int retval = -ENOMEM; ++ int i; ++ ++ appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL); ++ if (!appleir) ++ goto allocfail; ++ ++ appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL, ++ &appleir->dma_buf); ++ if (!appleir->data) ++ goto usbfail; ++ ++ appleir->urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!appleir->urb) ++ goto urbfail; ++ ++ appleir->usbdev = dev; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ goto inputfail; ++ ++ appleir->input_dev = input_dev; ++ ++ usb_make_path(dev, appleir->phys, sizeof(appleir->phys)); ++ strlcpy(appleir->phys, "/input0", sizeof(appleir->phys)); ++ ++ input_dev->name = "Apple Infrared Remote Controller"; ++ input_dev->phys = appleir->phys; ++ usb_to_input_id(dev, &input_dev->id); ++ input_dev->dev.parent = &intf->dev; ++ input_dev->keycode = appleir->keymap; ++ input_dev->keycodesize = sizeof(unsigned short); ++ input_dev->keycodemax = ARRAY_SIZE(appleir->keymap); ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); ++ ++ memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap)); ++ for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) ++ set_bit(appleir->keymap[i], input_dev->keybit); ++ clear_bit(KEY_RESERVED, input_dev->keybit); ++ ++ input_set_drvdata(input_dev, appleir); ++ input_dev->open = appleir_open; ++ input_dev->close = appleir_close; ++ ++ endpoint = &intf->cur_altsetting->endpoint[0].desc; ++ ++ usb_fill_int_urb(appleir->urb, dev, ++ usb_rcvintpipe(dev, endpoint->bEndpointAddress), ++ appleir->data, 8, ++ appleir_urb, appleir, endpoint->bInterval); ++ ++ appleir->urb->transfer_dma = appleir->dma_buf; ++ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ setup_timer(&appleir->key_up_timer, ++ key_up_tick, (unsigned long) appleir); ++ ++ retval = input_register_device(appleir->input_dev); ++ if (retval) ++ goto inputfail; ++ ++ usb_set_intfdata(intf, appleir); ++ ++ return 0; ++ ++inputfail: ++ input_free_device(appleir->input_dev); ++ ++urbfail: ++ usb_free_urb(appleir->urb); ++ ++usbfail: ++ usb_free_coherent(dev, URB_SIZE, appleir->data, ++ appleir->dma_buf); ++ ++allocfail: ++ kfree(appleir); ++ ++ return retval; ++} ++ ++static void appleir_disconnect(struct usb_interface *intf) ++{ ++ struct appleir *appleir = usb_get_intfdata(intf); ++ ++ usb_set_intfdata(intf, NULL); ++ input_unregister_device(appleir->input_dev); ++ usb_free_urb(appleir->urb); ++ usb_free_coherent(interface_to_usbdev(intf), URB_SIZE, ++ appleir->data, appleir->dma_buf); ++ kfree(appleir); ++} ++ ++static int appleir_suspend(struct usb_interface *interface, ++ pm_message_t message) ++{ ++ struct appleir *appleir = usb_get_intfdata(interface); ++ ++ mutex_lock(&appleir_mutex); ++ if (appleir->flags & APPLEIR_OPENED) ++ usb_kill_urb(appleir->urb); ++ ++ appleir->flags |= APPLEIR_SUSPENDED; ++ ++ mutex_unlock(&appleir_mutex); ++ ++ return 0; ++} ++ ++static int appleir_resume(struct usb_interface *interface) ++{ ++ struct appleir *appleir; ++ int r = 0; ++ ++ appleir = usb_get_intfdata(interface); ++ ++ mutex_lock(&appleir_mutex); ++ if (appleir->flags & APPLEIR_OPENED) { ++ struct usb_endpoint_descriptor *endpoint; ++ ++ endpoint = &interface->cur_altsetting->endpoint[0].desc; ++ usb_fill_int_urb(appleir->urb, appleir->usbdev, ++ usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress), ++ appleir->data, 8, ++ appleir_urb, appleir, endpoint->bInterval); ++ appleir->urb->transfer_dma = appleir->dma_buf; ++ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ /* And reset the USB device */ ++ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) ++ r = -EIO; ++ } ++ ++ appleir->flags &= ~APPLEIR_SUSPENDED; ++ ++ mutex_unlock(&appleir_mutex); ++ ++ return r; ++} ++ ++static struct usb_driver appleir_driver = { ++ .name = "appleir", ++ .probe = appleir_probe, ++ .disconnect = appleir_disconnect, ++ .suspend = appleir_suspend, ++ .resume = appleir_resume, ++ .reset_resume = appleir_resume, ++ .id_table = appleir_ids, ++}; ++ ++static int __init appleir_init(void) ++{ ++ return usb_register(&appleir_driver); ++} ++ ++static void __exit appleir_exit(void) ++{ ++ usb_deregister(&appleir_driver); ++} ++ ++module_init(appleir_init); ++module_exit(appleir_exit); diff --git a/kernel.spec b/kernel.spec index 5685f601e..afebac71c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 19 +%global baserelease 20 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1900,7 +1900,10 @@ fi # and build. %changelog -* Mon Sep 04 2010 Ben Skeggs 2.6.35.4-19 +* Mon Sep 06 2010 Jarod Wilson 2.6.35.4-20 +- Restore the rest of the appleir driver patch + +* Mon Sep 06 2010 Ben Skeggs 2.6.35.4-19 - nouveau: misc fixes from upstream + NVAF support * Fri Sep 03 2010 Kyle McMartin From cfdae029cc721afae80da35f6fad2383f0386435 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 6 Sep 2010 14:22:48 -0400 Subject: [PATCH 036/277] fix rcu_dereference_check warning --- fix-rcu_deref_check-warning.patch | 27 +++++++++++++++++++++++++++ kernel.spec | 10 ++++++++++ 2 files changed, 37 insertions(+) create mode 100644 fix-rcu_deref_check-warning.patch diff --git a/fix-rcu_deref_check-warning.patch b/fix-rcu_deref_check-warning.patch new file mode 100644 index 000000000..12199d470 --- /dev/null +++ b/fix-rcu_deref_check-warning.patch @@ -0,0 +1,27 @@ +diff --git a/kernel/sched.c b/kernel/sched.c +index 6d0dbeb..3640c20 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -5155,9 +5155,11 @@ void __cpuinit init_idle_bootup_task(struct task_struct *idle) + void __cpuinit init_idle(struct task_struct *idle, int cpu) + { + struct rq *rq = cpu_rq(cpu); ++ struct rq *oldrq = task_rq(idle); + unsigned long flags; + +- raw_spin_lock_irqsave(&rq->lock, flags); ++ local_irq_save(flags); ++ double_rq_lock(oldrq, rq); + + __sched_fork(idle); + idle->state = TASK_RUNNING; +@@ -5170,7 +5172,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) + #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) + idle->oncpu = 1; + #endif +- raw_spin_unlock_irqrestore(&rq->lock, flags); ++ double_rq_unlock(oldrq, rq); ++ local_irq_restore(flags); + + /* Set the preempt count _outside_ the spinlocks! */ + #if defined(CONFIG_PREEMPT) diff --git a/kernel.spec b/kernel.spec index afebac71c..d4445c694 100644 --- a/kernel.spec +++ b/kernel.spec @@ -712,6 +712,9 @@ Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch +# rhbz #622149 +Patch12085: fix-rcu_deref_check-warning.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1314,6 +1317,9 @@ ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch # bz 610941 ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch +# bz 622149 +ApplyPatch fix-rcu_deref_check-warning.patch + # END OF PATCH APPLICATIONS %endif @@ -1900,6 +1906,10 @@ fi # and build. %changelog +* Mon Sep 06 2010 Kyle McMartin +- Patch from paulmck to fix rcu_dereference_check warning + (http://lkml.org/lkml/2010/8/16/258) + * Mon Sep 06 2010 Jarod Wilson 2.6.35.4-20 - Restore the rest of the appleir driver patch From 426c30b2f1288770b9ad986d4ab219fae2cf4002 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 6 Sep 2010 15:17:29 -0400 Subject: [PATCH 037/277] add in f13 patch to fix eject key on dell studio 1555 --- ...dd-support-for-eject-key-studio-1555.patch | 29 +++++++++++++++++++ kernel.spec | 10 +++++++ 2 files changed, 39 insertions(+) create mode 100644 dell-wmi-add-support-for-eject-key-studio-1555.patch diff --git a/dell-wmi-add-support-for-eject-key-studio-1555.patch b/dell-wmi-add-support-for-eject-key-studio-1555.patch new file mode 100644 index 000000000..f806196b1 --- /dev/null +++ b/dell-wmi-add-support-for-eject-key-studio-1555.patch @@ -0,0 +1,29 @@ +From: Islam Amer +Date: Thu, 24 Jun 2010 17:39:47 +0000 (-0400) +Subject: dell-wmi: Add support for eject key on Dell Studio 1555 +X-Git-Tag: v2.6.36-rc1~579^2~64 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d5164dbf1f651d1e955b158fb70a9c844cc91cd1 + +dell-wmi: Add support for eject key on Dell Studio 1555 + +Fixes pressing the eject key on Dell Studio 1555 does not work and produces +message : + +dell-wmi: Unknown key 0 pressed + +Signed-off-by: Islam Amer +--- + +diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c +index 66f53c3..12a8e6f 100644 +--- a/drivers/platform/x86/dell-wmi.c ++++ b/drivers/platform/x86/dell-wmi.c +@@ -221,7 +221,7 @@ static void dell_wmi_notify(u32 value, void *context) + return; + } + +- if (dell_new_hk_type) ++ if (dell_new_hk_type || buffer_entry[1] == 0x0) + reported_key = (int)buffer_entry[2]; + else + reported_key = (int)buffer_entry[1] & 0xffff; diff --git a/kernel.spec b/kernel.spec index d4445c694..cafb93548 100644 --- a/kernel.spec +++ b/kernel.spec @@ -715,6 +715,9 @@ Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # rhbz #622149 Patch12085: fix-rcu_deref_check-warning.patch +# rhbz #513530 +Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1320,6 +1323,9 @@ ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # bz 622149 ApplyPatch fix-rcu_deref_check-warning.patch +# bz 513530 +ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch + # END OF PATCH APPLICATIONS %endif @@ -1906,6 +1912,10 @@ fi # and build. %changelog +* Mon Sep 06 2010 Kyle McMartin +- Suck in patch from F-13 to add support for the eject key on the + Dell Studio 1555. (#513530) + * Mon Sep 06 2010 Kyle McMartin - Patch from paulmck to fix rcu_dereference_check warning (http://lkml.org/lkml/2010/8/16/258) From 8b695bdd15271288d751966dcabdfe7230caa93a Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 6 Sep 2010 16:05:54 -0400 Subject: [PATCH 038/277] flexcop: fix registering braindead stupid names (#575873) --- flexcop-fix-xlate_proc_name-warning.patch | 30 +++++++++++++++++++++++ kernel.spec | 6 +++++ 2 files changed, 36 insertions(+) create mode 100644 flexcop-fix-xlate_proc_name-warning.patch diff --git a/flexcop-fix-xlate_proc_name-warning.patch b/flexcop-fix-xlate_proc_name-warning.patch new file mode 100644 index 000000000..82b50a47f --- /dev/null +++ b/flexcop-fix-xlate_proc_name-warning.patch @@ -0,0 +1,30 @@ +diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c +index 227c020..7465308 100644 +--- a/drivers/media/dvb/b2c2/flexcop-pci.c ++++ b/drivers/media/dvb/b2c2/flexcop-pci.c +@@ -39,6 +39,7 @@ MODULE_PARM_DESC(debug, + + #define DRIVER_VERSION "0.1" + #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" ++#define FLEXCOP_MODULE_NAME "b2c2-flexcop" + #define DRIVER_AUTHOR "Patrick Boettcher " + + struct flexcop_pci { +@@ -299,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) + return ret; + pci_set_master(fc_pci->pdev); + +- if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) ++ if ((ret = pci_request_regions(fc_pci->pdev, FLEXCOP_MODULE_NAME)) != 0) + goto err_pci_disable_device; + + fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); +@@ -313,7 +314,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) + pci_set_drvdata(fc_pci->pdev, fc_pci); + spin_lock_init(&fc_pci->irq_lock); + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, +- IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) ++ IRQF_SHARED, FLEXCOP_MODULE_NAME, fc_pci)) != 0) + goto err_pci_iounmap; + + fc_pci->init_state |= FC_PCI_INIT; diff --git a/kernel.spec b/kernel.spec index cafb93548..6339070d7 100644 --- a/kernel.spec +++ b/kernel.spec @@ -718,6 +718,8 @@ Patch12085: fix-rcu_deref_check-warning.patch # rhbz #513530 Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch +Patch12517: flexcop-fix-xlate_proc_name-warning.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1326,6 +1328,9 @@ ApplyPatch fix-rcu_deref_check-warning.patch # bz 513530 ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch +# bz #575873 +ApplyPatch flexcop-fix-xlate_proc_name-warning.patch + # END OF PATCH APPLICATIONS %endif @@ -1915,6 +1920,7 @@ fi * Mon Sep 06 2010 Kyle McMartin - Suck in patch from F-13 to add support for the eject key on the Dell Studio 1555. (#513530) +- flexcop: fix registering braindead stupid names (#575873) * Mon Sep 06 2010 Kyle McMartin - Patch from paulmck to fix rcu_dereference_check warning From f4da561c3d57c9020b84894e31a750fb3b32347b Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 7 Sep 2010 12:07:10 -0400 Subject: [PATCH 039/277] Enhance HID layer to fully support TiVo Slide remote and dongle Signed-off-by: Jarod Wilson --- hid-support-tivo-slide-remote.patch | 163 ++++++++++++++++++++++++++++ kernel.spec | 9 +- 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 hid-support-tivo-slide-remote.patch diff --git a/hid-support-tivo-slide-remote.patch b/hid-support-tivo-slide-remote.patch new file mode 100644 index 000000000..3129f57e7 --- /dev/null +++ b/hid-support-tivo-slide-remote.patch @@ -0,0 +1,163 @@ +[PATCH] hid: support for bluetooth tivo slide remote and usb dongle + +This patch adds full support for the TiVo Slide Remote, primarily by way +of extending the existing generic HID support. Only four keys are not +usages within a standard usage page, but they're easily handled by the +addition of a HID_UP_TIVOVENDOR usage page. Note that the UP is 0xffff, +which matches the mask, but its also a valid vendor-specific UP, according +to the spec. + +What's actually connected to the computer is a Broadcom-made usb dongle, +which has an embedded hub, bluetooth adapter, mouse and keyboard devices. +You pair with the dongle, then the remote sends data that its converted +into HID on the keyboard interface (the mouse interface doesn't do anything +interesting right now, so far as I can tell). + +lsusb for this device: +Bus 004 Device 005: ID 0a5c:2190 Broadcom Corp. +Bus 004 Device 004: ID 0a5c:4503 Broadcom Corp. +Bus 004 Device 003: ID 150a:1201 +Bus 004 Device 002: ID 0a5c:4500 Broadcom Corp. BCM2046B1 USB 2.0 Hub (part of BCM2046 Bluetooth) + +Speaking of the keyboard interface, the remote actually does contain a +keyboard as well. The top slides away, revealing a reasonably functional +qwerty keyboard (not unlike many slide cell phones), thus the product +name. + +Now for some caveats... This device seems to report 0xc (consumer usage +page) 0x20 ("+10") after most key presses. At the moment, this will simply +be ignored, but if a mapping for that usage is added, the remote behaves +very badly (we end up w/a repeating/stuck key until another key is pressed). +Not quite sure what to do about that one, if that usage does get mapped. I +guess a device-specific quirk to just ignore it would work. + +Anyway, the thing is working 100% as expected with this patch right now. + +Three more things to note... This patch fixes an incorrect mapping of 0xc 0x45, +which was mapped to KEY_RADIO, which is definitely wrong, but may cause some +existing device to now report KEY_RIGHT there. Second, there's also an +unrelated fix for a redundant KERN_DEBUG in a dbg_hid call. Third, the +additions to HID_UP_GENDESK aren't strictly needed by the remote, but the +dongle does try to register those, and they're all technically correct, so +I've included them for the benefit of a device that comes along and +actually does try to use them. + +Applies cleanly to hid master, tested w/a 2.6.35.4-based Fedora kernel. + +Signed-off-by: Jarod Wilson + +--- + drivers/hid/hid-input.c | 45 ++++++++++++++++++++++++++++++++++++++++----- + include/linux/hid.h | 1 + + 2 files changed, 41 insertions(+), 5 deletions(-) + +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index 6c03dcc..bd1479e 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -44,11 +44,11 @@ static const unsigned char hid_keyboard[256] = { + 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, + 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, +- 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, ++ 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, +- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, ++ unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk + }; +@@ -136,7 +136,7 @@ static int hidinput_setkeycode(struct input_dev *dev, + + clear_bit(old_keycode, dev->keybit); + set_bit(usage->code, dev->keybit); +- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); ++ dbg_hid("Assigned keycode %d to HID usage code %x\n", keycode, scancode); + /* Set the keybit for the old keycode if the old keycode is used + * by another key */ + if (hidinput_find_key (hid, 0, old_keycode)) +@@ -235,6 +235,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + case 0x1: map_key_clear(KEY_POWER); break; + case 0x2: map_key_clear(KEY_SLEEP); break; + case 0x3: map_key_clear(KEY_WAKEUP); break; ++ case 0x4: map_key_clear(KEY_CONTEXT_MENU); break; ++ case 0x5: map_key_clear(KEY_MENU); break; ++ case 0x6: map_key_clear(KEY_PROG1); break; ++ case 0x7: map_key_clear(KEY_HELP); break; ++ case 0x8: map_key_clear(KEY_EXIT); break; ++ case 0x9: map_key_clear(KEY_SELECT); break; ++ case 0xa: map_key_clear(KEY_RIGHT); break; ++ case 0xb: map_key_clear(KEY_LEFT); break; ++ case 0xc: map_key_clear(KEY_UP); break; ++ case 0xd: map_key_clear(KEY_DOWN); break; ++ case 0xe: map_key_clear(KEY_POWER2); break; ++ case 0xf: map_key_clear(KEY_RESTART); break; + default: goto unknown; + } + break; +@@ -343,12 +355,24 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ + switch (usage->hid & HID_USAGE) { + case 0x000: goto ignore; ++ case 0x030: map_key_clear(KEY_POWER); break; + case 0x034: map_key_clear(KEY_SLEEP); break; + case 0x036: map_key_clear(BTN_MISC); break; + + case 0x040: map_key_clear(KEY_MENU); break; +- case 0x045: map_key_clear(KEY_RADIO); break; +- ++ case 0x041: map_key_clear(KEY_SELECT); break; ++ case 0x042: map_key_clear(KEY_UP); break; ++ case 0x043: map_key_clear(KEY_DOWN); break; ++ case 0x044: map_key_clear(KEY_LEFT); break; ++ case 0x045: map_key_clear(KEY_RIGHT); break; ++ ++ case 0x069: map_key_clear(KEY_RED); break; ++ case 0x06a: map_key_clear(KEY_GREEN); break; ++ case 0x06b: map_key_clear(KEY_BLUE); break; ++ case 0x06c: map_key_clear(KEY_YELLOW); break; ++ case 0x06d: map_key_clear(KEY_ZOOM); break; ++ ++ case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; + case 0x083: map_key_clear(KEY_LAST); break; + case 0x088: map_key_clear(KEY_PC); break; + case 0x089: map_key_clear(KEY_TV); break; +@@ -390,6 +414,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + case 0x0e5: map_key_clear(KEY_BASSBOOST); break; + case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; + case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; ++ case 0x0f5: map_key_clear(KEY_SLOW); break; + + case 0x182: map_key_clear(KEY_BOOKMARKS); break; + case 0x183: map_key_clear(KEY_CONFIG); break; +@@ -491,6 +516,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel + } + break; + ++ case HID_UP_TIVOVENDOR: ++ switch (usage->hid & HID_USAGE) { ++ case 0x3d: map_key_clear(KEY_PROG1); break; ++ case 0x3e: map_key_clear(KEY_TV); break; ++ case 0x41: map_key_clear(KEY_PAGEDOWN); break; ++ case 0x42: map_key_clear(KEY_PAGEUP); break; ++ default: goto unknown; ++ } ++ break; ++ + default: + unknown: + if (field->report_size == 1) { +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 42a0f1d..083cfb2 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -200,6 +200,7 @@ struct hid_item { + #define HID_UP_MSVENDOR 0xff000000 + #define HID_UP_CUSTOM 0x00ff0000 + #define HID_UP_LOGIVENDOR 0xffbc0000 ++#define HID_UP_TIVOVENDOR 0xffff0000 + + #define HID_USAGE 0x0000ffff + diff --git a/kernel.spec b/kernel.spec index 6339070d7..dbff5f64c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 20 +%global baserelease 21 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -703,6 +703,8 @@ Patch12018: neuter_intel_microcode_load.patch Patch12019: add-appleir-usb-driver.patch +Patch12020: hid-support-tivo-slide-remote.patch + Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch # rhbz #617699 @@ -1310,6 +1312,8 @@ ApplyPatch disable-i8042-check-on-apple-mac.patch ApplyPatch add-appleir-usb-driver.patch +ApplyPatch hid-support-tivo-slide-remote.patch + ApplyPatch neuter_intel_microcode_load.patch ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch @@ -1917,6 +1921,9 @@ fi # and build. %changelog +* Tue Sep 07 2010 Jarod Wilson 2.6.35.4-21 +- Enhance HID layer to fully support TiVo Slide remote and dongle + * Mon Sep 06 2010 Kyle McMartin - Suck in patch from F-13 to add support for the eject key on the Dell Studio 1555. (#513530) From 2eba9aa0ec1138810962570cdea91570722addf2 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 7 Sep 2010 12:40:07 -0400 Subject: [PATCH 040/277] Disable hung task checker, it only ever causes false positives. (#630777) --- config-generic | 2 +- kernel.spec | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config-generic b/config-generic index 2b97a950b..1d079b5df 100644 --- a/config-generic +++ b/config-generic @@ -4258,7 +4258,7 @@ CONFIG_DEBUG_NX_TEST=m CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -CONFIG_DETECT_HUNG_TASK=y +# CONFIG_DETECT_HUNG_TASK is not set # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set CONFIG_ATOMIC64_SELFTEST=y diff --git a/kernel.spec b/kernel.spec index dbff5f64c..4d2cd3eb8 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 21 +%global baserelease 22 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1921,6 +1921,9 @@ fi # and build. %changelog +* Tue Sep 07 2010 Dave Jones 2.6.35.4-22 +- Disable hung task checker, it only ever causes false positives. (#630777) + * Tue Sep 07 2010 Jarod Wilson 2.6.35.4-21 - Enhance HID layer to fully support TiVo Slide remote and dongle From 215a71b03df53886372ecce4bb2012335845dbfc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 8 Sep 2010 16:23:30 +1000 Subject: [PATCH 041/277] nouveau: more updates --- drm-nouveau-updates.patch | 4561 +++++++++++++++++++++++++++++++------ kernel.spec | 5 +- 2 files changed, 3915 insertions(+), 651 deletions(-) diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 82ded4701..9749a29c8 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,7 +1,7 @@ -From c156fa3c71b6581b34526a9b2b649c3f4d57dd3e Mon Sep 17 00:00:00 2001 +From 71c6844b5918cd5b1f8b61735e52be12fb5f80e5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Jun 2010 15:32:24 +1000 -Subject: [PATCH 1/2] drm-nouveau-updates +Subject: [PATCH] drm-nouveau-updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -842,6 +842,120 @@ Signed-off-by: Ben Skeggs drm/nv50: report BAR access faults +Signed-off-by: Ben Skeggs + +drm/nouveau: rebase per-channel pramin heap offsets to 0 + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: remove nouveau_gpuobj_ref completely, replace with sanity + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: simplify fake gpu objects + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nv50: allow gpuobjs that aren't mapped into aperture + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: rework init ordering so nv50_instmem.c can be less bad + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: tidy ram{ht,fc,ro} a bit + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: add spinlock around ramht modifications + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: fix gpuobj refcount to use atomics + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: protect gpuobj list + global instmem heap with spinlock + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: remove nouveau_gpuobj_late_takedown + +Reviewed-by: Francisco Jerez +Signed-off-by: Ben Skeggs + +drm/nouveau: protect ramht_find() from oopsing if on channel without ramht + +This doesn't actually happen now, but there's a test case for an earlier +kernel where a GPU error is signalled on one of nv50's fake channels, and +the ramht lookup by the IRQ handler triggered an oops. + +This adds a check for RAMHT's existance on a channel before looking up +an object handle. + +Signed-off-by: Ben Skeggs + +drm/nv50: fix SOR count for early chipsets + +Signed-off-by: Ben Skeggs + +drm/nouveau: Break some long lines in the TV-out code. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Don't remove ramht entries from the neighboring channels. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Don't enable AGP FW on nv18. + +FW seems to be broken on nv18, it causes random lockups and breaks +suspend/resume even with the blob. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Add module parameter to override the default AGP rate. + +Signed-off-by: Francisco Jerez + +drm/nouveau: PRAMIN is available from the start on pre-nv50. + +This makes sure that RAMHT is cleared correctly on start up. + +Signed-off-by: Francisco Jerez + +drm/nouveau: Remove implicit argument from nv_wait(). + +Signed-off-by: Francisco Jerez + +drm/nouveau: Simplify tile region handling. + +Instead of emptying the caches to avoid a race with the PFIFO puller, +go straight ahead and try to recover from it when it happens. Also, +kill pfifo->cache_flush and tile->lock, we don't need them anymore. + +Signed-off-by: Francisco Jerez + +drm/nouveau: handle fifo pusher errors better + +The most important part of this change is that we now instruct PFIFO to +drop all pending fetches, rather than attempting to skip a single dword +and hope that things would magically sort themselves out - they usually +don't, and we end up with PFIFO being completely hung. + +This commit also adds somewhat more useful logging when these exceptions +occur. + Signed-off-by: Ben Skeggs --- drivers/gpu/drm/drm_crtc_helper.c | 22 +- @@ -851,15 +965,15 @@ Signed-off-by: Ben Skeggs drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 +- drivers/gpu/drm/nouveau/nouveau_bios.c | 910 ++++++-- drivers/gpu/drm/nouveau/nouveau_bios.h | 6 +- - drivers/gpu/drm/nouveau/nouveau_bo.c | 223 ++- + drivers/gpu/drm/nouveau/nouveau_bo.c | 228 ++- drivers/gpu/drm/nouveau/nouveau_calc.c | 10 +- - drivers/gpu/drm/nouveau/nouveau_channel.c | 6 +- + drivers/gpu/drm/nouveau/nouveau_channel.c | 18 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 417 ++-- drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +- - drivers/gpu/drm/nouveau/nouveau_dma.c | 7 - - drivers/gpu/drm/nouveau/nouveau_dp.c | 128 +- - drivers/gpu/drm/nouveau/nouveau_drv.c | 39 +- - drivers/gpu/drm/nouveau/nouveau_drv.h | 203 +- + drivers/gpu/drm/nouveau/nouveau_dma.c | 21 +- + drivers/gpu/drm/nouveau/nouveau_dp.c | 131 +- + drivers/gpu/drm/nouveau/nouveau_drv.c | 45 +- + drivers/gpu/drm/nouveau/nouveau_drv.h | 309 ++-- drivers/gpu/drm/nouveau/nouveau_encoder.h | 16 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- drivers/gpu/drm/nouveau/nouveau_fence.c | 35 +- @@ -869,52 +983,57 @@ Signed-off-by: Ben Skeggs drivers/gpu/drm/nouveau/nouveau_hw.c | 13 +- drivers/gpu/drm/nouveau/nouveau_i2c.c | 83 +- drivers/gpu/drm/nouveau/nouveau_i2c.h | 11 +- - drivers/gpu/drm/nouveau/nouveau_irq.c | 70 +- - drivers/gpu/drm/nouveau/nouveau_mem.c | 404 ++--- - drivers/gpu/drm/nouveau/nouveau_notifier.c | 30 +- - drivers/gpu/drm/nouveau/nouveau_object.c | 325 +-- - drivers/gpu/drm/nouveau/nouveau_ramht.c | 160 ++ - drivers/gpu/drm/nouveau/nouveau_ramht.h | 31 + - drivers/gpu/drm/nouveau/nouveau_reg.h | 109 +- - drivers/gpu/drm/nouveau/nouveau_sgdma.c | 108 +- - drivers/gpu/drm/nouveau/nouveau_state.c | 340 ++- + drivers/gpu/drm/nouveau/nouveau_irq.c | 129 +- + drivers/gpu/drm/nouveau/nouveau_mem.c | 529 ++--- + drivers/gpu/drm/nouveau/nouveau_notifier.c | 37 +- + drivers/gpu/drm/nouveau/nouveau_object.c | 853 +++----- + drivers/gpu/drm/nouveau/nouveau_ramht.c | 289 +++ + drivers/gpu/drm/nouveau/nouveau_ramht.h | 55 + + drivers/gpu/drm/nouveau/nouveau_reg.h | 118 +- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 117 +- + drivers/gpu/drm/nouveau/nouveau_state.c | 398 ++-- drivers/gpu/drm/nouveau/nv04_crtc.c | 11 +- drivers/gpu/drm/nouveau/nv04_dac.c | 60 +- drivers/gpu/drm/nouveau/nv04_dfp.c | 145 +- drivers/gpu/drm/nouveau/nv04_display.c | 90 +- - drivers/gpu/drm/nouveau/nv04_fifo.c | 28 +- + drivers/gpu/drm/nouveau/nv04_fbcon.c | 9 +- + drivers/gpu/drm/nouveau/nv04_fifo.c | 88 +- drivers/gpu/drm/nouveau/nv04_graph.c | 5 +- - drivers/gpu/drm/nouveau/nv04_instmem.c | 21 +- + drivers/gpu/drm/nouveau/nv04_instmem.c | 167 +- drivers/gpu/drm/nouveau/nv04_mc.c | 4 + drivers/gpu/drm/nouveau/nv04_tv.c | 133 +- - drivers/gpu/drm/nouveau/nv10_fifo.c | 10 - + drivers/gpu/drm/nouveau/nv10_fifo.c | 29 +- drivers/gpu/drm/nouveau/nv10_gpio.c | 92 + drivers/gpu/drm/nouveau/nv10_graph.c | 175 +- drivers/gpu/drm/nouveau/nv17_gpio.c | 92 - - drivers/gpu/drm/nouveau/nv17_tv.c | 82 +- - drivers/gpu/drm/nouveau/nv20_graph.c | 564 +++--- + drivers/gpu/drm/nouveau/nv17_tv.c | 181 +- + drivers/gpu/drm/nouveau/nv17_tv.h | 15 +- + drivers/gpu/drm/nouveau/nv17_tv_modes.c | 48 +- + drivers/gpu/drm/nouveau/nv20_graph.c | 576 +++--- drivers/gpu/drm/nouveau/nv30_fb.c | 95 + - drivers/gpu/drm/nouveau/nv40_fifo.c | 8 - - drivers/gpu/drm/nouveau/nv40_graph.c | 62 +- + drivers/gpu/drm/nouveau/nv40_fifo.c | 28 +- + drivers/gpu/drm/nouveau/nv40_graph.c | 72 +- drivers/gpu/drm/nouveau/nv40_grctx.c | 6 +- drivers/gpu/drm/nouveau/nv40_mc.c | 2 +- drivers/gpu/drm/nouveau/nv50_crtc.c | 67 +- - drivers/gpu/drm/nouveau/nv50_dac.c | 43 +- - drivers/gpu/drm/nouveau/nv50_display.c | 435 +++-- + drivers/gpu/drm/nouveau/nv50_cursor.c | 2 +- + drivers/gpu/drm/nouveau/nv50_dac.c | 47 +- + drivers/gpu/drm/nouveau/nv50_display.c | 496 +++-- drivers/gpu/drm/nouveau/nv50_display.h | 6 +- drivers/gpu/drm/nouveau/nv50_fb.c | 39 + - drivers/gpu/drm/nouveau/nv50_fifo.c | 335 ++-- + drivers/gpu/drm/nouveau/nv50_fbcon.c | 4 +- + drivers/gpu/drm/nouveau/nv50_fifo.c | 396 ++-- drivers/gpu/drm/nouveau/nv50_gpio.c | 35 + - drivers/gpu/drm/nouveau/nv50_graph.c | 104 +- + drivers/gpu/drm/nouveau/nv50_graph.c | 131 +- drivers/gpu/drm/nouveau/nv50_grctx.c | 3305 +++++++++++++++++---------- - drivers/gpu/drm/nouveau/nv50_instmem.c | 81 +- - drivers/gpu/drm/nouveau/nv50_sor.c | 105 +- + drivers/gpu/drm/nouveau/nv50_instmem.c | 473 ++--- + drivers/gpu/drm/nouveau/nv50_sor.c | 109 +- drivers/gpu/drm/nouveau/nvc0_fb.c | 38 + - drivers/gpu/drm/nouveau/nvc0_fifo.c | 95 + + drivers/gpu/drm/nouveau/nvc0_fifo.c | 89 + drivers/gpu/drm/nouveau/nvc0_graph.c | 74 + - drivers/gpu/drm/nouveau/nvc0_instmem.c | 234 ++ + drivers/gpu/drm/nouveau/nvc0_instmem.c | 229 ++ drivers/gpu/drm/nouveau/nvreg.h | 22 - - 70 files changed, 6456 insertions(+), 4215 deletions(-) + 75 files changed, 7469 insertions(+), 5278 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.h @@ -2713,7 +2832,7 @@ index adf4ec2..c1de2f3 100644 struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index 6f3c195..553a01d 100644 +index 6f3c195..22a2038 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -43,17 +43,12 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) @@ -2754,7 +2873,19 @@ index 6f3c195..553a01d 100644 } u16 -@@ -461,18 +454,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, +@@ -395,7 +388,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; +- man->gpu_offset = dev_priv->vm_vram_base; ++ if (dev_priv->card_type == NV_50) ++ man->gpu_offset = 0x40000000; ++ else ++ man->gpu_offset = 0; + break; + case TTM_PL_TT: + switch (dev_priv->gart_info.type) { +@@ -461,18 +457,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, @@ -2781,7 +2912,7 @@ index 6f3c195..553a01d 100644 if (mem->mem_type == TTM_PL_TT) return NvDmaGART; return NvDmaVRAM; -@@ -484,86 +479,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, +@@ -484,86 +482,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, } static int @@ -3008,7 +3139,7 @@ index 6f3c195..553a01d 100644 return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); } -@@ -710,13 +800,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, +@@ -710,13 +803,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) return ret; @@ -3022,7 +3153,7 @@ index 6f3c195..553a01d 100644 /* Fake bo copy. */ if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { BUG_ON(bo->mem.mm_node != NULL); -@@ -725,6 +808,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, +@@ -725,6 +811,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, goto out; } @@ -3084,10 +3215,27 @@ index 88f9bc0..23d9896 100644 static int diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c -index 1fc57ef..9a31023 100644 +index 1fc57ef..53c2a6f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c -@@ -257,9 +257,7 @@ nouveau_channel_free(struct nouveau_channel *chan) +@@ -69,14 +69,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) + chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT; + } + +- ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf); +- if (ret) { +- NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret); +- if (pushbuf != dev_priv->gart_info.sg_ctxdma) +- nouveau_gpuobj_del(dev, &pushbuf); +- return ret; +- } +- ++ nouveau_gpuobj_ref(pushbuf, &chan->pushbuf); ++ nouveau_gpuobj_ref(NULL, &pushbuf); + return 0; + } + +@@ -257,9 +251,7 @@ nouveau_channel_free(struct nouveau_channel *chan) nouveau_debugfs_channel_fini(chan); /* Give outstanding push buffers a chance to complete */ @@ -3097,15 +3245,18 @@ index 1fc57ef..9a31023 100644 if (chan->fence.sequence != chan->fence.sequence_ack) { struct nouveau_fence *fence = NULL; -@@ -311,6 +309,7 @@ nouveau_channel_free(struct nouveau_channel *chan) +@@ -309,8 +301,9 @@ nouveau_channel_free(struct nouveau_channel *chan) + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + /* Release the channel's resources */ - nouveau_gpuobj_ref_del(dev, &chan->pushbuf); +- nouveau_gpuobj_ref_del(dev, &chan->pushbuf); ++ nouveau_gpuobj_ref(NULL, &chan->pushbuf); if (chan->pushbuf_bo) { + nouveau_bo_unmap(chan->pushbuf_bo); nouveau_bo_unpin(chan->pushbuf_bo); nouveau_bo_ref(NULL, &chan->pushbuf_bo); } -@@ -368,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, +@@ -368,8 +361,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -3114,7 +3265,7 @@ index 1fc57ef..9a31023 100644 if (dev_priv->engine.graph.accel_blocked) return -ENODEV; -@@ -418,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, +@@ -418,7 +409,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, struct drm_nouveau_channel_free *cfree = data; struct nouveau_channel *chan; @@ -3762,10 +3913,52 @@ index 4ef38ab..0d2e668 100644 #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c -index 65c441a..2d00699 100644 +index 65c441a..9d27acd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c -@@ -91,13 +91,6 @@ nouveau_dma_init(struct nouveau_channel *chan) +@@ -28,6 +28,7 @@ + #include "drm.h" + #include "nouveau_drv.h" + #include "nouveau_dma.h" ++#include "nouveau_ramht.h" + + void + nouveau_dma_pre_init(struct nouveau_channel *chan) +@@ -58,26 +59,27 @@ nouveau_dma_init(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *m2mf = NULL; +- struct nouveau_gpuobj *nvsw = NULL; ++ struct nouveau_gpuobj *obj = NULL; + int ret, i; + + /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ + ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ? +- 0x0039 : 0x5039, &m2mf); ++ 0x0039 : 0x5039, &obj); + if (ret) + return ret; + +- ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL); ++ ret = nouveau_ramht_insert(chan, NvM2MF, obj); ++ nouveau_gpuobj_ref(NULL, &obj); + if (ret) + return ret; + + /* Create an NV_SW object for various sync purposes */ +- ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw); ++ ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj); + if (ret) + return ret; + +- ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL); ++ ret = nouveau_ramht_insert(chan, NvSw, obj); ++ nouveau_gpuobj_ref(NULL, &obj); + if (ret) + return ret; + +@@ -91,13 +93,6 @@ nouveau_dma_init(struct nouveau_channel *chan) if (ret) return ret; @@ -3780,7 +3973,7 @@ index 65c441a..2d00699 100644 ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c -index deeb21c..8a1b188 100644 +index deeb21c..89ca1f6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -23,8 +23,10 @@ @@ -3852,7 +4045,17 @@ index deeb21c..8a1b188 100644 return eq_done; } -@@ -535,47 +572,64 @@ out: +@@ -487,7 +524,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, + nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); + nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); + nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); +- if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) { ++ if (!nv_wait(dev, NV50_AUXCH_CTRL(index), ++ 0x00010000, 0x00000000)) { + NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", + nv_rd32(dev, NV50_AUXCH_CTRL(index))); + ret = -EBUSY; +@@ -535,47 +573,64 @@ out: return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); } @@ -3953,10 +4156,10 @@ index deeb21c..8a1b188 100644 + .functionality = nouveau_dp_i2c_func +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c -index 2737704..a8d3d17 100644 +index 2737704..946748a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c -@@ -35,10 +35,6 @@ +@@ -35,13 +35,9 @@ #include "drm_pciids.h" @@ -3964,9 +4167,15 @@ index 2737704..a8d3d17 100644 -int nouveau_ctxfw = 0; -module_param_named(ctxfw, nouveau_ctxfw, int, 0400); - - MODULE_PARM_DESC(noagp, "Disable AGP"); - int nouveau_noagp; - module_param_named(noagp, nouveau_noagp, int, 0400); +-MODULE_PARM_DESC(noagp, "Disable AGP"); +-int nouveau_noagp; +-module_param_named(noagp, nouveau_noagp, int, 0400); ++MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); ++int nouveau_agpmode = -1; ++module_param_named(agpmode, nouveau_agpmode, int, 0400); + + MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); + static int nouveau_modeset = -1; /* kms */ @@ -56,7 +52,7 @@ int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); @@ -4065,7 +4274,7 @@ index 2737704..a8d3d17 100644 nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index c697191..2eb622b 100644 +index c697191..228c8cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) @@ -4083,20 +4292,55 @@ index c697191..2eb622b 100644 enum nouveau_flags { NV_NFORCE = 0x10000000, NV_NFORCE2 = 0x20000000 -@@ -146,10 +138,11 @@ enum nouveau_flags { +@@ -141,22 +133,24 @@ enum nouveau_flags { + #define NVOBJ_ENGINE_DISPLAY 2 + #define NVOBJ_ENGINE_INT 0xdeadbeef + +-#define NVOBJ_FLAG_ALLOW_NO_REFS (1 << 0) + #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) - #define NVOBJ_FLAG_FAKE (1 << 3) +-#define NVOBJ_FLAG_FAKE (1 << 3) struct nouveau_gpuobj { + struct drm_device *dev; ++ struct kref refcount; struct list_head list; - struct nouveau_channel *im_channel; +- struct nouveau_channel *im_channel; - struct mem_block *im_pramin; + struct drm_mm_node *im_pramin; struct nouveau_bo *im_backing; - uint32_t im_backing_start; +- uint32_t im_backing_start; uint32_t *im_backing_suspend; -@@ -196,7 +189,7 @@ struct nouveau_channel { + int im_bound; + + uint32_t flags; +- int refcount; ++ ++ u32 size; ++ u32 pinst; ++ u32 cinst; ++ u64 vinst; + + uint32_t engine; + uint32_t class; +@@ -165,16 +159,6 @@ struct nouveau_gpuobj { + void *priv; + }; + +-struct nouveau_gpuobj_ref { +- struct list_head list; +- +- struct nouveau_gpuobj *gpuobj; +- uint32_t instance; +- +- struct nouveau_channel *channel; +- int handle; +-}; +- + struct nouveau_channel { + struct drm_device *dev; + int id; +@@ -196,37 +180,36 @@ struct nouveau_channel { struct list_head pending; uint32_t sequence; uint32_t sequence_ack; @@ -4105,7 +4349,12 @@ index c697191..2eb622b 100644 } fence; /* DMA push buffer */ -@@ -206,7 +199,7 @@ struct nouveau_channel { +- struct nouveau_gpuobj_ref *pushbuf; +- struct nouveau_bo *pushbuf_bo; +- uint32_t pushbuf_base; ++ struct nouveau_gpuobj *pushbuf; ++ struct nouveau_bo *pushbuf_bo; ++ uint32_t pushbuf_base; /* Notifier memory */ struct nouveau_bo *notifier_bo; @@ -4113,17 +4362,37 @@ index c697191..2eb622b 100644 + struct drm_mm notifier_heap; /* PFIFO context */ - struct nouveau_gpuobj_ref *ramfc; -@@ -224,7 +217,7 @@ struct nouveau_channel { +- struct nouveau_gpuobj_ref *ramfc; +- struct nouveau_gpuobj_ref *cache; ++ struct nouveau_gpuobj *ramfc; ++ struct nouveau_gpuobj *cache; + + /* PGRAPH context */ + /* XXX may be merge 2 pointers as private data ??? */ +- struct nouveau_gpuobj_ref *ramin_grctx; ++ struct nouveau_gpuobj *ramin_grctx; + void *pgraph_ctx; + + /* NV50 VM */ +- struct nouveau_gpuobj *vm_pd; +- struct nouveau_gpuobj_ref *vm_gart_pt; +- struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR]; ++ struct nouveau_gpuobj *vm_pd; ++ struct nouveau_gpuobj *vm_gart_pt; ++ struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; /* Objects */ - struct nouveau_gpuobj_ref *ramin; /* Private instmem */ +- struct nouveau_gpuobj_ref *ramin; /* Private instmem */ - struct mem_block *ramin_heap; /* Private PRAMIN heap */ -+ struct drm_mm ramin_heap; /* Private PRAMIN heap */ - struct nouveau_gpuobj_ref *ramht; /* Hash table */ - struct list_head ramht_refs; /* Objects referenced by RAMHT */ +- struct nouveau_gpuobj_ref *ramht; /* Hash table */ +- struct list_head ramht_refs; /* Objects referenced by RAMHT */ ++ struct nouveau_gpuobj *ramin; /* Private instmem */ ++ struct drm_mm ramin_heap; /* Private PRAMIN heap */ ++ struct nouveau_ramht *ramht; /* Hash table */ -@@ -277,8 +270,7 @@ struct nouveau_instmem_engine { + /* GPU object info for stuff used in-kernel (mm_enabled) */ + uint32_t m2mf_ntfy; +@@ -277,8 +260,7 @@ struct nouveau_instmem_engine { void (*clear)(struct drm_device *, struct nouveau_gpuobj *); int (*bind)(struct drm_device *, struct nouveau_gpuobj *); int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); @@ -4133,7 +4402,7 @@ index c697191..2eb622b 100644 }; struct nouveau_mc_engine { -@@ -303,10 +295,11 @@ struct nouveau_fb_engine { +@@ -303,17 +285,17 @@ struct nouveau_fb_engine { }; struct nouveau_fifo_engine { @@ -4141,13 +4410,20 @@ index c697191..2eb622b 100644 - int channels; -+ struct nouveau_gpuobj_ref *playlist[2]; ++ struct nouveau_gpuobj *playlist[2]; + int cur_playlist; + int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); -@@ -339,10 +332,11 @@ struct nouveau_pgraph_object_class { + void (*disable)(struct drm_device *); + void (*enable)(struct drm_device *); + bool (*reassign)(struct drm_device *, bool enable); +- bool (*cache_flush)(struct drm_device *dev); + bool (*cache_pull)(struct drm_device *dev, bool enable); + + int (*channel_id)(struct drm_device *); +@@ -339,10 +321,11 @@ struct nouveau_pgraph_object_class { struct nouveau_pgraph_engine { struct nouveau_pgraph_object_class *grclass; bool accel_blocked; @@ -4156,12 +4432,12 @@ index c697191..2eb622b 100644 int grctx_size; + /* NV2x/NV3x context table (0x400780) */ -+ struct nouveau_gpuobj_ref *ctx_table; ++ struct nouveau_gpuobj *ctx_table; + int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); -@@ -358,6 +352,24 @@ struct nouveau_pgraph_engine { +@@ -358,6 +341,24 @@ struct nouveau_pgraph_engine { uint32_t size, uint32_t pitch); }; @@ -4186,7 +4462,7 @@ index c697191..2eb622b 100644 struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; -@@ -365,6 +377,8 @@ struct nouveau_engine { +@@ -365,6 +366,8 @@ struct nouveau_engine { struct nouveau_fb_engine fb; struct nouveau_pgraph_engine graph; struct nouveau_fifo_engine fifo; @@ -4195,7 +4471,7 @@ index c697191..2eb622b 100644 }; struct nouveau_pll_vals { -@@ -397,7 +411,7 @@ enum nv04_fp_display_regs { +@@ -397,7 +400,7 @@ enum nv04_fp_display_regs { struct nv04_crtc_reg { unsigned char MiscOutReg; /* */ @@ -4204,7 +4480,7 @@ index c697191..2eb622b 100644 uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; -@@ -496,15 +510,11 @@ enum nouveau_card_type { +@@ -496,15 +499,11 @@ enum nouveau_card_type { NV_30 = 0x30, NV_40 = 0x40, NV_50 = 0x50, @@ -4221,7 +4497,23 @@ index c697191..2eb622b 100644 /* the card type, takes NV_* as values */ enum nouveau_card_type card_type; -@@ -528,13 +538,9 @@ struct drm_nouveau_private { +@@ -513,8 +512,14 @@ struct drm_nouveau_private { + int flags; + + void __iomem *mmio; ++ ++ spinlock_t ramin_lock; + void __iomem *ramin; +- uint32_t ramin_size; ++ u32 ramin_size; ++ u32 ramin_base; ++ bool ramin_available; ++ struct drm_mm ramin_heap; ++ struct list_head gpuobj_list; + + struct nouveau_bo *vga_ram; + +@@ -528,13 +533,9 @@ struct drm_nouveau_private { struct ttm_global_reference mem_global_ref; struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_device bdev; @@ -4235,7 +4527,36 @@ index c697191..2eb622b 100644 int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; -@@ -579,6 +585,7 @@ struct drm_nouveau_private { +@@ -545,15 +546,11 @@ struct drm_nouveau_private { + spinlock_t context_switch_lock; + + /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ +- struct nouveau_gpuobj *ramht; ++ struct nouveau_ramht *ramht; ++ struct nouveau_gpuobj *ramfc; ++ struct nouveau_gpuobj *ramro; ++ + uint32_t ramin_rsvd_vram; +- uint32_t ramht_offset; +- uint32_t ramht_size; +- uint32_t ramht_bits; +- uint32_t ramfc_offset; +- uint32_t ramfc_size; +- uint32_t ramro_offset; +- uint32_t ramro_size; + + struct { + enum { +@@ -571,14 +568,12 @@ struct drm_nouveau_private { + } gart_info; + + /* nv10-nv40 tiling regions */ +- struct { +- struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR]; +- spinlock_t lock; +- } tile; ++ struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR]; + /* VRAM/fb configuration */ uint64_t vram_size; uint64_t vram_sys_base; @@ -4243,7 +4564,7 @@ index c697191..2eb622b 100644 uint64_t fb_phys; uint64_t fb_available_size; -@@ -595,11 +602,7 @@ struct drm_nouveau_private { +@@ -595,14 +590,6 @@ struct drm_nouveau_private { struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; @@ -4252,11 +4573,13 @@ index c697191..2eb622b 100644 - /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ - uint32_t ctx_table_size; - struct nouveau_gpuobj_ref *ctx_table; -+ struct drm_mm ramin_heap; +- +- struct list_head gpuobj_list; +- + struct nvbios vbios; - struct list_head gpuobj_list; - -@@ -618,6 +621,11 @@ struct drm_nouveau_private { + struct nv04_mode_state mode_reg; +@@ -618,6 +605,11 @@ struct drm_nouveau_private { struct backlight_device *backlight; struct nouveau_channel *evo; @@ -4268,7 +4591,7 @@ index c697191..2eb622b 100644 struct { struct dentry *channel_root; -@@ -652,14 +660,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) +@@ -652,14 +644,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) return 0; } @@ -4283,7 +4606,16 @@ index c697191..2eb622b 100644 #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (!nouveau_channel_owner(dev, (cl), (id))) { \ -@@ -682,7 +682,6 @@ extern int nouveau_tv_disable; +@@ -671,7 +655,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) + } while (0) + + /* nouveau_drv.c */ +-extern int nouveau_noagp; ++extern int nouveau_agpmode; + extern int nouveau_duallink; + extern int nouveau_uscript_lvds; + extern int nouveau_uscript_tmds; +@@ -682,7 +666,6 @@ extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; @@ -4291,7 +4623,7 @@ index c697191..2eb622b 100644 extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; -@@ -707,17 +706,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); +@@ -707,17 +690,12 @@ extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ @@ -4302,15 +4634,57 @@ index c697191..2eb622b 100644 - struct drm_file *, int tail); -extern void nouveau_mem_takedown(struct mem_block **heap); -extern void nouveau_mem_free_block(struct mem_block *); - extern int nouveau_mem_detect(struct drm_device *dev); +-extern int nouveau_mem_detect(struct drm_device *dev); -extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); - extern int nouveau_mem_init(struct drm_device *); +-extern int nouveau_mem_init(struct drm_device *); ++extern int nouveau_mem_vram_init(struct drm_device *); ++extern void nouveau_mem_vram_fini(struct drm_device *); ++extern int nouveau_mem_gart_init(struct drm_device *); ++extern void nouveau_mem_gart_fini(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); +extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, -@@ -857,11 +849,13 @@ void nouveau_register_dsm_handler(void); +@@ -759,7 +737,6 @@ extern void nouveau_channel_free(struct nouveau_channel *); + extern int nouveau_gpuobj_early_init(struct drm_device *); + extern int nouveau_gpuobj_init(struct drm_device *); + extern void nouveau_gpuobj_takedown(struct drm_device *); +-extern void nouveau_gpuobj_late_takedown(struct drm_device *); + extern int nouveau_gpuobj_suspend(struct drm_device *dev); + extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev); + extern void nouveau_gpuobj_resume(struct drm_device *dev); +@@ -769,24 +746,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); + extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *, + uint32_t size, int align, uint32_t flags, + struct nouveau_gpuobj **); +-extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **); +-extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *, +- uint32_t handle, struct nouveau_gpuobj *, +- struct nouveau_gpuobj_ref **); +-extern int nouveau_gpuobj_ref_del(struct drm_device *, +- struct nouveau_gpuobj_ref **); +-extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle, +- struct nouveau_gpuobj_ref **ref_ret); +-extern int nouveau_gpuobj_new_ref(struct drm_device *, +- struct nouveau_channel *alloc_chan, +- struct nouveau_channel *ref_chan, +- uint32_t handle, uint32_t size, int align, +- uint32_t flags, struct nouveau_gpuobj_ref **); +-extern int nouveau_gpuobj_new_fake(struct drm_device *, +- uint32_t p_offset, uint32_t b_offset, +- uint32_t size, uint32_t flags, +- struct nouveau_gpuobj **, +- struct nouveau_gpuobj_ref**); ++extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *, ++ struct nouveau_gpuobj **); ++extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst, ++ u32 size, u32 flags, ++ struct nouveau_gpuobj **); + extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, + uint64_t offset, uint64_t size, int access, + int target, struct nouveau_gpuobj **); +@@ -857,11 +821,13 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); @@ -4324,7 +4698,7 @@ index c697191..2eb622b 100644 #endif /* nouveau_backlight.c */ -@@ -924,15 +918,23 @@ extern void nv10_fb_takedown(struct drm_device *); +@@ -924,22 +890,29 @@ extern void nv10_fb_takedown(struct drm_device *); extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); @@ -4349,7 +4723,14 @@ index c697191..2eb622b 100644 /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); -@@ -971,6 +973,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); + extern void nv04_fifo_disable(struct drm_device *); + extern void nv04_fifo_enable(struct drm_device *); + extern bool nv04_fifo_reassign(struct drm_device *, bool); +-extern bool nv04_fifo_cache_flush(struct drm_device *); + extern bool nv04_fifo_cache_pull(struct drm_device *, bool); + extern int nv04_fifo_channel_id(struct drm_device *); + extern int nv04_fifo_create_context(struct nouveau_channel *); +@@ -971,6 +944,19 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); @@ -4359,7 +4740,6 @@ index c697191..2eb622b 100644 +extern void nvc0_fifo_disable(struct drm_device *); +extern void nvc0_fifo_enable(struct drm_device *); +extern bool nvc0_fifo_reassign(struct drm_device *, bool); -+extern bool nvc0_fifo_cache_flush(struct drm_device *); +extern bool nvc0_fifo_cache_pull(struct drm_device *, bool); +extern int nvc0_fifo_channel_id(struct drm_device *); +extern int nvc0_fifo_create_context(struct nouveau_channel *); @@ -4370,7 +4750,7 @@ index c697191..2eb622b 100644 /* nv04_graph.c */ extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern int nv04_graph_init(struct drm_device *); -@@ -1035,11 +1051,15 @@ extern int nv50_graph_unload_context(struct drm_device *); +@@ -1035,11 +1021,15 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); @@ -4391,7 +4771,7 @@ index c697191..2eb622b 100644 /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); -@@ -1051,8 +1071,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1051,8 +1041,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -4401,7 +4781,7 @@ index c697191..2eb622b 100644 /* nv50_instmem.c */ extern int nv50_instmem_init(struct drm_device *); -@@ -1064,8 +1083,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1064,8 +1053,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -4425,7 +4805,7 @@ index c697191..2eb622b 100644 /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); -@@ -1088,13 +1120,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, +@@ -1088,13 +1090,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nv04_dac.c */ @@ -4442,7 +4822,7 @@ index c697191..2eb622b 100644 extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, int head, bool dl); -@@ -1103,15 +1136,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); +@@ -1103,15 +1106,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); /* nv04_tv.c */ extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); @@ -4463,7 +4843,7 @@ index c697191..2eb622b 100644 /* nv04_crtc.c */ extern int nv04_crtc_create(struct drm_device *, int index); -@@ -1147,7 +1182,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); +@@ -1147,7 +1152,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); extern int nouveau_fence_flush(void *obj, void *arg); extern void nouveau_fence_unref(void **obj); extern void *nouveau_fence_ref(void *obj); @@ -4471,7 +4851,7 @@ index c697191..2eb622b 100644 /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, -@@ -1167,13 +1201,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, +@@ -1167,13 +1171,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); @@ -4490,7 +4870,7 @@ index c697191..2eb622b 100644 /* nv50_calc. */ int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, -@@ -1220,6 +1256,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) +@@ -1220,6 +1226,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) iowrite32_native(val, dev_priv->mmio + reg); } @@ -4504,7 +4884,16 @@ index c697191..2eb622b 100644 static inline u8 nv_rd08(struct drm_device *dev, unsigned reg) { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -1249,17 +1292,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val) +@@ -1232,7 +1245,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) + iowrite8(val, dev_priv->mmio + reg); + } + +-#define nv_wait(reg, mask, val) \ ++#define nv_wait(dev, reg, mask, val) \ + nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val)) + + /* PRAMIN access */ +@@ -1249,17 +1262,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val) } /* object access */ @@ -4524,7 +4913,7 @@ index c697191..2eb622b 100644 /* * Logging -@@ -1346,6 +1380,15 @@ nv_two_reg_pll(struct drm_device *dev) +@@ -1346,6 +1350,15 @@ nv_two_reg_pll(struct drm_device *dev) return false; } @@ -5157,10 +5546,18 @@ index c8eaf7a..f71cb32 100644 #endif /* __NOUVEAU_I2C_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c -index 53360f1..b8658a0 100644 +index 53360f1..6fd51a5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c -@@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev) +@@ -35,6 +35,7 @@ + #include "nouveau_drm.h" + #include "nouveau_drv.h" + #include "nouveau_reg.h" ++#include "nouveau_ramht.h" + #include + + /* needed for hotplug irq */ +@@ -49,7 +50,7 @@ nouveau_irq_preinstall(struct drm_device *dev) /* Master disable */ nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); @@ -5169,7 +5566,82 @@ index 53360f1..b8658a0 100644 INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); INIT_LIST_HEAD(&dev_priv->vbl_waiting); -@@ -226,6 +226,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev) +@@ -106,15 +107,16 @@ nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data) + const int mthd = addr & 0x1ffc; + + if (mthd == 0x0000) { +- struct nouveau_gpuobj_ref *ref = NULL; ++ struct nouveau_gpuobj *gpuobj; + +- if (nouveau_gpuobj_ref_find(chan, data, &ref)) ++ gpuobj = nouveau_ramht_find(chan, data); ++ if (!gpuobj) + return false; + +- if (ref->gpuobj->engine != NVOBJ_ENGINE_SW) ++ if (gpuobj->engine != NVOBJ_ENGINE_SW) + return false; + +- chan->sw_subchannel[subc] = ref->gpuobj->class; ++ chan->sw_subchannel[subc] = gpuobj->class; + nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev, + NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4)); + return true; +@@ -200,16 +202,45 @@ nouveau_fifo_irq_handler(struct drm_device *dev) + } + + if (status & NV_PFIFO_INTR_DMA_PUSHER) { +- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid); ++ u32 get = nv_rd32(dev, 0x003244); ++ u32 put = nv_rd32(dev, 0x003240); ++ u32 push = nv_rd32(dev, 0x003220); ++ u32 state = nv_rd32(dev, 0x003228); ++ ++ if (dev_priv->card_type == NV_50) { ++ u32 ho_get = nv_rd32(dev, 0x003328); ++ u32 ho_put = nv_rd32(dev, 0x003320); ++ u32 ib_get = nv_rd32(dev, 0x003334); ++ u32 ib_put = nv_rd32(dev, 0x003330); ++ ++ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " ++ "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " ++ "State 0x%08x Push 0x%08x\n", ++ chid, ho_get, get, ho_put, put, ib_get, ib_put, ++ state, push); ++ ++ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ ++ nv_wr32(dev, 0x003364, 0x00000000); ++ if (get != put || ho_get != ho_put) { ++ nv_wr32(dev, 0x003244, put); ++ nv_wr32(dev, 0x003328, ho_put); ++ } else ++ if (ib_get != ib_put) { ++ nv_wr32(dev, 0x003334, ib_put); ++ } ++ } else { ++ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " ++ "Put 0x%08x State 0x%08x Push 0x%08x\n", ++ chid, get, put, state, push); + +- status &= ~NV_PFIFO_INTR_DMA_PUSHER; +- nv_wr32(dev, NV03_PFIFO_INTR_0, +- NV_PFIFO_INTR_DMA_PUSHER); ++ if (get != put) ++ nv_wr32(dev, 0x003244, put); ++ } + +- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000); +- if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get) +- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, +- get + 4); ++ nv_wr32(dev, 0x003228, 0x00000000); ++ nv_wr32(dev, 0x003220, 0x00000001); ++ nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); ++ status &= ~NV_PFIFO_INTR_DMA_PUSHER; + } + + if (status & NV_PFIFO_INTR_SEMAPHORE) { +@@ -226,6 +257,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev) nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); } @@ -5184,7 +5656,25 @@ index 53360f1..b8658a0 100644 if (status) { NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", status, chid); -@@ -586,11 +594,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) +@@ -357,7 +396,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev) + if (!chan || !chan->ramin_grctx) + continue; + +- if (inst == chan->ramin_grctx->instance) ++ if (inst == chan->ramin_grctx->pinst) + break; + } + } else { +@@ -369,7 +408,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev) + if (!chan || !chan->ramin) + continue; + +- if (inst == chan->ramin->instance) ++ if (inst == chan->ramin->vinst) + break; + } + } +@@ -586,11 +625,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) } if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { @@ -5198,7 +5688,7 @@ index 53360f1..b8658a0 100644 } if (status) { -@@ -605,40 +613,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) +@@ -605,40 +644,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); } @@ -5239,7 +5729,7 @@ index 53360f1..b8658a0 100644 static struct nouveau_enum_names nv50_mp_exec_error_names[] = { { 3, "STACK_UNDERFLOW" }, -@@ -711,7 +685,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, +@@ -711,7 +716,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, tps++; switch (type) { case 6: /* texture error... unknown for now */ @@ -5248,7 +5738,7 @@ index 53360f1..b8658a0 100644 if (display) { NV_ERROR(dev, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) -@@ -734,7 +708,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, +@@ -734,7 +739,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); @@ -5257,7 +5747,7 @@ index 53360f1..b8658a0 100644 /* 2d engine destination */ if (ustatus & 0x00000010) { if (display) { -@@ -817,7 +791,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -817,7 +822,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) /* Known to be triggered by screwed up NOTIFY and COND... */ if (ustatus & 0x00000001) { @@ -5266,7 +5756,7 @@ index 53360f1..b8658a0 100644 nv_wr32(dev, 0x400500, 0); if (nv_rd32(dev, 0x400808) & 0x80000000) { if (display) { -@@ -842,7 +816,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -842,7 +847,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) ustatus &= ~0x00000001; } if (ustatus & 0x00000002) { @@ -5275,7 +5765,7 @@ index 53360f1..b8658a0 100644 nv_wr32(dev, 0x400500, 0); if (nv_rd32(dev, 0x40084c) & 0x80000000) { if (display) { -@@ -884,15 +858,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -884,15 +889,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev) NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n"); } if (ustatus & 0x00000001) { @@ -5294,7 +5784,7 @@ index 53360f1..b8658a0 100644 ustatus &= ~0x00000004; } NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n", -@@ -917,7 +891,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -917,7 +922,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n"); } if (ustatus & 0x00000001) { @@ -5303,7 +5793,7 @@ index 53360f1..b8658a0 100644 NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n", nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), -@@ -939,7 +913,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -939,7 +944,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n"); } if (ustatus & 0x00000001) { @@ -5312,7 +5802,7 @@ index 53360f1..b8658a0 100644 NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n", nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), -@@ -964,7 +938,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -964,7 +969,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n"); } if (ustatus & 0x00000001) { @@ -5321,7 +5811,7 @@ index 53360f1..b8658a0 100644 NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n", nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), -@@ -986,7 +960,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) +@@ -986,7 +991,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) * remaining, so try to handle it anyway. Perhaps related to that * unknown DMA slot on tesla? */ if (status & 0x20) { @@ -5331,7 +5821,7 @@ index 53360f1..b8658a0 100644 if (display) NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c -index c1fd42b..ee799c2 100644 +index c1fd42b..4f0ae39 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -35,162 +35,6 @@ @@ -5497,7 +5987,74 @@ index c1fd42b..ee799c2 100644 /* * NV10-NV40 tiling helpers */ -@@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, +@@ -203,18 +47,14 @@ nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; ++ struct nouveau_tile_reg *tile = &dev_priv->tile[i]; + + tile->addr = addr; + tile->size = size; + tile->used = !!pitch; + nouveau_fence_unref((void **)&tile->fence); + +- if (!pfifo->cache_flush(dev)) +- return; +- + pfifo->reassign(dev, false); +- pfifo->cache_flush(dev); + pfifo->cache_pull(dev, false); + + nouveau_wait_for_idle(dev); +@@ -232,34 +72,36 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; +- struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL; +- int i; ++ struct nouveau_tile_reg *found = NULL; ++ unsigned long i, flags; + +- spin_lock(&dev_priv->tile.lock); ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + + for (i = 0; i < pfb->num_tiles; i++) { +- if (tile[i].used) ++ struct nouveau_tile_reg *tile = &dev_priv->tile[i]; ++ ++ if (tile->used) + /* Tile region in use. */ + continue; + +- if (tile[i].fence && +- !nouveau_fence_signalled(tile[i].fence, NULL)) ++ if (tile->fence && ++ !nouveau_fence_signalled(tile->fence, NULL)) + /* Pending tile region. */ + continue; + +- if (max(tile[i].addr, addr) < +- min(tile[i].addr + tile[i].size, addr + size)) ++ if (max(tile->addr, addr) < ++ min(tile->addr + tile->size, addr + size)) + /* Kill an intersecting tile region. */ + nv10_mem_set_region_tiling(dev, i, 0, 0, 0); + + if (pitch && !found) { + /* Free tile region. */ + nv10_mem_set_region_tiling(dev, i, addr, size, pitch); +- found = &tile[i]; ++ found = tile; + } + } + +- spin_unlock(&dev_priv->tile.lock); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + return found; + } +@@ -299,7 +141,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, phys |= 0x30; } @@ -5505,7 +6062,7 @@ index c1fd42b..ee799c2 100644 while (size) { unsigned offset_h = upper_32_bits(phys); unsigned offset_l = lower_32_bits(phys); -@@ -326,41 +169,18 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, +@@ -326,41 +167,18 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, virt += (end - pte); while (pte < end) { @@ -5555,7 +6112,7 @@ index c1fd42b..ee799c2 100644 return 0; } -@@ -374,7 +194,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) +@@ -374,7 +192,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) virt -= dev_priv->vm_vram_base; pages = (size >> 16) << 1; @@ -5563,7 +6120,7 @@ index c1fd42b..ee799c2 100644 while (pages) { pgt = dev_priv->vm_vram_pt[virt >> 29]; pte = (virt & 0x1ffe0000ULL) >> 15; -@@ -385,60 +204,24 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) +@@ -385,60 +202,24 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) pages -= (end - pte); virt += (end - pte) << 15; @@ -5631,31 +6188,43 @@ index c1fd42b..ee799c2 100644 - -void nouveau_mem_close(struct drm_device *dev) +void -+nouveau_mem_close(struct drm_device *dev) ++nouveau_mem_vram_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -449,8 +232,7 @@ void nouveau_mem_close(struct drm_device *dev) +@@ -449,8 +230,20 @@ void nouveau_mem_close(struct drm_device *dev) nouveau_ttm_global_release(dev_priv); - if (drm_core_has_AGP(dev) && dev->agp && - drm_core_check_feature(dev, DRIVER_MODESET)) { ++ if (dev_priv->fb_mtrr >= 0) { ++ drm_mtrr_del(dev_priv->fb_mtrr, ++ pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); ++ dev_priv->fb_mtrr = -1; ++ } ++} ++ ++void ++nouveau_mem_gart_fini(struct drm_device *dev) ++{ ++ nouveau_sgdma_takedown(dev); ++ + if (drm_core_has_AGP(dev) && dev->agp) { struct drm_agp_mem *entry, *tempe; /* Remove AGP resources, but leave dev->agp -@@ -470,29 +252,29 @@ void nouveau_mem_close(struct drm_device *dev) +@@ -469,30 +262,24 @@ void nouveau_mem_close(struct drm_device *dev) + dev->agp->acquired = 0; dev->agp->enabled = 0; } - +- - if (dev_priv->fb_mtrr) { -+ if (dev_priv->fb_mtrr >= 0) { - drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1), - drm_get_resource_len(dev, 1), DRM_MTRR_WC); +- drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1), +- drm_get_resource_len(dev, 1), DRM_MTRR_WC); - dev_priv->fb_mtrr = 0; -+ dev_priv->fb_mtrr = -1; - } +- } } static uint32_t @@ -5683,11 +6252,12 @@ index c1fd42b..ee799c2 100644 return 4 * 1024 * 1024; } -@@ -525,7 +307,61 @@ nouveau_mem_detect_nforce(struct drm_device *dev) +@@ -525,8 +312,62 @@ nouveau_mem_detect_nforce(struct drm_device *dev) return 0; } -/* returns the amount of FB ram in bytes */ +-int +static void +nv50_vram_preinit(struct drm_device *dev) +{ @@ -5743,10 +6313,11 @@ index c1fd42b..ee799c2 100644 + dev_priv->vram_rblock_size = 1; +} + - int ++static int nouveau_mem_detect(struct drm_device *dev) { -@@ -536,12 +372,31 @@ nouveau_mem_detect(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -536,12 +377,31 @@ nouveau_mem_detect(struct drm_device *dev) } else if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { dev_priv->vram_size = nouveau_mem_detect_nforce(dev); @@ -5782,16 +6353,41 @@ index c1fd42b..ee799c2 100644 } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -@@ -555,18 +410,37 @@ nouveau_mem_detect(struct drm_device *dev) - return -ENOMEM; +@@ -556,17 +416,63 @@ nouveau_mem_detect(struct drm_device *dev) } --#if __OS_HAS_AGP + #if __OS_HAS_AGP -static void nouveau_mem_reset_agp(struct drm_device *dev) -+int -+nouveau_mem_reset_agp(struct drm_device *dev) ++static unsigned long ++get_agp_mode(struct drm_device *dev, unsigned long mode) { - uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ /* ++ * FW seems to be broken on nv18, it makes the card lock up ++ * randomly. ++ */ ++ if (dev_priv->chipset == 0x18) ++ mode &= ~PCI_AGP_COMMAND_FW; ++ ++ /* ++ * AGP mode set in the command line. ++ */ ++ if (nouveau_agpmode > 0) { ++ bool agpv3 = mode & 0x8; ++ int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; ++ ++ mode = (mode & ~0x7) | (rate & 0x7); ++ } ++ ++ return mode; ++} ++#endif ++ ++int ++nouveau_mem_reset_agp(struct drm_device *dev) ++{ +#if __OS_HAS_AGP + uint32_t saved_pci_nv_1, pmc_enable; + int ret; @@ -5808,7 +6404,7 @@ index c1fd42b..ee799c2 100644 + if (ret) + return ret; + -+ mode.mode = info.mode & ~PCI_AGP_COMMAND_FW; ++ mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW; + ret = drm_agp_enable(dev, mode); + if (ret) + return ret; @@ -5826,7 +6422,7 @@ index c1fd42b..ee799c2 100644 /* power cycle pgraph, if enabled */ pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); -@@ -578,11 +452,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) +@@ -578,11 +484,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) } /* and restore (gives effect of resetting AGP) */ @@ -5841,7 +6437,7 @@ index c1fd42b..ee799c2 100644 int nouveau_mem_init_agp(struct drm_device *dev) { -@@ -592,11 +467,6 @@ nouveau_mem_init_agp(struct drm_device *dev) +@@ -592,11 +499,6 @@ nouveau_mem_init_agp(struct drm_device *dev) struct drm_agp_mode mode; int ret; @@ -5853,7 +6449,7 @@ index c1fd42b..ee799c2 100644 if (!dev->agp->acquired) { ret = drm_agp_acquire(dev); if (ret) { -@@ -605,6 +475,8 @@ nouveau_mem_init_agp(struct drm_device *dev) +@@ -605,6 +507,8 @@ nouveau_mem_init_agp(struct drm_device *dev) } } @@ -5862,29 +6458,130 @@ index c1fd42b..ee799c2 100644 ret = drm_agp_info(dev, &info); if (ret) { NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); -@@ -659,8 +531,6 @@ nouveau_mem_init(struct drm_device *dev) +@@ -612,7 +516,7 @@ nouveau_mem_init_agp(struct drm_device *dev) + } + + /* see agp.h for the AGPSTAT_* modes available */ +- mode.mode = info.mode; ++ mode.mode = get_agp_mode(dev, info.mode); + ret = drm_agp_enable(dev, mode); + if (ret) { + NV_ERROR(dev, "Unable to enable AGP: %d\n", ret); +@@ -627,24 +531,27 @@ nouveau_mem_init_agp(struct drm_device *dev) + } + + int +-nouveau_mem_init(struct drm_device *dev) ++nouveau_mem_vram_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; +- int ret, dma_bits = 32; +- +- dev_priv->fb_phys = drm_get_resource_start(dev, 1); +- dev_priv->gart_info.type = NOUVEAU_GART_NONE; ++ int ret, dma_bits; + + if (dev_priv->card_type >= NV_50 && + pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) + dma_bits = 40; ++ else ++ dma_bits = 32; + + ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); +- if (ret) { +- NV_ERROR(dev, "Error setting DMA mask: %d\n", ret); ++ if (ret) + return ret; +- } ++ ++ ret = nouveau_mem_detect(dev); ++ if (ret) ++ return ret; ++ ++ dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); + + ret = nouveau_ttm_global_init(dev_priv); + if (ret) +@@ -659,17 +566,22 @@ nouveau_mem_init(struct drm_device *dev) return ret; } - INIT_LIST_HEAD(&dev_priv->ttm.bo_list); - spin_lock_init(&dev_priv->ttm.bo_list_lock); - spin_lock_init(&dev_priv->tile.lock); - +- spin_lock_init(&dev_priv->tile.lock); +- dev_priv->fb_available_size = dev_priv->vram_size; -@@ -692,7 +562,7 @@ nouveau_mem_init(struct drm_device *dev) + dev_priv->fb_mappable_pages = dev_priv->fb_available_size; + if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1)) + dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1); + dev_priv->fb_mappable_pages >>= PAGE_SHIFT; - /* GART */ +- /* remove reserved space at end of vram from available amount */ ++ /* reserve space at end of VRAM for PRAMIN */ ++ if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || ++ dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) ++ dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); ++ else ++ if (dev_priv->card_type >= NV_40) ++ dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); ++ else ++ dev_priv->ramin_rsvd_vram = (512 * 1024); ++ + dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; + dev_priv->fb_aper_free = dev_priv->fb_available_size; + +@@ -690,9 +602,23 @@ nouveau_mem_init(struct drm_device *dev) + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + +- /* GART */ ++ dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1), ++ DRM_MTRR_WC); ++ return 0; ++} ++ ++int ++nouveau_mem_gart_init(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; ++ int ret; ++ ++ dev_priv->gart_info.type = NOUVEAU_GART_NONE; ++ #if !defined(__powerpc__) && !defined(__ia64__) - if (drm_device_is_agp(dev) && dev->agp) { -+ if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { ++ if (drm_device_is_agp(dev) && dev->agp && nouveau_agpmode) { ret = nouveau_mem_init_agp(dev); if (ret) NV_ERROR(dev, "Error initialising AGP: %d\n", ret); +@@ -718,11 +644,6 @@ nouveau_mem_init(struct drm_device *dev) + return ret; + } + +- dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1), +- drm_get_resource_len(dev, 1), +- DRM_MTRR_WC); +- + return 0; + } + +- diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c -index 9537f3e..3ec181f 100644 +index 9537f3e..22b8618 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c -@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) +@@ -28,6 +28,7 @@ + #include "drmP.h" + #include "drm.h" + #include "nouveau_drv.h" ++#include "nouveau_ramht.h" + + int + nouveau_notifier_init_channel(struct nouveau_channel *chan) +@@ -55,7 +56,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) if (ret) goto out_err; @@ -5893,7 +6590,7 @@ index 9537f3e..3ec181f 100644 if (ret) goto out_err; -@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan) +@@ -80,7 +81,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan) nouveau_bo_unpin(chan->notifier_bo); mutex_unlock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(chan->notifier_bo->gem); @@ -5902,7 +6599,7 @@ index 9537f3e..3ec181f 100644 } static void -@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev, +@@ -90,7 +91,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev, NV_DEBUG(dev, "\n"); if (gpuobj->priv) @@ -5911,7 +6608,7 @@ index 9537f3e..3ec181f 100644 } int -@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, +@@ -100,18 +101,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *nobj = NULL; @@ -5934,7 +6631,7 @@ index 9537f3e..3ec181f 100644 if (!mem) { NV_ERROR(dev, "Channel %d notifier block full\n", chan->id); return -ENOMEM; -@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, +@@ -144,18 +140,18 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, mem->size, NV_DMA_ACCESS_RW, target, &nobj); if (ret) { @@ -5948,15 +6645,19 @@ index 9537f3e..3ec181f 100644 + nobj->dtor = nouveau_notifier_gpuobj_dtor; + nobj->priv = mem; - ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL); +- ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL); ++ ret = nouveau_ramht_insert(chan, handle, nobj); ++ nouveau_gpuobj_ref(NULL, &nobj); if (ret) { - nouveau_gpuobj_del(dev, &nobj); +- nouveau_gpuobj_del(dev, &nobj); - nouveau_mem_free_block(mem); +- NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret); + drm_mm_put_block(mem); - NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret); ++ NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret); return ret; } -@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset) + +@@ -170,7 +166,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset) return -EINVAL; if (poffset) { @@ -5965,7 +6666,7 @@ index 9537f3e..3ec181f 100644 if (*poffset >= mem->size) return false; -@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, +@@ -189,7 +185,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -5974,7 +6675,7 @@ index 9537f3e..3ec181f 100644 ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c -index e7c100b..6aedc3b 100644 +index e7c100b..115904d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -34,6 +34,7 @@ @@ -6132,21 +6833,29 @@ index e7c100b..6aedc3b 100644 struct nouveau_engine *engine = &dev_priv->engine; struct nouveau_gpuobj *gpuobj; - struct mem_block *pramin = NULL; -+ struct drm_mm *pramin = NULL; ++ struct drm_mm_node *ramin = NULL; int ret; NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", -@@ -222,6 +88,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -222,82 +88,102 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (!gpuobj) return -ENOMEM; NV_DEBUG(dev, "gpuobj %p\n", gpuobj); + gpuobj->dev = dev; gpuobj->flags = flags; - gpuobj->im_channel = chan; +- gpuobj->im_channel = chan; ++ kref_init(&gpuobj->refcount); ++ gpuobj->size = size; -@@ -233,25 +100,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, - * available. - */ ++ spin_lock(&dev_priv->ramin_lock); + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); ++ spin_unlock(&dev_priv->ramin_lock); + +- /* Choose between global instmem heap, and per-channel private +- * instmem heap. On ramin_heap) { - NV_DEBUG(dev, "private heap\n"); @@ -6155,14 +6864,20 @@ index e7c100b..6aedc3b 100644 - if (dev_priv->card_type < NV_50) { - NV_DEBUG(dev, "global heap fallback\n"); - pramin = dev_priv->ramin_heap; -- } + NV_DEBUG(dev, "channel heap\n"); -+ pramin = &chan->ramin_heap; ++ ++ ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0); ++ if (ramin) ++ ramin = drm_mm_get_block(ramin, size, align); ++ ++ if (!ramin) { ++ nouveau_gpuobj_ref(NULL, &gpuobj); ++ return -ENOMEM; + } } else { NV_DEBUG(dev, "global heap\n"); - pramin = dev_priv->ramin_heap; - } -+ pramin = &dev_priv->ramin_heap; - if (!pramin) { - NV_ERROR(dev, "No PRAMIN heap!\n"); @@ -6170,88 +6885,472 @@ index e7c100b..6aedc3b 100644 - } - - if (!chan) { ++ /* allocate backing pages, sets vinst */ ret = engine->instmem.populate(dev, gpuobj, &size); if (ret) { - nouveau_gpuobj_del(dev, &gpuobj); -@@ -260,9 +114,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, - } +- nouveau_gpuobj_del(dev, &gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + return ret; + } +- } - /* Allocate a chunk of the PRAMIN aperture */ +- /* Allocate a chunk of the PRAMIN aperture */ - gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, - drm_order(align), - (struct drm_file *)-2, 0); -+ gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0); -+ if (gpuobj->im_pramin) -+ gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align); +- if (!gpuobj->im_pramin) { +- nouveau_gpuobj_del(dev, &gpuobj); +- return -ENOMEM; ++ /* try and get aperture space */ ++ do { ++ if (drm_mm_pre_get(&dev_priv->ramin_heap)) ++ return -ENOMEM; + - if (!gpuobj->im_pramin) { - nouveau_gpuobj_del(dev, &gpuobj); - return -ENOMEM; -@@ -279,10 +134,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, - if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { - int i; ++ spin_lock(&dev_priv->ramin_lock); ++ ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, ++ align, 0); ++ if (ramin == NULL) { ++ spin_unlock(&dev_priv->ramin_lock); ++ nouveau_gpuobj_ref(NULL, &gpuobj); ++ return ret; ++ } ++ ++ ramin = drm_mm_get_block_atomic(ramin, size, align); ++ spin_unlock(&dev_priv->ramin_lock); ++ } while (ramin == NULL); ++ ++ /* on nv50 it's ok to fail, we have a fallback path */ ++ if (!ramin && dev_priv->card_type < NV_50) { ++ nouveau_gpuobj_ref(NULL, &gpuobj); ++ return -ENOMEM; ++ } + } + +- if (!chan) { ++ /* if we got a chunk of the aperture, map pages into it */ ++ gpuobj->im_pramin = ramin; ++ if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) { + ret = engine->instmem.bind(dev, gpuobj); + if (ret) { +- nouveau_gpuobj_del(dev, &gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + return ret; + } + } + +- if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { +- int i; ++ /* calculate the various different addresses for the object */ ++ if (chan) { ++ gpuobj->pinst = chan->ramin->pinst; ++ if (gpuobj->pinst != ~0) ++ gpuobj->pinst += gpuobj->im_pramin->start; - engine->instmem.prepare_access(dev, true); - for (i = 0; i < gpuobj->im_pramin->size; i += 4) +- for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); -+ nv_wo32(gpuobj, i, 0); -+ engine->instmem.flush(dev); ++ if (dev_priv->card_type < NV_50) { ++ gpuobj->cinst = gpuobj->pinst; ++ } else { ++ gpuobj->cinst = gpuobj->im_pramin->start; ++ gpuobj->vinst = gpuobj->im_pramin->start + ++ chan->ramin->vinst; ++ } ++ } else { ++ if (gpuobj->im_pramin) ++ gpuobj->pinst = gpuobj->im_pramin->start; ++ else ++ gpuobj->pinst = ~0; ++ gpuobj->cinst = 0xdeadbeef; } - *gpuobj_ret = gpuobj; -@@ -370,10 +224,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) - } +- *gpuobj_ret = gpuobj; +- return 0; +-} +- +-int +-nouveau_gpuobj_early_init(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; ++ if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { ++ int i; + +- NV_DEBUG(dev, "\n"); ++ for (i = 0; i < gpuobj->size; i += 4) ++ nv_wo32(gpuobj, i, 0); ++ engine->instmem.flush(dev); ++ } + +- INIT_LIST_HEAD(&dev_priv->gpuobj_list); + ++ *gpuobj_ret = gpuobj; + return 0; + } + +@@ -305,18 +191,12 @@ int + nouveau_gpuobj_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- int ret; + + NV_DEBUG(dev, "\n"); + +- if (dev_priv->card_type < NV_50) { +- ret = nouveau_gpuobj_new_fake(dev, +- dev_priv->ramht_offset, ~0, dev_priv->ramht_size, +- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS, +- &dev_priv->ramht, NULL); +- if (ret) +- return ret; +- } ++ INIT_LIST_HEAD(&dev_priv->gpuobj_list); ++ spin_lock_init(&dev_priv->ramin_lock); ++ dev_priv->ramin_base = ~0; + + return 0; + } +@@ -328,299 +208,89 @@ nouveau_gpuobj_takedown(struct drm_device *dev) + + NV_DEBUG(dev, "\n"); + +- nouveau_gpuobj_del(dev, &dev_priv->ramht); ++ BUG_ON(!list_empty(&dev_priv->gpuobj_list)); + } + +-void +-nouveau_gpuobj_late_takedown(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *gpuobj = NULL; +- struct list_head *entry, *tmp; +- +- NV_DEBUG(dev, "\n"); +- +- list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) { +- gpuobj = list_entry(entry, struct nouveau_gpuobj, list); + +- NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n", +- gpuobj, gpuobj->refcount); +- gpuobj->refcount = 0; +- nouveau_gpuobj_del(dev, &gpuobj); +- } +-} +- +-int +-nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) ++static void ++nouveau_gpuobj_del(struct kref *ref) + { ++ struct nouveau_gpuobj *gpuobj = ++ container_of(ref, struct nouveau_gpuobj, refcount); ++ struct drm_device *dev = gpuobj->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; +- struct nouveau_gpuobj *gpuobj; + int i; + +- NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); +- +- if (!dev_priv || !pgpuobj || !(*pgpuobj)) +- return -EINVAL; +- gpuobj = *pgpuobj; +- +- if (gpuobj->refcount != 0) { +- NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount); +- return -EINVAL; +- } ++ NV_DEBUG(dev, "gpuobj %p\n", gpuobj); if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { - engine->instmem.prepare_access(dev, true); - for (i = 0; i < gpuobj->im_pramin->size; i += 4) +- for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); ++ for (i = 0; i < gpuobj->size; i += 4) + nv_wo32(gpuobj, i, 0); + engine->instmem.flush(dev); } if (gpuobj->dtor) -@@ -386,7 +239,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) - if (gpuobj->flags & NVOBJ_FLAG_FAKE) - kfree(gpuobj->im_pramin); - else -- nouveau_mem_free_block(gpuobj->im_pramin); -+ drm_mm_put_block(gpuobj->im_pramin); - } + gpuobj->dtor(dev, gpuobj); +- if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE)) ++ if (gpuobj->im_backing) + engine->instmem.clear(dev, gpuobj); + +- if (gpuobj->im_pramin) { +- if (gpuobj->flags & NVOBJ_FLAG_FAKE) +- kfree(gpuobj->im_pramin); +- else +- nouveau_mem_free_block(gpuobj->im_pramin); +- } +- ++ spin_lock(&dev_priv->ramin_lock); ++ if (gpuobj->im_pramin) ++ drm_mm_put_block(gpuobj->im_pramin); list_del(&gpuobj->list); -@@ -583,13 +436,14 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, ++ spin_unlock(&dev_priv->ramin_lock); + +- *pgpuobj = NULL; + kfree(gpuobj); +- return 0; +-} +- +-static int +-nouveau_gpuobj_instance_get(struct drm_device *dev, +- struct nouveau_channel *chan, +- struct nouveau_gpuobj *gpuobj, uint32_t *inst) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *cpramin; +- +- /* card_type < NV_50) { +- *inst = gpuobj->im_pramin->start; +- return 0; +- } +- +- if (chan && gpuobj->im_channel != chan) { +- NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n", +- gpuobj->im_channel->id, chan->id); +- return -EINVAL; +- } +- +- /* NV50 channel-local instance */ +- if (chan) { +- cpramin = chan->ramin->gpuobj; +- *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; +- return 0; +- } +- +- /* NV50 global (VRAM) instance */ +- if (!gpuobj->im_channel) { +- /* ...from global heap */ +- if (!gpuobj->im_backing) { +- NV_ERROR(dev, "AII, no VRAM backing gpuobj\n"); +- return -EINVAL; +- } +- *inst = gpuobj->im_backing_start; +- return 0; +- } else { +- /* ...from local heap */ +- cpramin = gpuobj->im_channel->ramin->gpuobj; +- *inst = cpramin->im_backing_start + +- (gpuobj->im_pramin->start - cpramin->im_pramin->start); +- return 0; +- } +- +- return -EINVAL; +-} +- +-int +-nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan, +- uint32_t handle, struct nouveau_gpuobj *gpuobj, +- struct nouveau_gpuobj_ref **ref_ret) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj_ref *ref; +- uint32_t instance; +- int ret; +- +- NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n", +- chan ? chan->id : -1, handle, gpuobj); +- +- if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL)) +- return -EINVAL; +- +- if (!chan && !ref_ret) +- return -EINVAL; +- +- if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) { +- /* sw object */ +- instance = 0x40; +- } else { +- ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance); +- if (ret) +- return ret; +- } +- +- ref = kzalloc(sizeof(*ref), GFP_KERNEL); +- if (!ref) +- return -ENOMEM; +- INIT_LIST_HEAD(&ref->list); +- ref->gpuobj = gpuobj; +- ref->channel = chan; +- ref->instance = instance; +- +- if (!ref_ret) { +- ref->handle = handle; +- +- ret = nouveau_ramht_insert(dev, ref); +- if (ret) { +- kfree(ref); +- return ret; +- } +- } else { +- ref->handle = ~0; +- *ref_ret = ref; +- } +- +- ref->gpuobj->refcount++; +- return 0; + } + +-int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref) +-{ +- struct nouveau_gpuobj_ref *ref; +- +- NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL); +- +- if (!dev || !pref || *pref == NULL) +- return -EINVAL; +- ref = *pref; +- +- if (ref->handle != ~0) +- nouveau_ramht_remove(dev, ref); +- +- if (ref->gpuobj) { +- ref->gpuobj->refcount--; +- +- if (ref->gpuobj->refcount == 0) { +- if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS)) +- nouveau_gpuobj_del(dev, &ref->gpuobj); +- } +- } +- +- *pref = NULL; +- kfree(ref); +- return 0; +-} +- +-int +-nouveau_gpuobj_new_ref(struct drm_device *dev, +- struct nouveau_channel *oc, struct nouveau_channel *rc, +- uint32_t handle, uint32_t size, int align, +- uint32_t flags, struct nouveau_gpuobj_ref **ref) +-{ +- struct nouveau_gpuobj *gpuobj = NULL; +- int ret; +- +- ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj); +- if (ret) +- return ret; +- +- ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref); +- if (ret) { +- nouveau_gpuobj_del(dev, &gpuobj); +- return ret; +- } +- +- return 0; +-} +- +-int +-nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle, +- struct nouveau_gpuobj_ref **ref_ret) ++void ++nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr) + { +- struct nouveau_gpuobj_ref *ref; +- struct list_head *entry, *tmp; ++ if (ref) ++ kref_get(&ref->refcount); + +- list_for_each_safe(entry, tmp, &chan->ramht_refs) { +- ref = list_entry(entry, struct nouveau_gpuobj_ref, list); ++ if (*ptr) ++ kref_put(&(*ptr)->refcount, nouveau_gpuobj_del); + +- if (ref->handle == handle) { +- if (ref_ret) +- *ref_ret = ref; +- return 0; +- } +- } +- +- return -EINVAL; ++ *ptr = ref; + } + + int +-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, +- uint32_t b_offset, uint32_t size, +- uint32_t flags, struct nouveau_gpuobj **pgpuobj, +- struct nouveau_gpuobj_ref **pref) ++nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst, ++ u32 size, u32 flags, struct nouveau_gpuobj **pgpuobj) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *gpuobj = NULL; + int i; + + NV_DEBUG(dev, +- "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n", +- p_offset, b_offset, size, flags); ++ "pinst=0x%08x vinst=0x%010llx size=0x%08x flags=0x%08x\n", ++ pinst, vinst, size, flags); + + gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); if (!gpuobj) return -ENOMEM; NV_DEBUG(dev, "gpuobj %p\n", gpuobj); -+ gpuobj->dev = dev; - gpuobj->im_channel = NULL; - gpuobj->flags = flags | NVOBJ_FLAG_FAKE; - - list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); - - if (p_offset != ~0) { +- gpuobj->im_channel = NULL; +- gpuobj->flags = flags | NVOBJ_FLAG_FAKE; +- +- list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); +- +- if (p_offset != ~0) { - gpuobj->im_pramin = kzalloc(sizeof(struct mem_block), -+ gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node), - GFP_KERNEL); - if (!gpuobj->im_pramin) { - nouveau_gpuobj_del(dev, &gpuobj); -@@ -605,10 +459,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, - } +- GFP_KERNEL); +- if (!gpuobj->im_pramin) { +- nouveau_gpuobj_del(dev, &gpuobj); +- return -ENOMEM; +- } +- gpuobj->im_pramin->start = p_offset; +- gpuobj->im_pramin->size = size; +- } +- +- if (b_offset != ~0) { +- gpuobj->im_backing = (struct nouveau_bo *)-1; +- gpuobj->im_backing_start = b_offset; +- } ++ gpuobj->dev = dev; ++ gpuobj->flags = flags; ++ kref_init(&gpuobj->refcount); ++ gpuobj->size = size; ++ gpuobj->pinst = pinst; ++ gpuobj->cinst = 0xdeadbeef; ++ gpuobj->vinst = vinst; if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { - dev_priv->engine.instmem.prepare_access(dev, true); - for (i = 0; i < gpuobj->im_pramin->size; i += 4) +- for (i = 0; i < gpuobj->im_pramin->size; i += 4) - nv_wo32(dev, gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); ++ for (i = 0; i < gpuobj->size; i += 4) + nv_wo32(gpuobj, i, 0); + dev_priv->engine.instmem.flush(dev); } - if (pref) { -@@ -696,8 +549,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, +- if (pref) { +- i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref); +- if (i) { +- nouveau_gpuobj_del(dev, &gpuobj); +- return i; +- } +- } +- +- if (pgpuobj) +- *pgpuobj = gpuobj; ++ spin_lock(&dev_priv->ramin_lock); ++ list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); ++ spin_unlock(&dev_priv->ramin_lock); ++ *pgpuobj = gpuobj; + return 0; + } + +@@ -696,8 +366,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, return ret; } @@ -6260,7 +7359,7 @@ index e7c100b..6aedc3b 100644 if (dev_priv->card_type < NV_50) { uint32_t frame, adjust, pte_flags = 0; -@@ -706,14 +557,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, +@@ -706,14 +374,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, adjust = offset & 0x00000fff; frame = offset & ~0x00000fff; @@ -6281,7 +7380,7 @@ index e7c100b..6aedc3b 100644 } else { uint64_t limit = offset + size - 1; uint32_t flags0, flags5; -@@ -726,15 +575,15 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, +@@ -726,15 +392,15 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, flags5 = 0x00080000; } @@ -6304,7 +7403,16 @@ index e7c100b..6aedc3b 100644 (*gpuobj)->engine = NVOBJ_ENGINE_SW; (*gpuobj)->class = class; -@@ -849,32 +698,31 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, +@@ -762,7 +428,7 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan, + *o_ret = 0; + } else + if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) { +- *gpuobj = dev_priv->gart_info.sg_ctxdma; ++ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj); + if (offset & ~0xffffffffULL) { + NV_ERROR(dev, "obj offset exceeds 32-bits\n"); + return -EINVAL; +@@ -849,32 +515,31 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return ret; } @@ -6346,7 +7454,31 @@ index e7c100b..6aedc3b 100644 (*gpuobj)->engine = NVOBJ_ENGINE_GR; (*gpuobj)->class = class; -@@ -920,6 +768,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) +@@ -895,10 +560,15 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, + gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); + if (!gpuobj) + return -ENOMEM; ++ gpuobj->dev = chan->dev; + gpuobj->engine = NVOBJ_ENGINE_SW; + gpuobj->class = class; ++ kref_init(&gpuobj->refcount); ++ gpuobj->cinst = 0x40; + ++ spin_lock(&dev_priv->ramin_lock); + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); ++ spin_unlock(&dev_priv->ramin_lock); + *gpuobj_ret = gpuobj; + return 0; + } +@@ -908,7 +578,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *pramin = NULL; + uint32_t size; + uint32_t base; + int ret; +@@ -920,6 +589,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) base = 0; /* PGRAPH context */ @@ -6354,7 +7486,7 @@ index e7c100b..6aedc3b 100644 if (dev_priv->card_type == NV_50) { /* Various fixed table thingos */ -@@ -930,12 +779,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) +@@ -930,25 +600,18 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) size += 0x8000; /* RAMFC */ size += 0x1000; @@ -6364,21 +7496,31 @@ index e7c100b..6aedc3b 100644 - NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", - chan->id, size, base); - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, - &chan->ramin); +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, +- &chan->ramin); ++ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); if (ret) { -@@ -944,8 +789,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret); + return ret; } - pramin = chan->ramin->gpuobj; +- pramin = chan->ramin->gpuobj; - ret = nouveau_mem_init_heap(&chan->ramin_heap, - pramin->im_pramin->start + base, size); -+ ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size); ++ ret = drm_mm_init(&chan->ramin_heap, base, size); if (ret) { NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret); - nouveau_gpuobj_ref_del(dev, &chan->ramin); -@@ -969,15 +813,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +- nouveau_gpuobj_ref_del(dev, &chan->ramin); ++ nouveau_gpuobj_ref(NULL, &chan->ramin); + return ret; + } +@@ -965,19 +628,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + struct nouveau_gpuobj *vram = NULL, *tt = NULL; + int ret, i; + +- INIT_LIST_HEAD(&chan->ramht_refs); +- NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); - /* Reserve a block of PRAMIN for the channel @@ -6398,19 +7540,29 @@ index e7c100b..6aedc3b 100644 } /* NV50 VM -@@ -988,50 +828,42 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +@@ -986,65 +643,56 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + * locations determined during init. + */ if (dev_priv->card_type >= NV_50) { - uint32_t vm_offset, pde; - -- instmem->prepare_access(dev, true); +- uint32_t vm_offset, pde; - - vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; - vm_offset += chan->ramin->gpuobj->im_pramin->start; +- instmem->prepare_access(dev, true); ++ u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; ++ u64 vm_vinst = chan->ramin->vinst + pgd_offs; ++ u32 vm_pinst = chan->ramin->pinst; ++ u32 pde; - ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, - 0, &chan->vm_pd, NULL); +- vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; +- vm_offset += chan->ramin->gpuobj->im_pramin->start; ++ if (vm_pinst != ~0) ++ vm_pinst += pgd_offs; + +- ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, +- 0, &chan->vm_pd, NULL); - if (ret) { - instmem->finish_access(dev); ++ ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000, ++ 0, &chan->vm_pd); + if (ret) return ret; - } @@ -6422,38 +7574,40 @@ index e7c100b..6aedc3b 100644 } - pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2; -+ pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8; - ret = nouveau_gpuobj_ref_add(dev, NULL, 0, - dev_priv->gart_info.sg_ctxdma, - &chan->vm_gart_pt); +- ret = nouveau_gpuobj_ref_add(dev, NULL, 0, +- dev_priv->gart_info.sg_ctxdma, +- &chan->vm_gart_pt); - if (ret) { - instmem->finish_access(dev); -+ if (ret) - return ret; +- return ret; - } - nv_wo32(dev, chan->vm_pd, pde++, - chan->vm_gart_pt->instance | 0x03); - nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); -+ nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->instance | 3); ++ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, ++ &chan->vm_gart_pt); ++ pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8; ++ nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3); + nv_wo32(chan->vm_pd, pde + 4, 0x00000000); - pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2; + pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8; for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { - ret = nouveau_gpuobj_ref_add(dev, NULL, 0, - dev_priv->vm_vram_pt[i], - &chan->vm_vram_pt[i]); +- ret = nouveau_gpuobj_ref_add(dev, NULL, 0, +- dev_priv->vm_vram_pt[i], +- &chan->vm_vram_pt[i]); - if (ret) { - instmem->finish_access(dev); -+ if (ret) - return ret; +- return ret; - } ++ nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i], ++ &chan->vm_vram_pt[i]); - nv_wo32(dev, chan->vm_pd, pde++, - chan->vm_vram_pt[i]->instance | 0x61); - nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); + nv_wo32(chan->vm_pd, pde + 0, -+ chan->vm_vram_pt[i]->instance | 0x61); ++ chan->vm_vram_pt[i]->vinst | 0x61); + nv_wo32(chan->vm_pd, pde + 4, 0x00000000); + pde += 8; } @@ -6463,18 +7617,134 @@ index e7c100b..6aedc3b 100644 } /* RAMHT */ -@@ -1130,8 +962,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) - nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); + if (dev_priv->card_type < NV_50) { +- ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht, +- &chan->ramht); ++ nouveau_ramht_ref(dev_priv->ramht, &chan->ramht, NULL); ++ } else { ++ struct nouveau_gpuobj *ramht = NULL; ++ ++ ret = nouveau_gpuobj_new(dev, chan, 0x8000, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, &ramht); + if (ret) + return ret; +- } else { +- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, +- 0x8000, 16, +- NVOBJ_FLAG_ZERO_ALLOC, +- &chan->ramht); ++ ++ ret = nouveau_ramht_new(dev, ramht, &chan->ramht); ++ nouveau_gpuobj_ref(NULL, &ramht); + if (ret) + return ret; + } +@@ -1061,24 +709,32 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + } + } else { + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, +- 0, dev_priv->fb_available_size, +- NV_DMA_ACCESS_RW, +- NV_DMA_TARGET_VIDMEM, &vram); ++ 0, dev_priv->fb_available_size, ++ NV_DMA_ACCESS_RW, ++ NV_DMA_TARGET_VIDMEM, &vram); + if (ret) { + NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); + return ret; + } + } +- ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL); ++ ret = nouveau_ramht_insert(chan, vram_h, vram); ++ nouveau_gpuobj_ref(NULL, &vram); + if (ret) { +- NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", ret); ++ NV_ERROR(dev, "Error adding VRAM ctxdma to RAMHT: %d\n", ret); + return ret; + } + + /* TT memory ctxdma */ + if (dev_priv->card_type >= NV_50) { +- tt = vram; ++ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, ++ 0, dev_priv->vm_end, ++ NV_DMA_ACCESS_RW, ++ NV_DMA_TARGET_AGP, &tt); ++ if (ret) { ++ NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); ++ return ret; ++ } + } else + if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { + ret = nouveau_gpuobj_gart_dma_new(chan, 0, +@@ -1094,9 +750,10 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + return ret; + } + +- ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL); ++ ret = nouveau_ramht_insert(chan, tt_h, tt); ++ nouveau_gpuobj_ref(NULL, &tt); + if (ret) { +- NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret); ++ NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret); + return ret; + } + +@@ -1108,33 +765,23 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_device *dev = chan->dev; +- struct list_head *entry, *tmp; +- struct nouveau_gpuobj_ref *ref; + int i; + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- if (!chan->ramht_refs.next) ++ if (!chan->ramht) + return; + +- list_for_each_safe(entry, tmp, &chan->ramht_refs) { +- ref = list_entry(entry, struct nouveau_gpuobj_ref, list); ++ nouveau_ramht_ref(NULL, &chan->ramht, chan); + +- nouveau_gpuobj_ref_del(dev, &ref); +- } +- +- nouveau_gpuobj_ref_del(dev, &chan->ramht); +- +- nouveau_gpuobj_del(dev, &chan->vm_pd); +- nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt); ++ nouveau_gpuobj_ref(NULL, &chan->vm_pd); ++ nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt); + for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) +- nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); +- - if (chan->ramin_heap) - nouveau_mem_takedown(&chan->ramin_heap); +- if (chan->ramin) +- nouveau_gpuobj_ref_del(dev, &chan->ramin); ++ nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); + + if (chan->ramin_heap.fl_entry.next) + drm_mm_takedown(&chan->ramin_heap); - if (chan->ramin) - nouveau_gpuobj_ref_del(dev, &chan->ramin); ++ nouveau_gpuobj_ref(NULL, &chan->ramin); + } -@@ -1164,10 +996,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev) + int +@@ -1155,19 +802,17 @@ nouveau_gpuobj_suspend(struct drm_device *dev) + } + + list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { +- if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE)) ++ if (!gpuobj->im_backing) + continue; + +- gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size); ++ gpuobj->im_backing_suspend = vmalloc(gpuobj->size); + if (!gpuobj->im_backing_suspend) { + nouveau_gpuobj_resume(dev); return -ENOMEM; } @@ -6482,12 +7752,12 @@ index e7c100b..6aedc3b 100644 - for (i = 0; i < gpuobj->im_pramin->size / 4; i++) - gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i); - dev_priv->engine.instmem.finish_access(dev); -+ for (i = 0; i < gpuobj->im_pramin->size; i += 4) ++ for (i = 0; i < gpuobj->size; i += 4) + gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i); } return 0; -@@ -1212,10 +1042,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) +@@ -1212,10 +857,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) if (!gpuobj->im_backing_suspend) continue; @@ -6495,13 +7765,13 @@ index e7c100b..6aedc3b 100644 - for (i = 0; i < gpuobj->im_pramin->size / 4; i++) - nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]); - dev_priv->engine.instmem.finish_access(dev); -+ for (i = 0; i < gpuobj->im_pramin->size; i += 4) ++ for (i = 0; i < gpuobj->size; i += 4) + nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]); + dev_priv->engine.instmem.flush(dev); } nouveau_gpuobj_suspend_cleanup(dev); -@@ -1232,7 +1061,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, +@@ -1232,7 +876,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; @@ -6509,38 +7779,111 @@ index e7c100b..6aedc3b 100644 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); if (init->handle == ~0) -@@ -1283,7 +1111,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, +@@ -1250,25 +893,24 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, + return -EPERM; + } + +- if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0) ++ if (nouveau_ramht_find(chan, init->handle)) + return -EEXIST; + + if (!grc->software) + ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr); + else + ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr); +- + if (ret) { + NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", + ret, init->channel, init->handle); + return ret; + } + +- ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL); ++ ret = nouveau_ramht_insert(chan, init->handle, gr); ++ nouveau_gpuobj_ref(NULL, &gr); + if (ret) { + NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n", + ret, init->channel, init->handle); +- nouveau_gpuobj_del(dev, &gr); + return ret; + } + +@@ -1279,17 +921,62 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) + { + struct drm_nouveau_gpuobj_free *objfree = data; +- struct nouveau_gpuobj_ref *ref; ++ struct nouveau_gpuobj *gpuobj; struct nouveau_channel *chan; - int ret; +- int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); - ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); -@@ -1293,3 +1120,17 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, +- ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); +- if (ret) +- return ret; +- nouveau_gpuobj_ref_del(dev, &ref); ++ gpuobj = nouveau_ramht_find(chan, objfree->handle); ++ if (!gpuobj) ++ return -ENOENT; ++ nouveau_ramht_remove(chan, objfree->handle); return 0; } + +u32 +nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) +{ ++ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct drm_device *dev = gpuobj->dev; -+ return nv_ri32(dev, gpuobj->im_pramin->start + offset); ++ ++ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { ++ u64 ptr = gpuobj->vinst + offset; ++ u32 base = ptr >> 16; ++ u32 val; ++ ++ spin_lock(&dev_priv->ramin_lock); ++ if (dev_priv->ramin_base != base) { ++ dev_priv->ramin_base = base; ++ nv_wr32(dev, 0x001700, dev_priv->ramin_base); ++ } ++ val = nv_rd32(dev, 0x700000 + (ptr & 0xffff)); ++ spin_unlock(&dev_priv->ramin_lock); ++ return val; ++ } ++ ++ return nv_ri32(dev, gpuobj->pinst + offset); +} + +void +nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) +{ ++ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct drm_device *dev = gpuobj->dev; -+ nv_wi32(dev, gpuobj->im_pramin->start + offset, val); ++ ++ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { ++ u64 ptr = gpuobj->vinst + offset; ++ u32 base = ptr >> 16; ++ ++ spin_lock(&dev_priv->ramin_lock); ++ if (dev_priv->ramin_base != base) { ++ dev_priv->ramin_base = base; ++ nv_wr32(dev, 0x001700, dev_priv->ramin_base); ++ } ++ nv_wr32(dev, 0x700000 + (ptr & 0xffff), val); ++ spin_unlock(&dev_priv->ramin_lock); ++ return; ++ } ++ ++ nv_wi32(dev, gpuobj->pinst + offset, val); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c new file mode 100644 -index 0000000..e5cc93c +index 0000000..7f16697 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c -@@ -0,0 +1,160 @@ +@@ -0,0 +1,289 @@ +/* + * Copyright 2010 Red Hat Inc. + * @@ -6570,22 +7913,24 @@ index 0000000..e5cc93c +#include "nouveau_drv.h" +#include "nouveau_ramht.h" + -+static uint32_t -+nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) ++static u32 ++nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle) +{ ++ struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; -+ uint32_t hash = 0; ++ struct nouveau_ramht *ramht = chan->ramht; ++ u32 hash = 0; + int i; + -+ NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle); ++ NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle); + -+ for (i = 32; i > 0; i -= dev_priv->ramht_bits) { -+ hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); -+ handle >>= dev_priv->ramht_bits; ++ for (i = 32; i > 0; i -= ramht->bits) { ++ hash ^= (handle & ((1 << ramht->bits) - 1)); ++ handle >>= ramht->bits; + } + + if (dev_priv->card_type < NV_50) -+ hash ^= channel << (dev_priv->ramht_bits - 4); ++ hash ^= chan->id << (ramht->bits - 4); + hash <<= 3; + + NV_DEBUG(dev, "hash=0x%08x\n", hash); @@ -6594,59 +7939,88 @@ index 0000000..e5cc93c + +static int +nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, -+ uint32_t offset) ++ u32 offset) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; -+ uint32_t ctx = nv_ro32(ramht, offset + 4); ++ u32 ctx = nv_ro32(ramht, offset + 4); + + if (dev_priv->card_type < NV_40) + return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); + return (ctx != 0); +} + -+int -+nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) ++static int ++nouveau_ramht_entry_same_channel(struct nouveau_channel *chan, ++ struct nouveau_gpuobj *ramht, u32 offset) +{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ u32 ctx = nv_ro32(ramht, offset + 4); ++ ++ if (dev_priv->card_type >= NV_50) ++ return true; ++ else if (dev_priv->card_type >= NV_40) ++ return chan->id == ++ ((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f); ++ else ++ return chan->id == ++ ((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f); ++} ++ ++int ++nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, ++ struct nouveau_gpuobj *gpuobj) ++{ ++ struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; -+ struct nouveau_channel *chan = ref->channel; -+ struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; -+ uint32_t ctx, co, ho; ++ struct nouveau_ramht_entry *entry; ++ struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; ++ unsigned long flags; ++ u32 ctx, co, ho; + -+ if (!ramht) { -+ NV_ERROR(dev, "No hash table!\n"); -+ return -EINVAL; -+ } ++ if (nouveau_ramht_find(chan, handle)) ++ return -EEXIST; ++ ++ entry = kmalloc(sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return -ENOMEM; ++ entry->channel = chan; ++ entry->gpuobj = NULL; ++ entry->handle = handle; ++ nouveau_gpuobj_ref(gpuobj, &entry->gpuobj); + + if (dev_priv->card_type < NV_40) { -+ ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | ++ ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) | + (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | -+ (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); ++ (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); + } else + if (dev_priv->card_type < NV_50) { -+ ctx = (ref->instance >> 4) | ++ ctx = (gpuobj->cinst >> 4) | + (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | -+ (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); ++ (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + } else { -+ if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { -+ ctx = (ref->instance << 10) | 2; ++ if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { ++ ctx = (gpuobj->cinst << 10) | 2; + } else { -+ ctx = (ref->instance >> 4) | -+ ((ref->gpuobj->engine << ++ ctx = (gpuobj->cinst >> 4) | ++ ((gpuobj->engine << + NV40_RAMHT_CONTEXT_ENGINE_SHIFT)); + } + } + -+ co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); ++ spin_lock_irqsave(&chan->ramht->lock, flags); ++ list_add(&entry->head, &chan->ramht->entries); ++ ++ co = ho = nouveau_ramht_hash_handle(chan, handle); + do { + if (!nouveau_ramht_entry_valid(dev, ramht, co)) { + NV_DEBUG(dev, + "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", -+ chan->id, co, ref->handle, ctx); -+ nv_wo32(ramht, co + 0, ref->handle); ++ chan->id, co, handle, ctx); ++ nv_wo32(ramht, co + 0, handle); + nv_wo32(ramht, co + 4, ctx); + -+ list_add_tail(&ref->list, &chan->ramht_refs); ++ spin_unlock_irqrestore(&chan->ramht->lock, flags); + instmem->flush(dev); + return 0; + } @@ -6654,59 +8028,157 @@ index 0000000..e5cc93c + chan->id, co, nv_ro32(ramht, co)); + + co += 8; -+ if (co >= dev_priv->ramht_size) ++ if (co >= ramht->size) + co = 0; + } while (co != ho); + + NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); ++ list_del(&entry->head); ++ spin_unlock_irqrestore(&chan->ramht->lock, flags); ++ kfree(entry); + return -ENOMEM; +} + -+void -+nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) ++static void ++nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) +{ ++ struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; -+ struct nouveau_channel *chan = ref->channel; -+ struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; -+ uint32_t co, ho; ++ struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; ++ struct nouveau_ramht_entry *entry, *tmp; ++ u32 co, ho; + -+ if (!ramht) { -+ NV_ERROR(dev, "No hash table!\n"); -+ return; ++ list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) { ++ if (entry->channel != chan || entry->handle != handle) ++ continue; ++ ++ nouveau_gpuobj_ref(NULL, &entry->gpuobj); ++ list_del(&entry->head); ++ kfree(entry); ++ break; + } + -+ co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); ++ co = ho = nouveau_ramht_hash_handle(chan, handle); + do { + if (nouveau_ramht_entry_valid(dev, ramht, co) && -+ (ref->handle == nv_ro32(ramht, co))) { ++ nouveau_ramht_entry_same_channel(chan, ramht, co) && ++ (handle == nv_ro32(ramht, co))) { + NV_DEBUG(dev, + "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", -+ chan->id, co, ref->handle, -+ nv_ro32(ramht, co + 4)); ++ chan->id, co, handle, nv_ro32(ramht, co + 4)); + nv_wo32(ramht, co + 0, 0x00000000); + nv_wo32(ramht, co + 4, 0x00000000); -+ -+ list_del(&ref->list); + instmem->flush(dev); + return; + } + + co += 8; -+ if (co >= dev_priv->ramht_size) ++ if (co >= ramht->size) + co = 0; + } while (co != ho); -+ list_del(&ref->list); + + NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", -+ chan->id, ref->handle); ++ chan->id, handle); ++} ++ ++void ++nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) ++{ ++ struct nouveau_ramht *ramht = chan->ramht; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ramht->lock, flags); ++ nouveau_ramht_remove_locked(chan, handle); ++ spin_unlock_irqrestore(&ramht->lock, flags); ++} ++ ++struct nouveau_gpuobj * ++nouveau_ramht_find(struct nouveau_channel *chan, u32 handle) ++{ ++ struct nouveau_ramht *ramht = chan->ramht; ++ struct nouveau_ramht_entry *entry; ++ struct nouveau_gpuobj *gpuobj = NULL; ++ unsigned long flags; ++ ++ if (unlikely(!chan->ramht)) ++ return NULL; ++ ++ spin_lock_irqsave(&ramht->lock, flags); ++ list_for_each_entry(entry, &chan->ramht->entries, head) { ++ if (entry->channel == chan && entry->handle == handle) { ++ gpuobj = entry->gpuobj; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&ramht->lock, flags); ++ ++ return gpuobj; ++} ++ ++int ++nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, ++ struct nouveau_ramht **pramht) ++{ ++ struct nouveau_ramht *ramht; ++ ++ ramht = kzalloc(sizeof(*ramht), GFP_KERNEL); ++ if (!ramht) ++ return -ENOMEM; ++ ++ ramht->dev = dev; ++ kref_init(&ramht->refcount); ++ ramht->bits = drm_order(gpuobj->size / 8); ++ INIT_LIST_HEAD(&ramht->entries); ++ spin_lock_init(&ramht->lock); ++ nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj); ++ ++ *pramht = ramht; ++ return 0; ++} ++ ++static void ++nouveau_ramht_del(struct kref *ref) ++{ ++ struct nouveau_ramht *ramht = ++ container_of(ref, struct nouveau_ramht, refcount); ++ ++ nouveau_gpuobj_ref(NULL, &ramht->gpuobj); ++ kfree(ramht); ++} ++ ++void ++nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, ++ struct nouveau_channel *chan) ++{ ++ struct nouveau_ramht_entry *entry, *tmp; ++ struct nouveau_ramht *ramht; ++ unsigned long flags; ++ ++ if (ref) ++ kref_get(&ref->refcount); ++ ++ ramht = *ptr; ++ if (ramht) { ++ spin_lock_irqsave(&ramht->lock, flags); ++ list_for_each_entry_safe(entry, tmp, &ramht->entries, head) { ++ if (entry->channel != chan) ++ continue; ++ ++ nouveau_ramht_remove_locked(chan, entry->handle); ++ } ++ spin_unlock_irqrestore(&ramht->lock, flags); ++ ++ kref_put(&ramht->refcount, nouveau_ramht_del); ++ } ++ *ptr = ref; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h new file mode 100644 -index 0000000..e10455c +index 0000000..b79cb5e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h -@@ -0,0 +1,31 @@ +@@ -0,0 +1,55 @@ +/* + * Copyright 2010 Red Hat Inc. + * @@ -6734,12 +8206,36 @@ index 0000000..e10455c +#ifndef __NOUVEAU_RAMHT_H__ +#define __NOUVEAU_RAMHT_H__ + -+extern int nouveau_ramht_insert(struct drm_device *, struct nouveau_gpuobj_ref *); -+extern void nouveau_ramht_remove(struct drm_device *, struct nouveau_gpuobj_ref *); ++struct nouveau_ramht_entry { ++ struct list_head head; ++ struct nouveau_channel *channel; ++ struct nouveau_gpuobj *gpuobj; ++ u32 handle; ++}; ++ ++struct nouveau_ramht { ++ struct drm_device *dev; ++ struct kref refcount; ++ spinlock_t lock; ++ struct nouveau_gpuobj *gpuobj; ++ struct list_head entries; ++ int bits; ++}; ++ ++extern int nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *, ++ struct nouveau_ramht **); ++extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **, ++ struct nouveau_channel *unref_channel); ++ ++extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle, ++ struct nouveau_gpuobj *); ++extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle); ++extern struct nouveau_gpuobj * ++nouveau_ramht_find(struct nouveau_channel *chan, u32 handle); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h -index 6ca80a3..21a6e45 100644 +index 6ca80a3..1b42541 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -1,19 +1,64 @@ @@ -6891,7 +8387,34 @@ index 6ca80a3..21a6e45 100644 #define NV10_PGRAPH_DMA_PITCH 0x00400770 #define NV10_PGRAPH_DVD_COLORFMT 0x00400774 #define NV10_PGRAPH_SCALED_FORMAT 0x00400778 -@@ -814,6 +838,7 @@ +@@ -527,6 +551,8 @@ + #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 +@@ -761,15 +787,12 @@ + #define NV50_PDISPLAY_DAC_MODE_CTRL_C(i) (0x00610b5c + (i) * 0x8) + #define NV50_PDISPLAY_SOR_MODE_CTRL_P(i) (0x00610b70 + (i) * 0x8) + #define NV50_PDISPLAY_SOR_MODE_CTRL_C(i) (0x00610b74 + (i) * 0x8) ++#define NV50_PDISPLAY_EXT_MODE_CTRL_P(i) (0x00610b80 + (i) * 0x8) ++#define NV50_PDISPLAY_EXT_MODE_CTRL_C(i) (0x00610b84 + (i) * 0x8) + #define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i) (0x00610bdc + (i) * 0x8) + #define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i) (0x00610be0 + (i) * 0x8) +- + #define NV90_PDISPLAY_SOR_MODE_CTRL_P(i) (0x00610794 + (i) * 0x8) + #define NV90_PDISPLAY_SOR_MODE_CTRL_C(i) (0x00610798 + (i) * 0x8) +-#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i) (0x00610b58 + (i) * 0x8) +-#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i) (0x00610b5c + (i) * 0x8) +-#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i) (0x00610b80 + (i) * 0x8) +-#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i) (0x00610b84 + (i) * 0x8) + + #define NV50_PDISPLAY_CRTC_CLK 0x00614000 + #define NV50_PDISPLAY_CRTC_CLK_CTRL1(i) ((i) * 0x800 + 0x614100) +@@ -814,6 +837,7 @@ #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff #define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) @@ -6900,7 +8423,7 @@ index 6ca80a3..21a6e45 100644 #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -index 1d6ee8b..630988a 100644 +index 1d6ee8b..5a66a7a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) @@ -7015,12 +8538,20 @@ index 1d6ee8b..630988a 100644 struct nouveau_gpuobj *gpuobj = NULL; uint32_t aper_size, obj_size; int i, ret; -@@ -267,34 +244,42 @@ nouveau_sgdma_init(struct drm_device *dev) +@@ -257,7 +234,6 @@ nouveau_sgdma_init(struct drm_device *dev) + } + + ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, +- NVOBJ_FLAG_ALLOW_NO_REFS | + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, &gpuobj); + if (ret) { +@@ -267,34 +243,48 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.sg_dummy_page = alloc_page(GFP_KERNEL|__GFP_DMA32); + if (!dev_priv->gart_info.sg_dummy_page) { -+ nouveau_gpuobj_del(dev, &gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + return -ENOMEM; + } + @@ -7030,12 +8561,18 @@ index 1d6ee8b..630988a 100644 + pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { -+ nouveau_gpuobj_del(dev, &gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + return -EFAULT; + } - dev_priv->engine.instmem.prepare_access(dev, true); if (dev_priv->card_type < NV_50) { ++ /* special case, allocated from global instmem heap so ++ * cinst is invalid, we use it on all channels though so ++ * cinst needs to be valid, set it the same as pinst ++ */ ++ gpuobj->cinst = gpuobj->pinst; ++ /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE * on those cards? */ @@ -7072,7 +8609,16 @@ index 1d6ee8b..630988a 100644 dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; dev_priv->gart_info.aper_base = 0; -@@ -325,14 +310,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) +@@ -317,7 +307,7 @@ nouveau_sgdma_takedown(struct drm_device *dev) + dev_priv->gart_info.sg_dummy_bus = 0; + } + +- nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma); ++ nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); + } + + int +@@ -325,14 +315,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; @@ -7090,10 +8636,14 @@ index 1d6ee8b..630988a 100644 } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c -index b02a231..989322b 100644 +index b02a231..be85960 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c -@@ -38,6 +38,7 @@ +@@ -35,9 +35,11 @@ + #include "nouveau_drv.h" + #include "nouveau_drm.h" + #include "nouveau_fbcon.h" ++#include "nouveau_ramht.h" #include "nv50_display.h" static void nouveau_stub_takedown(struct drm_device *dev) {} @@ -7101,7 +8651,7 @@ index b02a231..989322b 100644 static int nouveau_init_engine_ptrs(struct drm_device *dev) { -@@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -54,8 +56,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -7111,7 +8661,14 @@ index b02a231..989322b 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -78,13 +79,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.disable = nv04_fifo_disable; + engine->fifo.enable = nv04_fifo_enable; + engine->fifo.reassign = nv04_fifo_reassign; +- engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; + engine->fifo.channel_id = nv04_fifo_channel_id; + engine->fifo.create_context = nv04_fifo_create_context; engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv04_fifo_load_context; engine->fifo.unload_context = nv04_fifo_unload_context; @@ -7138,7 +8695,14 @@ index b02a231..989322b 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -121,13 +130,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.disable = nv04_fifo_disable; + engine->fifo.enable = nv04_fifo_enable; + engine->fifo.reassign = nv04_fifo_reassign; +- engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; + engine->fifo.channel_id = nv10_fifo_channel_id; + engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; @@ -7155,7 +8719,7 @@ index b02a231..989322b 100644 break; case 0x20: engine->instmem.init = nv04_instmem_init; -@@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -138,8 +156,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -7165,7 +8729,14 @@ index b02a231..989322b 100644 engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -164,13 +181,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.disable = nv04_fifo_disable; + engine->fifo.enable = nv04_fifo_enable; + engine->fifo.reassign = nv04_fifo_reassign; +- engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; + engine->fifo.channel_id = nv10_fifo_channel_id; + engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; @@ -7182,7 +8753,7 @@ index b02a231..989322b 100644 break; case 0x30: engine->instmem.init = nv04_instmem_init; -@@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -181,15 +207,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -7201,7 +8772,14 @@ index b02a231..989322b 100644 engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv30_graph_grclass; engine->graph.init = nv30_graph_init; -@@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -207,13 +232,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.disable = nv04_fifo_disable; + engine->fifo.enable = nv04_fifo_enable; + engine->fifo.reassign = nv04_fifo_reassign; +- engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; + engine->fifo.channel_id = nv10_fifo_channel_id; + engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; @@ -7218,7 +8796,7 @@ index b02a231..989322b 100644 break; case 0x40: case 0x60: -@@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -225,8 +259,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; @@ -7228,7 +8806,14 @@ index b02a231..989322b 100644 engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -251,13 +284,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.disable = nv04_fifo_disable; + engine->fifo.enable = nv04_fifo_enable; + engine->fifo.reassign = nv04_fifo_reassign; +- engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; + engine->fifo.channel_id = nv10_fifo_channel_id; + engine->fifo.create_context = nv40_fifo_create_context; engine->fifo.destroy_context = nv40_fifo_destroy_context; engine->fifo.load_context = nv40_fifo_load_context; engine->fifo.unload_context = nv40_fifo_unload_context; @@ -7245,7 +8830,7 @@ index b02a231..989322b 100644 break; case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ -@@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -271,8 +313,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv50_instmem_clear; engine->instmem.bind = nv50_instmem_bind; engine->instmem.unbind = nv50_instmem_unbind; @@ -7258,7 +8843,7 @@ index b02a231..989322b 100644 engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; engine->timer.init = nv04_timer_init; -@@ -300,6 +348,64 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) +@@ -300,6 +344,64 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.unload_context = nv50_fifo_unload_context; @@ -7323,7 +8908,58 @@ index b02a231..989322b 100644 break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); -@@ -407,11 +513,6 @@ nouveau_card_init(struct drm_device *dev) +@@ -331,16 +433,14 @@ static int + nouveau_card_init_channel(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *gpuobj; ++ struct nouveau_gpuobj *gpuobj = NULL; + int ret; + + ret = nouveau_channel_alloc(dev, &dev_priv->channel, +- (struct drm_file *)-2, +- NvDmaFB, NvDmaTT); ++ (struct drm_file *)-2, NvDmaFB, NvDmaTT); + if (ret) + return ret; + +- gpuobj = NULL; + ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->vram_size, + NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM, +@@ -348,26 +448,25 @@ nouveau_card_init_channel(struct drm_device *dev) + if (ret) + goto out_err; + +- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM, +- gpuobj, NULL); ++ ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + if (ret) + goto out_err; + +- gpuobj = NULL; + ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0, + dev_priv->gart_info.aper_size, + NV_DMA_ACCESS_RW, &gpuobj, NULL); + if (ret) + goto out_err; + +- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART, +- gpuobj, NULL); ++ ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); + if (ret) + goto out_err; + + return 0; ++ + out_err: +- nouveau_gpuobj_del(dev, &gpuobj); + nouveau_channel_free(dev_priv->channel); + dev_priv->channel = NULL; + return ret; +@@ -407,11 +506,6 @@ nouveau_card_init(struct drm_device *dev) struct nouveau_engine *engine; int ret; @@ -7335,7 +8971,7 @@ index b02a231..989322b 100644 vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, nouveau_switcheroo_can_switch); -@@ -421,15 +522,17 @@ nouveau_card_init(struct drm_device *dev) +@@ -421,50 +515,48 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out; engine = &dev_priv->engine; @@ -7357,17 +8993,47 @@ index b02a231..989322b 100644 + if (ret) + goto out_display_early; - ret = nouveau_mem_detect(dev); +- ret = nouveau_mem_detect(dev); ++ ret = nouveau_mem_vram_init(dev); if (ret) -@@ -461,10 +564,15 @@ nouveau_card_init(struct drm_device *dev) - if (ret) - goto out_gpuobj; + goto out_bios; +- ret = nouveau_gpuobj_early_init(dev); ++ ret = nouveau_gpuobj_init(dev); + if (ret) +- goto out_bios; ++ goto out_vram; + +- /* Initialise instance memory, must happen before mem_init so we +- * know exactly how much VRAM we're able to use for "normal" +- * purposes. +- */ + ret = engine->instmem.init(dev); + if (ret) +- goto out_gpuobj_early; ++ goto out_gpuobj; + +- /* Setup the memory manager */ +- ret = nouveau_mem_init(dev); ++ ret = nouveau_mem_gart_init(dev); + if (ret) + goto out_instmem; + +- ret = nouveau_gpuobj_init(dev); +- if (ret) +- goto out_mem; +- + /* PMC */ + ret = engine->mc.init(dev); + if (ret) +- goto out_gpuobj; ++ goto out_gart; ++ + /* PGPIO */ + ret = engine->gpio.init(dev); + if (ret) + goto out_mc; -+ + /* PTIMER */ ret = engine->timer.init(dev); if (ret) @@ -7376,7 +9042,7 @@ index b02a231..989322b 100644 /* PFB */ ret = engine->fb.init(dev); -@@ -485,12 +593,16 @@ nouveau_card_init(struct drm_device *dev) +@@ -485,12 +577,16 @@ nouveau_card_init(struct drm_device *dev) goto out_graph; } @@ -7394,7 +9060,7 @@ index b02a231..989322b 100644 ret = drm_vblank_init(dev, 0); if (ret) -@@ -504,35 +616,18 @@ nouveau_card_init(struct drm_device *dev) +@@ -504,35 +600,18 @@ nouveau_card_init(struct drm_device *dev) goto out_irq; } @@ -7434,7 +9100,7 @@ index b02a231..989322b 100644 out_fifo: if (!nouveau_noaccel) engine->fifo.takedown(dev); -@@ -543,6 +638,8 @@ out_fb: +@@ -543,19 +622,22 @@ out_fb: engine->fb.takedown(dev); out_timer: engine->timer.takedown(dev); @@ -7442,9 +9108,21 @@ index b02a231..989322b 100644 + engine->gpio.takedown(dev); out_mc: engine->mc.takedown(dev); - out_gpuobj: -@@ -556,6 +653,8 @@ out_gpuobj_early: - nouveau_gpuobj_late_takedown(dev); +-out_gpuobj: +- nouveau_gpuobj_takedown(dev); +-out_mem: +- nouveau_sgdma_takedown(dev); +- nouveau_mem_close(dev); ++out_gart: ++ nouveau_mem_gart_fini(dev); + out_instmem: + engine->instmem.takedown(dev); +-out_gpuobj_early: +- nouveau_gpuobj_late_takedown(dev); ++out_gpuobj: ++ nouveau_gpuobj_takedown(dev); ++out_vram: ++ nouveau_mem_vram_fini(dev); out_bios: nouveau_bios_takedown(dev); +out_display_early: @@ -7452,22 +9130,22 @@ index b02a231..989322b 100644 out: vga_client_register(dev->pdev, NULL, NULL, NULL); return ret; -@@ -566,45 +665,39 @@ static void nouveau_card_takedown(struct drm_device *dev) +@@ -566,45 +648,38 @@ static void nouveau_card_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; - NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); - - if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { -- ++ nouveau_backlight_exit(dev); + - nouveau_backlight_exit(dev); - - if (dev_priv->channel) { - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; - } -+ nouveau_backlight_exit(dev); - +- - if (!nouveau_noaccel) { - engine->fifo.takedown(dev); - engine->graph.takedown(dev); @@ -7502,20 +9180,19 @@ index b02a231..989322b 100644 + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); + mutex_unlock(&dev->struct_mutex); -+ nouveau_sgdma_takedown(dev); ++ nouveau_mem_gart_fini(dev); - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_irq_uninstall(dev); -+ nouveau_gpuobj_takedown(dev); -+ nouveau_mem_close(dev); + engine->instmem.takedown(dev); ++ nouveau_gpuobj_takedown(dev); ++ nouveau_mem_vram_fini(dev); - nouveau_gpuobj_late_takedown(dev); - nouveau_bios_takedown(dev); + drm_irq_uninstall(dev); - vga_client_register(dev->pdev, NULL, NULL, NULL); -+ nouveau_gpuobj_late_takedown(dev); + nouveau_bios_takedown(dev); - dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; @@ -7524,7 +9201,7 @@ index b02a231..989322b 100644 } /* here a client dies, release the stuff that was allocated for its -@@ -691,22 +784,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -691,22 +766,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) struct drm_nouveau_private *dev_priv; uint32_t reg0; resource_size_t mmio_start_offs; @@ -7556,7 +9233,7 @@ index b02a231..989322b 100644 /* resource 0 is mmio regs */ /* resource 1 is linear FB */ -@@ -719,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -719,7 +798,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) if (!dev_priv->mmio) { NV_ERROR(dev, "Unable to initialize the mmio mapping. " "Please report your setup to " DRIVER_EMAIL "\n"); @@ -7566,7 +9243,7 @@ index b02a231..989322b 100644 } NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", (unsigned long long)mmio_start_offs); -@@ -765,19 +863,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -765,19 +845,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) case 0xa0: dev_priv->card_type = NV_50; break; @@ -7594,7 +9271,7 @@ index b02a231..989322b 100644 /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ if (dev_priv->card_type >= NV_40) { -@@ -791,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -791,7 +873,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to PRAMIN BAR"); @@ -7604,7 +9281,7 @@ index b02a231..989322b 100644 } } else { dev_priv->ramin_size = 1 * 1024 * 1024; -@@ -799,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -799,7 +882,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); @@ -7614,7 +9291,7 @@ index b02a231..989322b 100644 } } -@@ -812,46 +914,38 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) +@@ -812,46 +896,38 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->flags |= NV_NFORCE2; /* For kernel modesetting, init card now and bring up fbcon */ @@ -7680,7 +9357,7 @@ index b02a231..989322b 100644 iounmap(dev_priv->mmio); iounmap(dev_priv->ramin); -@@ -867,8 +961,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, +@@ -867,8 +943,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_getparam *getparam = data; @@ -7689,7 +9366,7 @@ index b02a231..989322b 100644 switch (getparam->param) { case NOUVEAU_GETPARAM_CHIPSET_ID: getparam->value = dev_priv->chipset; -@@ -937,8 +1029,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, +@@ -937,8 +1011,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, { struct drm_nouveau_setparam *setparam = data; @@ -7698,6 +9375,15 @@ index b02a231..989322b 100644 switch (setparam->param) { default: NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); +@@ -967,7 +1039,7 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout, + /* Waits for PGRAPH to go completely idle */ + bool nouveau_wait_for_idle(struct drm_device *dev) + { +- if (!nv_wait(NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) { ++ if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) { + NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n", + nv_rd32(dev, NV04_PGRAPH_STATUS)); + return false; diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index eba687f..291a4cb 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -8324,11 +10010,49 @@ index c7898b4..9e28cf7 100644 + return 0; } +diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c +index 1eeac4f..33e4c93 100644 +--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c ++++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c +@@ -25,6 +25,7 @@ + #include "drmP.h" + #include "nouveau_drv.h" + #include "nouveau_dma.h" ++#include "nouveau_ramht.h" + #include "nouveau_fbcon.h" + + void +@@ -169,11 +170,9 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) + if (ret) + return ret; + +- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, handle, obj, NULL); +- if (ret) +- return ret; +- +- return 0; ++ ret = nouveau_ramht_insert(dev_priv->channel, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; + } + + int diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c -index 66fe559..bbb87ef 100644 +index 66fe559..708293b 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c -@@ -38,10 +38,10 @@ +@@ -27,8 +27,9 @@ + #include "drmP.h" + #include "drm.h" + #include "nouveau_drv.h" ++#include "nouveau_ramht.h" + +-#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE)) ++#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE)) + #define NV04_RAMFC__SIZE 32 + #define NV04_RAMFC_DMA_PUT 0x00 + #define NV04_RAMFC_DMA_GET 0x04 +@@ -38,10 +39,8 @@ #define NV04_RAMFC_ENGINE 0x14 #define NV04_RAMFC_PULL1_ENGINE 0x18 @@ -8336,14 +10060,70 @@ index 66fe559..bbb87ef 100644 - NV04_RAMFC_##offset/4, (val)) -#define RAMFC_RD(offset) nv_ro32(dev, chan->ramfc->gpuobj, \ - NV04_RAMFC_##offset/4) -+#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc->gpuobj, \ -+ NV04_RAMFC_##offset, (val)) -+#define RAMFC_RD(offset) nv_ro32(chan->ramfc->gpuobj, \ -+ NV04_RAMFC_##offset) ++#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val)) ++#define RAMFC_RD(offset) nv_ro32(chan->ramfc, NV04_RAMFC_##offset) void nv04_fifo_disable(struct drm_device *dev) -@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev) +@@ -72,37 +71,32 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable) + } + + bool +-nv04_fifo_cache_flush(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; +- uint64_t start = ptimer->read(dev); +- +- do { +- if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) == +- nv_rd32(dev, NV03_PFIFO_CACHE1_PUT)) +- return true; +- +- } while (ptimer->read(dev) - start < 100000000); +- +- NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n"); +- +- return false; +-} +- +-bool + nv04_fifo_cache_pull(struct drm_device *dev, bool enable) + { +- uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0); ++ int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable); ++ ++ if (!enable) { ++ /* In some cases the PFIFO puller may be left in an ++ * inconsistent state if you try to stop it when it's ++ * busy translating handles. Sometimes you get a ++ * PFIFO_CACHE_ERROR, sometimes it just fails silently ++ * sending incorrect instance offsets to PGRAPH after ++ * it's started up again. To avoid the latter we ++ * invalidate the most recently calculated instance. ++ */ ++ if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0, ++ NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0)) ++ NV_ERROR(dev, "Timeout idling the PFIFO puller.\n"); ++ ++ if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) & ++ NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) ++ nv_wr32(dev, NV03_PFIFO_INTR_0, ++ NV_PFIFO_INTR_CACHE_ERROR); + +- if (enable) { +- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1); +- } else { +- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1); + nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + } + +- return !!(pull & 1); ++ return pull & 1; + } + + int +@@ -112,6 +106,12 @@ nv04_fifo_channel_id(struct drm_device *dev) NV03_PFIFO_CACHE1_PUSH1_CHID_MASK; } @@ -8356,14 +10136,23 @@ index 66fe559..bbb87ef 100644 int nv04_fifo_create_context(struct nouveau_channel *chan) { -@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan) +@@ -124,25 +124,20 @@ nv04_fifo_create_context(struct nouveau_channel *chan) + NV04_RAMFC__SIZE, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, +- NULL, &chan->ramfc); ++ &chan->ramfc); + if (ret) + return ret; + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); /* Setup initial state */ - dev_priv->engine.instmem.prepare_access(dev, true); RAMFC_WR(DMA_PUT, chan->pushbuf_base); RAMFC_WR(DMA_GET, chan->pushbuf_base); - RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4); +- RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4); ++ RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4); RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | @@ -8376,7 +10165,16 @@ index 66fe559..bbb87ef 100644 /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, -@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) +@@ -160,7 +155,7 @@ nv04_fifo_destroy_context(struct nouveau_channel *chan) + nv_wr32(dev, NV04_PFIFO_MODE, + nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); + +- nouveau_gpuobj_ref_del(dev, &chan->ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->ramfc); + } + + static void +@@ -169,8 +164,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV04_RAMFC(chid), tmp; @@ -8385,7 +10183,7 @@ index 66fe559..bbb87ef 100644 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); tmp = nv_ri32(dev, fc + 8); -@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) +@@ -181,8 +174,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20)); nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24)); @@ -8394,7 +10192,7 @@ index 66fe559..bbb87ef 100644 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); } -@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev) +@@ -223,7 +214,6 @@ nv04_fifo_unload_context(struct drm_device *dev) return -EINVAL; } @@ -8402,7 +10200,7 @@ index 66fe559..bbb87ef 100644 RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16; -@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev) +@@ -233,7 +223,6 @@ nv04_fifo_unload_context(struct drm_device *dev) RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH)); RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE)); RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1)); @@ -8410,7 +10208,22 @@ index 66fe559..bbb87ef 100644 nv04_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); -@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev) +@@ -269,10 +258,10 @@ nv04_fifo_init_ramxx(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | +- ((dev_priv->ramht_bits - 9) << 16) | +- (dev_priv->ramht_offset >> 8)); +- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8); +- nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8); ++ ((dev_priv->ramht->bits - 9) << 16) | ++ (dev_priv->ramht->gpuobj->pinst >> 8)); ++ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8); ++ nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8); + } + + static void +@@ -297,6 +286,7 @@ nv04_fifo_init(struct drm_device *dev) nv04_fifo_init_intr(dev); pfifo->enable(dev); @@ -8442,30 +10255,158 @@ index 618355e..c897342 100644 } diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c -index a3b9563..4408232 100644 +index a3b9563..0b5ae29 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c -@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev) - NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10); +@@ -1,6 +1,7 @@ + #include "drmP.h" + #include "drm.h" + #include "nouveau_drv.h" ++#include "nouveau_ramht.h" - /* Clear all of it, except the BIOS image that's in the first 64KiB */ -- dev_priv->engine.instmem.prepare_access(dev, true); - for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4) - nv_wi32(dev, i, 0x00000000); -- dev_priv->engine.instmem.finish_access(dev); + /* returns the size of fifo context */ + static int +@@ -17,104 +18,51 @@ nouveau_fifo_ctx_size(struct drm_device *dev) + return 32; } - static void -@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev) +-static void +-nv04_instmem_determine_amount(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int i; +- +- /* Figure out how much instance memory we need */ +- if (dev_priv->card_type >= NV_40) { +- /* We'll want more instance memory than this on some NV4x cards. +- * There's a 16MB aperture to play with that maps onto the end +- * of vram. For now, only reserve a small piece until we know +- * more about what each chipset requires. +- */ +- switch (dev_priv->chipset) { +- case 0x40: +- case 0x47: +- case 0x49: +- case 0x4b: +- dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); +- break; +- default: +- dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); +- break; +- } +- } else { +- /*XXX: what *are* the limits on ramin_rsvd_vram = (512 * 1024); +- } +- NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10); +- +- /* Clear all of it, except the BIOS image that's in the first 64KiB */ +- dev_priv->engine.instmem.prepare_access(dev, true); +- for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4) +- nv_wi32(dev, i, 0x00000000); +- dev_priv->engine.instmem.finish_access(dev); +-} +- +-static void +-nv04_instmem_configure_fixed_tables(struct drm_device *dev) ++int nv04_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t offset; -- int ret = 0; +- struct nouveau_engine *engine = &dev_priv->engine; +- +- /* FIFO hash table (RAMHT) +- * use 4k hash table at RAMIN+0x10000 +- * TODO: extend the hash table +- */ +- dev_priv->ramht_offset = 0x10000; +- dev_priv->ramht_bits = 9; +- dev_priv->ramht_size = (1 << dev_priv->ramht_bits); /* nr entries */ +- dev_priv->ramht_size *= 8; /* 2 32-bit values per entry in RAMHT */ +- NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset, +- dev_priv->ramht_size); +- +- /* FIFO runout table (RAMRO) - 512k at 0x11200 */ +- dev_priv->ramro_offset = 0x11200; +- dev_priv->ramro_size = 512; +- NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset, +- dev_priv->ramro_size); +- +- /* FIFO context table (RAMFC) +- * NV40 : Not sure exactly how to position RAMFC on some cards, +- * 0x30002 seems to position it at RAMIN+0x20000 on these +- * cards. RAMFC is 4kb (32 fifos, 128byte entries). +- * Others: Position RAMFC at RAMIN+0x11400 +- */ +- dev_priv->ramfc_size = engine->fifo.channels * +- nouveau_fifo_ctx_size(dev); ++ struct nouveau_gpuobj *ramht = NULL; ++ u32 offset, length; + int ret; ++ ++ /* RAMIN always available */ ++ dev_priv->ramin_available = true; ++ ++ /* Setup shared RAMHT */ ++ ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096, ++ NVOBJ_FLAG_ZERO_ALLOC, &ramht); ++ if (ret) ++ return ret; ++ ++ ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht); ++ nouveau_gpuobj_ref(NULL, &ramht); ++ if (ret) ++ return ret; ++ ++ /* And RAMRO */ ++ ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512, ++ NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro); ++ if (ret) ++ return ret; ++ ++ /* And RAMFC */ ++ length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev); + switch (dev_priv->card_type) { + case NV_40: +- dev_priv->ramfc_offset = 0x20000; ++ offset = 0x20000; + break; +- case NV_30: +- case NV_20: +- case NV_10: +- case NV_04: + default: +- dev_priv->ramfc_offset = 0x11400; ++ offset = 0x11400; + break; + } +- NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset, +- dev_priv->ramfc_size); +-} - nv04_instmem_determine_amount(dev); - nv04_instmem_configure_fixed_tables(dev); -@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev) +-int nv04_instmem_init(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t offset; +- int ret = 0; ++ ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length, ++ NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc); ++ if (ret) ++ return ret; + +- nv04_instmem_determine_amount(dev); +- nv04_instmem_configure_fixed_tables(dev); +- +- /* Create a heap to manage RAMIN allocations, we don't allocate +- * the space that was reserved for RAMHT/FC/RO. +- */ +- offset = dev_priv->ramfc_offset + dev_priv->ramfc_size; ++ /* Only allow space after RAMFC to be used for object allocation */ ++ offset += length; + + /* It appears RAMRO (or something?) is controlled by 0x2220/0x2230 + * on certain NV4x chipsets as well as RAMFC. When 0x2230 == 0 +@@ -129,69 +77,52 @@ int nv04_instmem_init(struct drm_device *dev) offset = 0x40000; } @@ -8485,7 +10426,56 @@ index a3b9563..4408232 100644 } void -@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + nv04_instmem_takedown(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL); ++ nouveau_gpuobj_ref(NULL, &dev_priv->ramro); ++ nouveau_gpuobj_ref(NULL, &dev_priv->ramfc); + } + + int +-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz) ++nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, ++ uint32_t *sz) + { +- if (gpuobj->im_backing) +- return -EINVAL; +- + return 0; + } + + void + nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (gpuobj && gpuobj->im_backing) { +- if (gpuobj->im_bound) +- dev_priv->engine.instmem.unbind(dev, gpuobj); +- gpuobj->im_backing = NULL; +- } + } + + int + nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + { +- if (!gpuobj->im_pramin || gpuobj->im_bound) +- return -EINVAL; +- +- gpuobj->im_bound = 1; + return 0; + } + + int + nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + { +- if (gpuobj->im_bound == 0) +- return -EINVAL; +- +- gpuobj->im_bound = 0; + return 0; } void @@ -8734,18 +10724,41 @@ index c4e3404..0b5d012 100644 return ret; } diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c -index 7aeabf2..7a4069c 100644 +index 7aeabf2..f1b03ad 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c -@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) +@@ -27,8 +27,9 @@ + #include "drmP.h" + #include "drm.h" + #include "nouveau_drv.h" ++#include "nouveau_ramht.h" + +-#define NV10_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE)) ++#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE)) + #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32) + + int +@@ -48,17 +49,16 @@ nv10_fifo_create_context(struct nouveau_channel *chan) + + ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0, + NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc); ++ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc); + if (ret) + return ret; + /* Fill entries that are seen filled in dumps of nvidia driver just * after channel's is put into DMA mode */ - dev_priv->engine.instmem.prepare_access(dev, true); nv_wi32(dev, fc + 0, chan->pushbuf_base); nv_wi32(dev, fc + 4, chan->pushbuf_base); - nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); -@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) +- nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); ++ nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4); + nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | +@@ -66,7 +66,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) NV_PFIFO_CACHE1_BIG_ENDIAN | #endif 0); @@ -8753,7 +10766,16 @@ index 7aeabf2..7a4069c 100644 /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, -@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) +@@ -82,7 +81,7 @@ nv10_fifo_destroy_context(struct nouveau_channel *chan) + nv_wr32(dev, NV04_PFIFO_MODE, + nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); + +- nouveau_gpuobj_ref_del(dev, &chan->ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->ramfc); + } + + static void +@@ -91,8 +90,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV10_RAMFC(chid), tmp; @@ -8762,7 +10784,7 @@ index 7aeabf2..7a4069c 100644 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8)); -@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) +@@ -117,8 +114,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48)); out: @@ -8771,7 +10793,7 @@ index 7aeabf2..7a4069c 100644 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); } -@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev) +@@ -155,8 +150,6 @@ nv10_fifo_unload_context(struct drm_device *dev) return 0; fc = NV10_RAMFC(chid); @@ -8780,7 +10802,7 @@ index 7aeabf2..7a4069c 100644 nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT)); -@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev) +@@ -179,8 +172,6 @@ nv10_fifo_unload_context(struct drm_device *dev) nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); out: @@ -8789,6 +10811,26 @@ index 7aeabf2..7a4069c 100644 nv10_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); return 0; +@@ -212,14 +203,14 @@ nv10_fifo_init_ramxx(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | +- ((dev_priv->ramht_bits - 9) << 16) | +- (dev_priv->ramht_offset >> 8)); +- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8); ++ ((dev_priv->ramht->bits - 9) << 16) | ++ (dev_priv->ramht->gpuobj->pinst >> 8)); ++ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8); + + if (dev_priv->chipset < 0x17) { +- nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8); ++ nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8); + } else { +- nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc_offset >> 8) | ++ nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) | + (1 << 16) /* 64 Bytes entry*/); + /* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */ + } diff --git a/drivers/gpu/drm/nouveau/nv10_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c new file mode 100644 index 0000000..007fc29 @@ -9193,7 +11235,7 @@ index 2e58c33..0000000 - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c -index 74c8803..703c188 100644 +index 74c8803..a3b8861 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) @@ -9297,7 +11339,149 @@ index 74c8803..703c188 100644 NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; -@@ -296,6 +326,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, +@@ -163,55 +193,56 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) + } + } + +-static const struct { +- int hdisplay; +- int vdisplay; +-} modes[] = { +- { 640, 400 }, +- { 640, 480 }, +- { 720, 480 }, +- { 720, 576 }, +- { 800, 600 }, +- { 1024, 768 }, +- { 1280, 720 }, +- { 1280, 1024 }, +- { 1920, 1080 } +-}; +- +-static int nv17_tv_get_modes(struct drm_encoder *encoder, +- struct drm_connector *connector) ++static int nv17_tv_get_ld_modes(struct drm_encoder *encoder, ++ struct drm_connector *connector) + { + struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); +- struct drm_display_mode *mode; +- struct drm_display_mode *output_mode; ++ struct drm_display_mode *mode, *tv_mode; + int n = 0; +- int i; + +- if (tv_norm->kind != CTV_ENC_MODE) { +- struct drm_display_mode *tv_mode; ++ for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) { ++ mode = drm_mode_duplicate(encoder->dev, tv_mode); + +- for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) { +- mode = drm_mode_duplicate(encoder->dev, tv_mode); ++ mode->clock = tv_norm->tv_enc_mode.vrefresh * ++ mode->htotal / 1000 * ++ mode->vtotal / 1000; + +- mode->clock = tv_norm->tv_enc_mode.vrefresh * +- mode->htotal / 1000 * +- mode->vtotal / 1000; +- +- if (mode->flags & DRM_MODE_FLAG_DBLSCAN) +- mode->clock *= 2; ++ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) ++ mode->clock *= 2; + +- if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay && +- mode->vdisplay == tv_norm->tv_enc_mode.vdisplay) +- mode->type |= DRM_MODE_TYPE_PREFERRED; ++ if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay && ++ mode->vdisplay == tv_norm->tv_enc_mode.vdisplay) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; + +- drm_mode_probed_add(connector, mode); +- n++; +- } +- return n; ++ drm_mode_probed_add(connector, mode); ++ n++; + } + +- /* tv_norm->kind == CTV_ENC_MODE */ +- output_mode = &tv_norm->ctv_enc_mode.mode; ++ return n; ++} ++ ++static int nv17_tv_get_hd_modes(struct drm_encoder *encoder, ++ struct drm_connector *connector) ++{ ++ struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); ++ struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode; ++ struct drm_display_mode *mode; ++ const struct { ++ int hdisplay; ++ int vdisplay; ++ } modes[] = { ++ { 640, 400 }, ++ { 640, 480 }, ++ { 720, 480 }, ++ { 720, 576 }, ++ { 800, 600 }, ++ { 1024, 768 }, ++ { 1280, 720 }, ++ { 1280, 1024 }, ++ { 1920, 1080 } ++ }; ++ int i, n = 0; ++ + for (i = 0; i < ARRAY_SIZE(modes); i++) { + if (modes[i].hdisplay > output_mode->hdisplay || + modes[i].vdisplay > output_mode->vdisplay) +@@ -221,11 +252,12 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder, + modes[i].vdisplay == output_mode->vdisplay) { + mode = drm_mode_duplicate(encoder->dev, output_mode); + mode->type |= DRM_MODE_TYPE_PREFERRED; ++ + } else { + mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay, +- modes[i].vdisplay, 60, false, +- output_mode->flags & DRM_MODE_FLAG_INTERLACE, +- false); ++ modes[i].vdisplay, 60, false, ++ (output_mode->flags & ++ DRM_MODE_FLAG_INTERLACE), false); + } + + /* CVT modes are sometimes unsuitable... */ +@@ -236,6 +268,7 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder, + - mode->hdisplay) * 9 / 10) & ~7; + mode->hsync_end = mode->hsync_start + 8; + } ++ + if (output_mode->vdisplay >= 1024) { + mode->vtotal = output_mode->vtotal; + mode->vsync_start = output_mode->vsync_start; +@@ -246,9 +279,21 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder, + drm_mode_probed_add(connector, mode); + n++; + } ++ + return n; + } + ++static int nv17_tv_get_modes(struct drm_encoder *encoder, ++ struct drm_connector *connector) ++{ ++ struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); ++ ++ if (tv_norm->kind == CTV_ENC_MODE) ++ return nv17_tv_get_hd_modes(encoder, connector); ++ else ++ return nv17_tv_get_ld_modes(encoder, connector); ++} ++ + static int nv17_tv_mode_valid(struct drm_encoder *encoder, + struct drm_display_mode *mode) + { +@@ -296,6 +341,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, { struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); @@ -9307,7 +11491,7 @@ index 74c8803..703c188 100644 if (tv_norm->kind == CTV_ENC_MODE) adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock; else -@@ -307,6 +340,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, +@@ -307,6 +355,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -9316,7 +11500,7 @@ index 74c8803..703c188 100644 struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); -@@ -331,8 +366,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) +@@ -331,8 +381,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) nv_load_ptv(dev, regs, 200); @@ -9327,7 +11511,7 @@ index 74c8803..703c188 100644 nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } -@@ -373,15 +408,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) +@@ -373,15 +423,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) } @@ -9347,7 +11531,7 @@ index 74c8803..703c188 100644 /* Set the DACCLK register */ dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1; -@@ -744,8 +774,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { +@@ -744,8 +789,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { .destroy = nv17_tv_destroy, }; @@ -9359,7 +11543,7 @@ index 74c8803..703c188 100644 struct drm_encoder *encoder; struct nv17_tv_encoder *tv_enc = NULL; -@@ -774,5 +806,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -774,5 +821,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -9367,8 +11551,142 @@ index 74c8803..703c188 100644 + drm_mode_connector_attach_encoder(connector, encoder); return 0; } +diff --git a/drivers/gpu/drm/nouveau/nv17_tv.h b/drivers/gpu/drm/nouveau/nv17_tv.h +index c00977c..6bf0384 100644 +--- a/drivers/gpu/drm/nouveau/nv17_tv.h ++++ b/drivers/gpu/drm/nouveau/nv17_tv.h +@@ -127,7 +127,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder); + + /* TV hardware access functions */ + +-static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val) ++static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, ++ uint32_t val) + { + nv_wr32(dev, reg, val); + } +@@ -137,7 +138,8 @@ static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg) + return nv_rd32(dev, reg); + } + +-static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, uint8_t val) ++static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, ++ uint8_t val) + { + nv_write_ptv(dev, NV_PTV_TV_INDEX, reg); + nv_write_ptv(dev, NV_PTV_TV_DATA, val); +@@ -149,8 +151,11 @@ static inline uint8_t nv_read_tv_enc(struct drm_device *dev, uint8_t reg) + return nv_read_ptv(dev, NV_PTV_TV_DATA); + } + +-#define nv_load_ptv(dev, state, reg) nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg) +-#define nv_save_ptv(dev, state, reg) state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg) +-#define nv_load_tv_enc(dev, state, reg) nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg]) ++#define nv_load_ptv(dev, state, reg) \ ++ nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg) ++#define nv_save_ptv(dev, state, reg) \ ++ state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg) ++#define nv_load_tv_enc(dev, state, reg) \ ++ nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg]) + + #endif +diff --git a/drivers/gpu/drm/nouveau/nv17_tv_modes.c b/drivers/gpu/drm/nouveau/nv17_tv_modes.c +index d64683d..9d3893c 100644 +--- a/drivers/gpu/drm/nouveau/nv17_tv_modes.c ++++ b/drivers/gpu/drm/nouveau/nv17_tv_modes.c +@@ -336,12 +336,17 @@ static void tv_setup_filter(struct drm_encoder *encoder) + struct filter_params *p = &fparams[k][j]; + + for (i = 0; i < 7; i++) { +- int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + p->ki3*i*i*i) +- + (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k] +- + (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker +- + (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k]; +- +- (*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9); ++ int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + ++ p->ki3*i*i*i) ++ + (p->kr + p->kir*i + p->ki2r*i*i + ++ p->ki3r*i*i*i) * rs[k] ++ + (p->kf + p->kif*i + p->ki2f*i*i + ++ p->ki3f*i*i*i) * flicker ++ + (p->krf + p->kirf*i + p->ki2rf*i*i + ++ p->ki3rf*i*i*i) * flicker * rs[k]; ++ ++ (*filters[k])[j][i] = (c + id5/2) >> 39 ++ & (0x1 << 31 | 0x7f << 9); + } + } + } +@@ -349,7 +354,8 @@ static void tv_setup_filter(struct drm_encoder *encoder) + + /* Hardware state saving/restoring */ + +-static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7]) ++static void tv_save_filter(struct drm_device *dev, uint32_t base, ++ uint32_t regs[4][7]) + { + int i, j; + uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c }; +@@ -360,7 +366,8 @@ static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[ + } + } + +-static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7]) ++static void tv_load_filter(struct drm_device *dev, uint32_t base, ++ uint32_t regs[4][7]) + { + int i, j; + uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c }; +@@ -504,10 +511,10 @@ void nv17_tv_update_properties(struct drm_encoder *encoder) + break; + } + +- regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255, +- tv_enc->saturation); +- regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255, +- tv_enc->saturation); ++ regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], ++ 255, tv_enc->saturation); ++ regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], ++ 255, tv_enc->saturation); + regs->tv_enc[0x25] = tv_enc->hue * 255 / 100; + + nv_load_ptv(dev, regs, 204); +@@ -541,7 +548,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder) + int head = nouveau_crtc(encoder->crtc)->index; + struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head]; + struct drm_display_mode *crtc_mode = &encoder->crtc->mode; +- struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode; ++ struct drm_display_mode *output_mode = ++ &get_tv_norm(encoder)->ctv_enc_mode.mode; + int overscan, hmargin, vmargin, hratio, vratio; + + /* The rescaler doesn't do the right thing for interlaced modes. */ +@@ -553,13 +561,15 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder) + hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2; + vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2; + +- hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin, +- overscan); +- vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin, +- overscan); ++ hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), ++ hmargin, overscan); ++ vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), ++ vmargin, overscan); + +- hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin); +- vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3; ++ hratio = crtc_mode->hdisplay * 0x800 / ++ (output_mode->hdisplay - 2*hmargin); ++ vratio = crtc_mode->vdisplay * 0x800 / ++ (output_mode->vdisplay - 2*vmargin) & ~3; + + regs->fp_horiz_regs[FP_VALID_START] = hmargin; + regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1; diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c -index d6fc0a8..cc876ef 100644 +index d6fc0a8..93f0d8a 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -37,49 +37,49 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) @@ -9935,7 +12253,7 @@ index d6fc0a8..cc876ef 100644 } int -@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan) +@@ -370,68 +370,52 @@ nv20_graph_create_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -9989,48 +12307,66 @@ index d6fc0a8..cc876ef 100644 - ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, - NVOBJ_FLAG_ZERO_ALLOC, - &chan->ramin_grctx); -+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, -+ 16, NVOBJ_FLAG_ZERO_ALLOC, -+ &chan->ramin_grctx); ++ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx); if (ret) return ret; /* Initialise default context values */ - dev_priv->engine.instmem.prepare_access(dev, true); - ctx_init(dev, chan->ramin_grctx->gpuobj); +- ctx_init(dev, chan->ramin_grctx->gpuobj); ++ ctx_init(dev, chan->ramin_grctx); /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ - nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs, - (chan->id << 24) | 0x1); /* CTX_USER */ -+ nv_wo32(chan->ramin_grctx->gpuobj, idoffs, ++ nv_wo32(chan->ramin_grctx, idoffs, + (chan->id << 24) | 0x1); /* CTX_USER */ - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, - chan->ramin_grctx->instance >> 4); - - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4, -+ chan->ramin_grctx->instance >> 4); ++ nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4); return 0; } -@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan) +@@ -440,13 +424,10 @@ nv20_graph_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - if (chan->ramin_grctx) - nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - +- if (chan->ramin_grctx) +- nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); +- - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0); - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4, 0); ++ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); ++ nv_wo32(pgraph->ctx_table, chan->id * 4, 0); } int -@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, +@@ -457,7 +438,7 @@ nv20_graph_load_context(struct nouveau_channel *chan) + + if (!chan->ramin_grctx) + return -EINVAL; +- inst = chan->ramin_grctx->instance >> 4; ++ inst = chan->ramin_grctx->pinst >> 4; + + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, +@@ -480,7 +461,7 @@ nv20_graph_unload_context(struct drm_device *dev) + chan = pgraph->channel(dev); + if (!chan) + return 0; +- inst = chan->ramin_grctx->instance >> 4; ++ inst = chan->ramin_grctx->pinst >> 4; + + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, +@@ -538,29 +519,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, int nv20_graph_init(struct drm_device *dev) { @@ -10069,28 +12405,29 @@ index d6fc0a8..cc876ef 100644 - dev_priv->ctx_table_size = 32 * 4; - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, - dev_priv->ctx_table_size, 16, -+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, +- NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->ctx_table); -+ &pgraph->ctx_table); ++ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pgraph->ctx_table); if (ret) return ret; } nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, - dev_priv->ctx_table->instance >> 4); -+ pgraph->ctx_table->instance >> 4); ++ pgraph->ctx_table->pinst >> 4); nv20_graph_rdi(dev); -@@ -644,34 +644,52 @@ void +@@ -644,34 +640,52 @@ void nv20_graph_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table); -+ nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table); ++ nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); } int @@ -10129,17 +12466,18 @@ index d6fc0a8..cc876ef 100644 - dev_priv->ctx_table_size = 32 * 4; - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, - dev_priv->ctx_table_size, 16, -+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, +- NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->ctx_table); -+ &pgraph->ctx_table); ++ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pgraph->ctx_table); if (ret) return ret; } nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, - dev_priv->ctx_table->instance >> 4); -+ pgraph->ctx_table->instance >> 4); ++ pgraph->ctx_table->pinst >> 4); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -10245,25 +12583,60 @@ index 0000000..4a3f2f0 +{ +} diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c -index 500ccfd..2b67f18 100644 +index 500ccfd..d337b8b 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c -@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) +@@ -27,8 +27,9 @@ + #include "drmP.h" + #include "nouveau_drv.h" + #include "nouveau_drm.h" ++#include "nouveau_ramht.h" + +-#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE)) ++#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE)) + #define NV40_RAMFC__SIZE 128 + + int +@@ -42,16 +43,15 @@ nv40_fifo_create_context(struct nouveau_channel *chan) + + ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0, + NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc); ++ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc); + if (ret) + return ret; spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - dev_priv->engine.instmem.prepare_access(dev, true); nv_wi32(dev, fc + 0, chan->pushbuf_base); nv_wi32(dev, fc + 4, chan->pushbuf_base); - nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); -@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) +- nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); ++ nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4); + nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | +@@ -59,9 +59,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan) + NV_PFIFO_CACHE1_BIG_ENDIAN | + #endif 0x30000000 /* no idea.. */); - nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4); +- nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4); ++ nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4); nv_wi32(dev, fc + 60, 0x0001FFFF); - dev_priv->engine.instmem.finish_access(dev); /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, +@@ -79,8 +78,7 @@ nv40_fifo_destroy_context(struct nouveau_channel *chan) + nv_wr32(dev, NV04_PFIFO_MODE, + nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); + +- if (chan->ramfc) +- nouveau_gpuobj_ref_del(dev, &chan->ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->ramfc); + } + + static void @@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV40_RAMFC(chid), tmp, tmp2; @@ -10298,19 +12671,54 @@ index 500ccfd..2b67f18 100644 nv40_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, +@@ -249,9 +241,9 @@ nv40_fifo_init_ramxx(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | +- ((dev_priv->ramht_bits - 9) << 16) | +- (dev_priv->ramht_offset >> 8)); +- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8); ++ ((dev_priv->ramht->bits - 9) << 16) | ++ (dev_priv->ramht->gpuobj->pinst >> 8)); ++ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8); + + switch (dev_priv->chipset) { + case 0x47: +@@ -279,7 +271,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev) + nv_wr32(dev, 0x2230, 0); + nv_wr32(dev, NV40_PFIFO_RAMFC, + ((dev_priv->vram_size - 512 * 1024 + +- dev_priv->ramfc_offset) >> 16) | (3 << 16)); ++ dev_priv->ramfc->pinst) >> 16) | (3 << 16)); + break; + } + } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c -index 704a25d..f7b59ad 100644 +index 704a25d..2424289 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c -@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) +@@ -45,7 +45,7 @@ nv40_graph_channel(struct drm_device *dev) + struct nouveau_channel *chan = dev_priv->fifos[i]; + + if (chan && chan->ramin_grctx && +- chan->ramin_grctx->instance == inst) ++ chan->ramin_grctx->pinst == inst) + return chan; + } + +@@ -58,36 +58,28 @@ nv40_graph_create_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_grctx ctx = {}; int ret; - ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, -@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan) +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, +- 16, NVOBJ_FLAG_ZERO_ALLOC, +- &chan->ramin_grctx); ++ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx); + if (ret) return ret; /* Initialise default context values */ @@ -10330,15 +12738,31 @@ index 704a25d..f7b59ad 100644 - dev_priv->engine.instmem.finish_access(dev); + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; -+ ctx.data = chan->ramin_grctx->gpuobj; ++ ctx.data = chan->ramin_grctx; + nv40_grctx_init(&ctx); + -+ nv_wo32(chan->ramin_grctx->gpuobj, 0, -+ chan->ramin_grctx->gpuobj->im_pramin->start); ++ nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst); return 0; } -@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev) + void + nv40_graph_destroy_context(struct nouveau_channel *chan) + { +- nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx); ++ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); + } + + static int +@@ -141,7 +133,7 @@ nv40_graph_load_context(struct nouveau_channel *chan) + + if (!chan->ramin_grctx) + return -EINVAL; +- inst = chan->ramin_grctx->instance >> 4; ++ inst = chan->ramin_grctx->pinst >> 4; + + ret = nv40_graph_transfer_context(dev, inst, 0); + if (ret) +@@ -238,7 +230,8 @@ nv40_graph_init(struct drm_device *dev) struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; @@ -10348,7 +12772,7 @@ index 704a25d..f7b59ad 100644 int i, j; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & -@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev) +@@ -246,32 +239,22 @@ nv40_graph_init(struct drm_device *dev) nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); @@ -10394,7 +12818,7 @@ index 704a25d..f7b59ad 100644 /* No context present currently */ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); -@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev) +@@ -407,7 +390,6 @@ nv40_graph_init(struct drm_device *dev) void nv40_graph_takedown(struct drm_device *dev) { @@ -10568,8 +12992,21 @@ index b4e4a3b..2423c92 100644 } static bool +diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c +index 03ad7ab..1b9ce30 100644 +--- a/drivers/gpu/drm/nouveau/nv50_cursor.c ++++ b/drivers/gpu/drm/nouveau/nv50_cursor.c +@@ -147,7 +147,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc) + NV_DEBUG_KMS(dev, "\n"); + + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0); +- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), ++ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { + NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); + NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c -index 1fd9537..1bc0859 100644 +index 1fd9537..875414b 100644 --- a/drivers/gpu/drm/nouveau/nv50_dac.c +++ b/drivers/gpu/drm/nouveau/nv50_dac.c @@ -37,22 +37,31 @@ @@ -10608,6 +13045,24 @@ index 1fd9537..1bc0859 100644 } static enum drm_connector_status +@@ -70,7 +79,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) + + nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), + 0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING); +- if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or), ++ if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), + NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) { + NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or); + NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or, +@@ -121,7 +130,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode) + NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); + + /* wait for it to be done */ +- if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or), ++ if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), + NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) { + NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or); + NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or, @@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, uint32_t mode_ctl = 0, mode_ctl2 = 0; int ret; @@ -10679,10 +13134,33 @@ index 1fd9537..1bc0859 100644 } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c -index 580a5d1..435d2b7 100644 +index 580a5d1..11d366a 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c -@@ -42,6 +42,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan) +@@ -30,8 +30,22 @@ + #include "nouveau_connector.h" + #include "nouveau_fb.h" + #include "nouveau_fbcon.h" ++#include "nouveau_ramht.h" + #include "drm_crtc_helper.h" + ++static inline int ++nv50_sor_nr(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ if (dev_priv->chipset < 0x90 || ++ dev_priv->chipset == 0x92 || ++ dev_priv->chipset == 0xa0) ++ return 2; ++ ++ return 4; ++} ++ + static void + nv50_evo_channel_del(struct nouveau_channel **pchan) + { +@@ -42,6 +56,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan) *pchan = NULL; nouveau_gpuobj_channel_takedown(chan); @@ -10690,7 +13168,26 @@ index 580a5d1..435d2b7 100644 nouveau_bo_ref(NULL, &chan->pushbuf_bo); if (chan->user) -@@ -71,14 +72,16 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, +@@ -65,21 +80,23 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, + return ret; + obj->engine = NVOBJ_ENGINE_DISPLAY; + +- ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL); ++ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); ++ nv_wo32(obj, 4, limit); ++ nv_wo32(obj, 8, offset); ++ nv_wo32(obj, 12, 0x00000000); ++ nv_wo32(obj, 16, 0x00000000); ++ if (dev_priv->card_type < NV_C0) ++ nv_wo32(obj, 20, 0x00010000); ++ else ++ nv_wo32(obj, 20, 0x00020000); ++ dev_priv->engine.instmem.flush(dev); ++ ++ ret = nouveau_ramht_insert(evo, name, obj); ++ nouveau_gpuobj_ref(NULL, &obj); + if (ret) { +- nouveau_gpuobj_del(dev, &obj); return ret; } @@ -10702,31 +13199,63 @@ index 580a5d1..435d2b7 100644 - nv_wo32(dev, obj, 4, 0x00000000); - nv_wo32(dev, obj, 5, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); -+ nv_wo32(obj, 4, limit); -+ nv_wo32(obj, 8, offset); -+ nv_wo32(obj, 12, 0x00000000); -+ nv_wo32(obj, 16, 0x00000000); -+ if (dev_priv->card_type < NV_C0) -+ nv_wo32(obj, 20, 0x00010000); -+ else -+ nv_wo32(obj, 20, 0x00020000); -+ dev_priv->engine.instmem.flush(dev); - +- return 0; } -@@ -110,8 +113,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + +@@ -87,6 +104,7 @@ static int + nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ramht = NULL; + struct nouveau_channel *chan; + int ret; + +@@ -100,32 +118,35 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + chan->user_get = 4; + chan->user_put = 0; + +- INIT_LIST_HEAD(&chan->ramht_refs); +- +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000, +- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); ++ ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, ++ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); + if (ret) { + NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); + nv50_evo_channel_del(pchan); return ret; } - ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj-> - im_pramin->start, 32768); -+ ret = drm_mm_init(&chan->ramin_heap, -+ chan->ramin->gpuobj->im_pramin->start, 32768); ++ ret = drm_mm_init(&chan->ramin_heap, 0, 32768); if (ret) { NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); nv50_evo_channel_del(pchan); -@@ -179,13 +182,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + return ret; + } + +- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16, +- 0, &chan->ramht); ++ ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); + if (ret) { + NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + ++ ret = nouveau_ramht_new(dev, ramht, &chan->ramht); ++ nouveau_gpuobj_ref(NULL, &ramht); ++ if (ret) { ++ nv50_evo_channel_del(pchan); ++ return ret; ++ } ++ + if (dev_priv->chipset != 0x50) { + ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, + 0, 0xffffffff); +@@ -179,13 +200,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) } int @@ -10753,7 +13282,85 @@ index 580a5d1..435d2b7 100644 uint64_t start; int ret, i; -@@ -366,26 +381,13 @@ nv50_display_init(struct drm_device *dev) +@@ -213,11 +246,11 @@ nv50_display_init(struct drm_device *dev) + nv_wr32(dev, 0x006101d0 + (i * 0x04), val); + } + /* SOR */ +- for (i = 0; i < 4; i++) { ++ for (i = 0; i < nv50_sor_nr(dev); i++) { + val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); + nv_wr32(dev, 0x006101e0 + (i * 0x04), val); + } +- /* Something not yet in use, tv-out maybe. */ ++ /* EXT */ + for (i = 0; i < 3; i++) { + val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); + nv_wr32(dev, 0x006101f0 + (i * 0x04), val); +@@ -246,7 +279,7 @@ nv50_display_init(struct drm_device *dev) + if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) { + nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100); + nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1); +- if (!nv_wait(0x006194e8, 2, 0)) { ++ if (!nv_wait(dev, 0x006194e8, 2, 0)) { + NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n"); + NV_ERROR(dev, "0x6194e8 = 0x%08x\n", + nv_rd32(dev, 0x6194e8)); +@@ -277,7 +310,8 @@ nv50_display_init(struct drm_device *dev) + + nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); + nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); +- if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) { ++ if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), ++ 0x40000000, 0x40000000)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); +@@ -286,7 +320,7 @@ nv50_display_init(struct drm_device *dev) + + for (i = 0; i < 2; i++) { + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); +- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), ++ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { + NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); + NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", +@@ -296,7 +330,7 @@ nv50_display_init(struct drm_device *dev) + + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); +- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), ++ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { + NV_ERROR(dev, "timeout: " +@@ -307,7 +341,7 @@ nv50_display_init(struct drm_device *dev) + } + } + +- nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9); ++ nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); + + /* initialise fifo */ + nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), +@@ -316,7 +350,7 @@ nv50_display_init(struct drm_device *dev) + NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); + nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); + nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); +- if (!nv_wait(0x610200, 0x80000000, 0x00000000)) { ++ if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); + return -EBUSY; +@@ -356,7 +390,7 @@ nv50_display_init(struct drm_device *dev) + BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); + OUT_RING(evo, 0); + FIRE_RING(evo); +- if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2)) ++ if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) + NV_ERROR(dev, "evo pushbuf stalled\n"); + + /* enable clock change interrupts. */ +@@ -366,26 +400,13 @@ nv50_display_init(struct drm_device *dev) NV50_PDISPLAY_INTR_EN_CLK_UNK40)); /* enable hotplug interrupts */ @@ -10781,7 +13388,33 @@ index 580a5d1..435d2b7 100644 } return 0; -@@ -465,6 +467,7 @@ int nv50_display_create(struct drm_device *dev) +@@ -423,7 +444,7 @@ static int nv50_display_disable(struct drm_device *dev) + continue; + + nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask); +- if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) { ++ if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) { + NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == " + "0x%08x\n", mask, mask); + NV_ERROR(dev, "0x610024 = 0x%08x\n", +@@ -433,14 +454,14 @@ static int nv50_display_disable(struct drm_device *dev) + + nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); + nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); +- if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { ++ if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); + } + + for (i = 0; i < 3; i++) { +- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i), ++ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i), + NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) { + NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i); + NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i, +@@ -465,6 +486,7 @@ int nv50_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; @@ -10789,7 +13422,7 @@ index 580a5d1..435d2b7 100644 int ret, i; NV_DEBUG_KMS(dev, "\n"); -@@ -507,14 +510,18 @@ int nv50_display_create(struct drm_device *dev) +@@ -507,14 +529,18 @@ int nv50_display_create(struct drm_device *dev) continue; } @@ -10810,7 +13443,7 @@ index 580a5d1..435d2b7 100644 break; default: NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); -@@ -522,11 +529,13 @@ int nv50_display_create(struct drm_device *dev) +@@ -522,11 +548,13 @@ int nv50_display_create(struct drm_device *dev) } } @@ -10829,7 +13462,7 @@ index 580a5d1..435d2b7 100644 } ret = nv50_display_init(dev); -@@ -538,7 +547,8 @@ int nv50_display_create(struct drm_device *dev) +@@ -538,7 +566,8 @@ int nv50_display_create(struct drm_device *dev) return 0; } @@ -10839,7 +13472,7 @@ index 580a5d1..435d2b7 100644 { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -548,135 +558,30 @@ int nv50_display_destroy(struct drm_device *dev) +@@ -548,135 +577,30 @@ int nv50_display_destroy(struct drm_device *dev) nv50_display_disable(dev); nv50_evo_channel_del(&dev_priv->evo); @@ -10982,7 +13615,7 @@ index 580a5d1..435d2b7 100644 case OUTPUT_LVDS: script = (mc >> 8) & 0xf; if (bios->fp_no_ddc) { -@@ -767,17 +672,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) +@@ -767,17 +691,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) static void nv50_display_unk10_handler(struct drm_device *dev) { @@ -11012,7 +13645,7 @@ index 580a5d1..435d2b7 100644 + crtc = ffs((unk30 & 0x00000180) >> 7) - 1; + if (crtc < 0) + goto ack; - ++ + /* Find which encoder was connected to the CRTC */ + for (i = 0; type == OUTPUT_ANY && i < 3; i++) { + mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i)); @@ -11031,7 +13664,7 @@ index 580a5d1..435d2b7 100644 + or = i; + } + -+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) { ++ for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) { + if (dev_priv->chipset < 0x90 || + dev_priv->chipset == 0x92 || + dev_priv->chipset == 0xa0) @@ -11072,12 +13705,12 @@ index 580a5d1..435d2b7 100644 + goto ack; + } + } -+ + + NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); nv_wr32(dev, 0x610030, 0x80000000); -@@ -817,33 +793,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) +@@ -817,33 +812,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) static void nv50_display_unk20_handler(struct drm_device *dev) { @@ -11119,17 +13752,14 @@ index 580a5d1..435d2b7 100644 - pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; - script = nv50_display_script_select(dev, dcbent, pclk); + pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff; - -- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); ++ + /* Find which encoder is connected to the CRTC */ + for (i = 0; type == OUTPUT_ANY && i < 3; i++) { + mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i)); + NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; - -- if (dcbent->type != OUTPUT_DP) -- nouveau_bios_run_display_table(dev, dcbent, 0, -2); ++ + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_ANALOG; break; + case 1: type = OUTPUT_TV; break; @@ -11137,21 +13767,18 @@ index 580a5d1..435d2b7 100644 + NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); + goto ack; + } - -- nv50_crtc_set_clock(dev, head, pclk); ++ + or = i; + } - -- nouveau_bios_run_display_table(dev, dcbent, script, pclk); -+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) { ++ ++ for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) { + if (dev_priv->chipset < 0x90 || + dev_priv->chipset == 0x92 || + dev_priv->chipset == 0xa0) + mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i)); + else + mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i)); - -- nv50_display_unk20_dp_hack(dev, dcbent); ++ + NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; @@ -11167,39 +13794,45 @@ index 580a5d1..435d2b7 100644 + NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc); + goto ack; + } -+ + +- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); + or = i; + } -+ + +- if (dcbent->type != OUTPUT_DP) +- nouveau_bios_run_display_table(dev, dcbent, 0, -2); + if (type == OUTPUT_ANY) + goto ack; -+ + +- nv50_crtc_set_clock(dev, head, pclk); + /* Enable the encoder */ + for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { + dcb = &dev_priv->vbios.dcb.entry[i]; + if (dcb->type == type && (dcb->or & (1 << or))) + break; + } -+ + +- nouveau_bios_run_display_table(dev, dcbent, script, pclk); + if (i == dev_priv->vbios.dcb.entries) { + NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); + goto ack; + } -- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); -- tmp &= ~0x000000f; -- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); +- nv50_display_unk20_dp_hack(dev, dcbent); + script = nv50_display_script_select(dev, dcb, mc, pclk); + nouveau_bios_run_display_table(dev, dcb, script, pclk); -- if (dcbent->type != OUTPUT_ANALOG) { +- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); +- tmp &= ~0x000000f; +- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); + nv50_display_unk20_dp_hack(dev, dcb); -+ + +- if (dcbent->type != OUTPUT_ANALOG) { + if (dcb->type != OUTPUT_ANALOG) { tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); tmp &= ~0x00000f0f; if (script & 0x0100) -@@ -853,24 +899,61 @@ nv50_display_unk20_handler(struct drm_device *dev) +@@ -853,24 +918,61 @@ nv50_display_unk20_handler(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); } @@ -11287,7 +13920,7 @@ index 581d405..c551f0b 100644 int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c -index 32611bd..ad267c5 100644 +index 32611bd..594720b 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -36,3 +36,42 @@ void @@ -11323,7 +13956,7 @@ index 32611bd..ad267c5 100644 + if (!chan || !chan->ramin) + continue; + -+ if (chinst == chan->ramin->instance >> 12) ++ if (chinst == chan->ramin->vinst >> 12) + break; + } + @@ -11333,29 +13966,54 @@ index 32611bd..ad267c5 100644 + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, + trap[0], ch, chinst); +} +diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c +index 6bf025c..6dcf048 100644 +--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c ++++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c +@@ -1,6 +1,7 @@ + #include "drmP.h" + #include "nouveau_drv.h" + #include "nouveau_dma.h" ++#include "nouveau_ramht.h" + #include "nouveau_fbcon.h" + + void +@@ -193,7 +194,8 @@ nv50_fbcon_accel_init(struct fb_info *info) + if (ret) + return ret; + +- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL); ++ ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d); ++ nouveau_gpuobj_ref(NULL, &eng2d); + if (ret) + return ret; + diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c -index e20c0e2..38dbcda 100644 +index e20c0e2..a46a961 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c -@@ -28,41 +28,35 @@ +@@ -27,42 +27,37 @@ + #include "drmP.h" #include "drm.h" #include "nouveau_drv.h" - +- -struct nv50_fifo_priv { - struct nouveau_gpuobj_ref *thingo[2]; - int cur_thingo; -}; - -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) -- ++#include "nouveau_ramht.h" + static void -nv50_fifo_init_thingo(struct drm_device *dev) +nv50_fifo_playlist_update(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv; +- struct nouveau_gpuobj_ref *cur; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; - struct nouveau_gpuobj_ref *cur; ++ struct nouveau_gpuobj *cur; int i, nr; NV_DEBUG(dev, "\n"); @@ -11371,14 +14029,15 @@ index e20c0e2..38dbcda 100644 - if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) - nv_wo32(dev, cur->gpuobj, nr++, i); + if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) { -+ nv_wo32(cur->gpuobj, (nr * 4), i); ++ nv_wo32(cur, (nr * 4), i); + nr++; + } } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); - nv_wr32(dev, 0x32f4, cur->instance >> 12); +- nv_wr32(dev, 0x32f4, cur->instance >> 12); ++ nv_wr32(dev, 0x32f4, cur->vinst >> 12); nv_wr32(dev, 0x32ec, nr); nv_wr32(dev, 0x2500, 0x101); } @@ -11390,7 +14049,7 @@ index e20c0e2..38dbcda 100644 { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->fifos[channel]; -@@ -70,37 +64,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) +@@ -70,37 +65,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) NV_DEBUG(dev, "ch%d\n", channel); @@ -11398,12 +14057,14 @@ index e20c0e2..38dbcda 100644 - return -EINVAL; - - if (IS_G80) +- inst = chan->ramfc->instance >> 12; + if (dev_priv->chipset == 0x50) - inst = chan->ramfc->instance >> 12; ++ inst = chan->ramfc->vinst >> 12; else - inst = chan->ramfc->instance >> 8; +- inst = chan->ramfc->instance >> 8; - nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), - inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); ++ inst = chan->ramfc->vinst >> 8; - if (!nt) - nv50_fifo_init_thingo(dev); @@ -11434,7 +14095,7 @@ index e20c0e2..38dbcda 100644 } static void -@@ -133,12 +118,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) +@@ -133,12 +119,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { if (dev_priv->fifos[i]) @@ -11450,7 +14111,7 @@ index e20c0e2..38dbcda 100644 } static void -@@ -162,41 +147,38 @@ nv50_fifo_init_regs(struct drm_device *dev) +@@ -162,41 +148,38 @@ nv50_fifo_init_regs(struct drm_device *dev) nv_wr32(dev, 0x3270, 0); /* Enable dummy channels setup by nv50_instmem.c */ @@ -11483,28 +14144,30 @@ index e20c0e2..38dbcda 100644 - return -ENOMEM; - dev_priv->engine.fifo.priv = priv; - - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]); -+ NVOBJ_FLAG_ZERO_ALLOC, -+ &pfifo->playlist[0]); ++ ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000, ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pfifo->playlist[0]); if (ret) { - NV_ERROR(dev, "error creating thingo0: %d\n", ret); + NV_ERROR(dev, "error creating playlist 0: %d\n", ret); return ret; } - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]); -+ NVOBJ_FLAG_ZERO_ALLOC, -+ &pfifo->playlist[1]); ++ ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000, ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pfifo->playlist[1]); if (ret) { - NV_ERROR(dev, "error creating thingo1: %d\n", ret); -+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); ++ nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); + NV_ERROR(dev, "error creating playlist 1: %d\n", ret); return ret; } -@@ -216,18 +198,15 @@ void +@@ -216,18 +199,15 @@ void nv50_fifo_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -11522,21 +14185,59 @@ index e20c0e2..38dbcda 100644 - - dev_priv->engine.fifo.priv = NULL; - kfree(priv); -+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); -+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]); ++ nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); ++ nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); } int -@@ -248,7 +227,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) +@@ -248,72 +228,61 @@ nv50_fifo_create_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - if (IS_G80) { +- uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start; +- uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start; +- +- ret = nouveau_gpuobj_new_fake(dev, ramin_poffset, ramin_voffset, +- 0x100, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &ramfc, + if (dev_priv->chipset == 0x50) { - uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start; - uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start; ++ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst, ++ chan->ramin->vinst, 0x100, ++ NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, + &chan->ramfc); + if (ret) + return ret; -@@ -281,39 +260,31 @@ nv50_fifo_create_context(struct nouveau_channel *chan) +- ret = nouveau_gpuobj_new_fake(dev, ramin_poffset + 0x0400, +- ramin_voffset + 0x0400, 4096, +- 0, NULL, &chan->cache); ++ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400, ++ chan->ramin->vinst + 0x0400, ++ 4096, 0, &chan->cache); + if (ret) + return ret; + } else { +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256, +- NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, +- &chan->ramfc); ++ ret = nouveau_gpuobj_new(dev, chan, 0x100, 256, ++ NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc); + if (ret) + return ret; +- ramfc = chan->ramfc->gpuobj; + +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024, +- 0, &chan->cache); ++ ret = nouveau_gpuobj_new(dev, chan, 4096, 1024, ++ 0, &chan->cache); + if (ret) + return ret; + } ++ ramfc = chan->ramfc; spin_lock_irqsave(&dev_priv->context_switch_lock, flags); @@ -11561,10 +14262,10 @@ index e20c0e2..38dbcda 100644 - - nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10); - nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12); -+ nv_wo32(ramfc, 0x48, chan->pushbuf->instance >> 4); -+ nv_wo32(ramfc, 0x80, (0 << 27) /* 4KiB */ | ++ nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4); ++ nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | -+ (chan->ramht->instance >> 4)); ++ (chan->ramht->gpuobj->cinst >> 4)); + nv_wo32(ramfc, 0x44, 0x2101ffff); + nv_wo32(ramfc, 0x60, 0x7fffffff); + nv_wo32(ramfc, 0x40, 0x00000000); @@ -11575,11 +14276,11 @@ index e20c0e2..38dbcda 100644 + nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16); + + if (dev_priv->chipset != 0x50) { -+ nv_wo32(chan->ramin->gpuobj, 0, chan->id); -+ nv_wo32(chan->ramin->gpuobj, 4, chan->ramfc->instance >> 8); ++ nv_wo32(chan->ramin, 0, chan->id); ++ nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8); + -+ nv_wo32(ramfc, 0x88, chan->cache->instance >> 10); -+ nv_wo32(ramfc, 0x98, chan->ramin->instance >> 12); ++ nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10); ++ nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12); } - dev_priv->engine.instmem.finish_access(dev); @@ -11598,11 +14299,20 @@ index e20c0e2..38dbcda 100644 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); return 0; } -@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) +@@ -322,20 +291,22 @@ void + nv50_fifo_destroy_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; +- struct nouveau_gpuobj_ref *ramfc = chan->ramfc; ++ struct nouveau_gpuobj *ramfc = NULL; + + NV_DEBUG(dev, "ch%d\n", chan->id); /* This will ensure the channel is seen as disabled. */ - chan->ramfc = NULL; +- chan->ramfc = NULL; - nv50_fifo_channel_disable(dev, chan->id, false); ++ nouveau_gpuobj_ref(chan->ramfc, &ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->ramfc); + nv50_fifo_channel_disable(dev, chan->id); /* Dummy channel, also used on ch 127 */ @@ -11611,9 +14321,22 @@ index e20c0e2..38dbcda 100644 + nv50_fifo_channel_disable(dev, 127); + nv50_fifo_playlist_update(dev); - nouveau_gpuobj_ref_del(dev, &ramfc); - nouveau_gpuobj_ref_del(dev, &chan->cache); -@@ -349,63 +321,59 @@ nv50_fifo_load_context(struct nouveau_channel *chan) +- nouveau_gpuobj_ref_del(dev, &ramfc); +- nouveau_gpuobj_ref_del(dev, &chan->cache); ++ nouveau_gpuobj_ref(NULL, &ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->cache); + } + + int +@@ -343,69 +314,65 @@ nv50_fifo_load_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj; +- struct nouveau_gpuobj *cache = chan->cache->gpuobj; ++ struct nouveau_gpuobj *ramfc = chan->ramfc; ++ struct nouveau_gpuobj *cache = chan->cache; + int ptr, cnt; NV_DEBUG(dev, "ch%d\n", chan->id); @@ -11720,10 +14443,13 @@ index e20c0e2..38dbcda 100644 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } -@@ -434,64 +402,63 @@ nv50_fifo_unload_context(struct drm_device *dev) - ramfc = chan->ramfc->gpuobj; - cache = chan->cache->gpuobj; - +@@ -431,67 +398,66 @@ nv50_fifo_unload_context(struct drm_device *dev) + return -EINVAL; + } + NV_DEBUG(dev, "ch%d\n", chan->id); +- ramfc = chan->ramfc->gpuobj; +- cache = chan->cache->gpuobj; +- - dev_priv->engine.instmem.prepare_access(dev, true); - - nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330)); @@ -11759,6 +14485,9 @@ index e20c0e2..38dbcda 100644 - nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088)); - nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058)); - nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210)); ++ ramfc = chan->ramfc; ++ cache = chan->cache; ++ + nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330)); + nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334)); + nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240)); @@ -11875,11 +14604,15 @@ index bb47ad7..b2fab2b 100644 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c -index b203d06..17a8d78 100644 +index b203d06..cbf5ae2 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c -@@ -30,8 +30,6 @@ - +@@ -27,11 +27,9 @@ + #include "drmP.h" + #include "drm.h" + #include "nouveau_drv.h" +- ++#include "nouveau_ramht.h" #include "nouveau_grctx.h" -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) @@ -11955,19 +14688,43 @@ index b203d06..17a8d78 100644 } void -@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) +@@ -188,7 +181,7 @@ nv50_graph_channel(struct drm_device *dev) + /* Be sure we're not in the middle of a context switch or bad things + * will happen, such as unloading the wrong pgraph context. + */ +- if (!nv_wait(0x400300, 0x00000001, 0x00000000)) ++ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) + NV_ERROR(dev, "Ctxprog is still running\n"); + + inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); +@@ -199,7 +192,7 @@ nv50_graph_channel(struct drm_device *dev) + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { + struct nouveau_channel *chan = dev_priv->fifos[i]; + +- if (chan && chan->ramin && chan->ramin->instance == inst) ++ if (chan && chan->ramin && chan->ramin->vinst == inst) + return chan; + } + +@@ -211,44 +204,36 @@ nv50_graph_create_context(struct nouveau_channel *chan) + { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; +- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; - struct nouveau_gpuobj *ctx; -+ struct nouveau_gpuobj *obj; ++ struct nouveau_gpuobj *ramin = chan->ramin; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_grctx ctx = {}; int hdr, ret; NV_DEBUG(dev, "ch%d\n", chan->id); -@@ -223,32 +217,25 @@ nv50_graph_create_context(struct nouveau_channel *chan) - NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); + +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, +- 0x1000, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); ++ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000, ++ NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); if (ret) return ret; - ctx = chan->ramin_grctx->gpuobj; @@ -11995,29 +14752,28 @@ index b203d06..17a8d78 100644 - } - nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); - dev_priv->engine.instmem.finish_access(dev); -+ obj = chan->ramin_grctx->gpuobj; -+ + + hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + nv_wo32(ramin, hdr + 0x00, 0x00190002); -+ nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->instance + ++ nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst + + pgraph->grctx_size - 1); -+ nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->instance); ++ nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst); + nv_wo32(ramin, hdr + 0x0c, 0); + nv_wo32(ramin, hdr + 0x10, 0); + nv_wo32(ramin, hdr + 0x14, 0x00010000); + + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; -+ ctx.data = obj; ++ ctx.data = chan->ramin_grctx; + nv50_grctx_init(&ctx); + -+ nv_wo32(obj, 0x00000, chan->ramin->instance >> 12); - ++ nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); ++ + dev_priv->engine.instmem.flush(dev); return 0; } -@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) +@@ -257,19 +242,18 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -12026,17 +14782,51 @@ index b203d06..17a8d78 100644 NV_DEBUG(dev, "ch%d\n", chan->id); - if (!chan->ramin || !chan->ramin->gpuobj) +- if (!chan->ramin || !chan->ramin->gpuobj) ++ if (!chan->ramin) return; - dev_priv->engine.instmem.prepare_access(dev, true); for (i = hdr; i < hdr + 24; i += 4) - nv_wo32(dev, chan->ramin->gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); -+ nv_wo32(chan->ramin->gpuobj, i, 0); ++ nv_wo32(chan->ramin, i, 0); + dev_priv->engine.instmem.flush(dev); - nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); +- nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); ++ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); + } + + static int +@@ -296,7 +280,7 @@ nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst) + int + nv50_graph_load_context(struct nouveau_channel *chan) + { +- uint32_t inst = chan->ramin->instance >> 12; ++ uint32_t inst = chan->ramin->vinst >> 12; + + NV_DEBUG(chan->dev, "ch%d\n", chan->id); + return nv50_graph_do_load_context(chan->dev, inst); +@@ -341,15 +325,16 @@ static int + nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, + int mthd, uint32_t data) + { +- struct nouveau_gpuobj_ref *ref = NULL; ++ struct nouveau_gpuobj *gpuobj; + +- if (nouveau_gpuobj_ref_find(chan, data, &ref)) ++ gpuobj = nouveau_ramht_find(chan, data); ++ if (!gpuobj) + return -ENOENT; + +- if (nouveau_notifier_offset(ref->gpuobj, NULL)) ++ if (nouveau_notifier_offset(gpuobj, NULL)) + return -EINVAL; + +- chan->nvsw.vblsem = ref->gpuobj; ++ chan->nvsw.vblsem = gpuobj; + chan->nvsw.vblsem_offset = ~0; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index 42a8fb2..336aab2 100644 @@ -15837,78 +18627,531 @@ index 42a8fb2..336aab2 100644 size = (ctx->ctxvals_pos-offset)/8; } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c -index 5f21df3..092057b 100644 +index 5f21df3..c0eef78 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c -@@ -35,8 +35,6 @@ struct nv50_instmem_priv { - struct nouveau_gpuobj_ref *pramin_pt; - struct nouveau_gpuobj_ref *pramin_bar; - struct nouveau_gpuobj_ref *fb_bar; +@@ -32,41 +32,87 @@ + struct nv50_instmem_priv { + uint32_t save1700[5]; /* 0x1700->0x1710 */ + +- struct nouveau_gpuobj_ref *pramin_pt; +- struct nouveau_gpuobj_ref *pramin_bar; +- struct nouveau_gpuobj_ref *fb_bar; - - bool last_access_wr; ++ struct nouveau_gpuobj *pramin_pt; ++ struct nouveau_gpuobj *pramin_bar; ++ struct nouveau_gpuobj *fb_bar; }; - #define NV50_INSTMEM_PAGE_SHIFT 12 -@@ -141,13 +139,15 @@ nv50_instmem_init(struct drm_device *dev) - chan->file_priv = (struct drm_file *)-2; - dev_priv->fifos[0] = dev_priv->fifos[127] = chan; +-#define NV50_INSTMEM_PAGE_SHIFT 12 +-#define NV50_INSTMEM_PAGE_SIZE (1 << NV50_INSTMEM_PAGE_SHIFT) +-#define NV50_INSTMEM_PT_SIZE(a) (((a) >> 12) << 3) ++static void ++nv50_channel_del(struct nouveau_channel **pchan) ++{ ++ struct nouveau_channel *chan; -+ INIT_LIST_HEAD(&chan->ramht_refs); +-/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN +- */ +-#define BAR0_WI32(g, o, v) do { \ +- uint32_t offset; \ +- if ((g)->im_backing) { \ +- offset = (g)->im_backing_start; \ +- } else { \ +- offset = chan->ramin->gpuobj->im_backing_start; \ +- offset += (g)->im_pramin->start; \ +- } \ +- offset += (o); \ +- nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v)); \ +-} while (0) ++ chan = *pchan; ++ *pchan = NULL; ++ if (!chan) ++ return; + - /* Channel's PRAMIN object + heap */ - ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, - NULL, &chan->ramin); ++ nouveau_gpuobj_ref(NULL, &chan->ramfc); ++ nouveau_gpuobj_ref(NULL, &chan->vm_pd); ++ if (chan->ramin_heap.free_stack.next) ++ drm_mm_takedown(&chan->ramin_heap); ++ nouveau_gpuobj_ref(NULL, &chan->ramin); ++ kfree(chan); ++} ++ ++static int ++nv50_channel_new(struct drm_device *dev, u32 size, ++ struct nouveau_channel **pchan) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; ++ u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200; ++ struct nouveau_channel *chan; ++ int ret; ++ ++ chan = kzalloc(sizeof(*chan), GFP_KERNEL); ++ if (!chan) ++ return -ENOMEM; ++ chan->dev = dev; ++ ++ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); ++ if (ret) { ++ nv50_channel_del(&chan); ++ return ret; ++ } ++ ++ ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size); ++ if (ret) { ++ nv50_channel_del(&chan); ++ return ret; ++ } ++ ++ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : ++ chan->ramin->pinst + pgd, ++ chan->ramin->vinst + pgd, ++ 0x4000, NVOBJ_FLAG_ZERO_ALLOC, ++ &chan->vm_pd); ++ if (ret) { ++ nv50_channel_del(&chan); ++ return ret; ++ } ++ ++ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : ++ chan->ramin->pinst + fc, ++ chan->ramin->vinst + fc, 0x100, ++ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc); ++ if (ret) { ++ nv50_channel_del(&chan); ++ return ret; ++ } ++ ++ *pchan = chan; ++ return 0; ++} + + int + nv50_instmem_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *chan; +- uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size; +- uint32_t save_nv001700; +- uint64_t v; + struct nv50_instmem_priv *priv; ++ struct nouveau_channel *chan; + int ret, i; ++ u32 tmp; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -77,215 +123,113 @@ nv50_instmem_init(struct drm_device *dev) + for (i = 0x1700; i <= 0x1710; i += 4) + priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); + +- /* Reserve the last MiB of VRAM, we should probably try to avoid +- * setting up the below tables over the top of the VBIOS image at +- * some point. +- */ +- dev_priv->ramin_rsvd_vram = 1 << 20; +- c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; +- c_size = 128 << 10; +- c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; +- c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; +- c_base = c_vmpd + 0x4000; +- pt_size = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size); +- +- NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset); +- NV_DEBUG(dev, " VBIOS image: 0x%08x\n", +- (nv_rd32(dev, 0x619f04) & ~0xff) << 8); +- NV_DEBUG(dev, " Aperture size: %d MiB\n", dev_priv->ramin_size >> 20); +- NV_DEBUG(dev, " PT size: %d KiB\n", pt_size >> 10); +- +- /* Determine VM layout, we need to do this first to make sure +- * we allocate enough memory for all the page tables. +- */ +- dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); +- dev_priv->vm_gart_size = NV50_VM_BLOCK; +- +- dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; +- dev_priv->vm_vram_size = dev_priv->vram_size; +- if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) +- dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; +- dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); +- dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; +- +- dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; +- +- NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", +- dev_priv->vm_gart_base, +- dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); +- NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", +- dev_priv->vm_vram_base, +- dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); +- +- c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8); +- +- /* Map BAR0 PRAMIN aperture over the memory we want to use */ +- save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN); +- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16)); +- +- /* Create a fake channel, and use it as our "dummy" channels 0/127. +- * The main reason for creating a channel is so we can use the gpuobj +- * code. However, it's probably worth noting that NVIDIA also setup +- * their channels 0/127 with the same values they configure here. +- * So, there may be some other reason for doing this. +- * +- * Have to create the entire channel manually, as the real channel +- * creation code assumes we have PRAMIN access, and we don't until +- * we're done here. +- */ +- chan = kzalloc(sizeof(*chan), GFP_KERNEL); +- if (!chan) ++ /* Global PRAMIN heap */ ++ ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size); ++ if (ret) { ++ NV_ERROR(dev, "Failed to init RAMIN heap\n"); + return -ENOMEM; +- chan->id = 0; +- chan->dev = dev; +- chan->file_priv = (struct drm_file *)-2; +- dev_priv->fifos[0] = dev_priv->fifos[127] = chan; ++ } + +- /* Channel's PRAMIN object + heap */ +- ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, +- NULL, &chan->ramin); ++ /* we need a channel to plug into the hw to control the BARs */ ++ ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]); + if (ret) + return ret; ++ chan = dev_priv->fifos[127] = dev_priv->fifos[0]; + +- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base)) +- return -ENOMEM; +- +- /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ +- ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc, +- 0x4000, 0, NULL, &chan->ramfc); ++ /* allocate page table for PRAMIN BAR */ ++ ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, ++ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, ++ &priv->pramin_pt); if (ret) return ret; -- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base)) -+ if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base)) - return -ENOMEM; +- for (i = 0; i < c_vmpd; i += 4) +- BAR0_WI32(chan->ramin->gpuobj, i, 0); ++ nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63); ++ nv_wo32(chan->vm_pd, 0x0004, 0); - /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ -@@ -262,30 +262,25 @@ nv50_instmem_init(struct drm_device *dev) +- /* VM page directory */ +- ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd, +- 0x4000, 0, &chan->vm_pd, NULL); ++ /* DMA object for PRAMIN BAR */ ++ ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar); + if (ret) + return ret; +- for (i = 0; i < 0x4000; i += 8) { +- BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000); +- BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000); +- } +- +- /* PRAMIN page table, cheat and map into VM at 0x0000000000. +- * We map the entire fake channel into the start of the PRAMIN BAR +- */ +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000, +- 0, &priv->pramin_pt); ++ nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000); ++ nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); ++ nv_wo32(priv->pramin_bar, 0x08, 0x00000000); ++ nv_wo32(priv->pramin_bar, 0x0c, 0x00000000); ++ nv_wo32(priv->pramin_bar, 0x10, 0x00000000); ++ nv_wo32(priv->pramin_bar, 0x14, 0x00000000); ++ ++ /* map channel into PRAMIN, gpuobj didn't do it for us */ ++ ret = nv50_instmem_bind(dev, chan->ramin); + if (ret) + return ret; - /* Assume that praying isn't enough, check that we can re-read the - * entire fake channel back from the PRAMIN BAR */ -- dev_priv->engine.instmem.prepare_access(dev, false); - for (i = 0; i < c_size; i += 4) { - if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { - NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", - i); -- dev_priv->engine.instmem.finish_access(dev); - return -EINVAL; - } +- v = c_offset | 1; +- if (dev_priv->vram_sys_base) { +- v += dev_priv->vram_sys_base; +- v |= 0x30; +- } ++ /* poke regs... */ ++ nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); ++ nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); ++ nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4)); + +- i = 0; +- while (v < dev_priv->vram_sys_base + c_offset + c_size) { +- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v)); +- BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v)); +- v += 0x1000; +- i += 8; ++ tmp = nv_ri32(dev, 0); ++ nv_wi32(dev, 0, ~tmp); ++ if (nv_ri32(dev, 0) != ~tmp) { ++ NV_ERROR(dev, "PRAMIN readback failed\n"); ++ return -EIO; } ++ nv_wi32(dev, 0, tmp); + +- while (i < pt_size) { +- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000); +- BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000); +- i += 8; +- } ++ dev_priv->ramin_available = true; ++ ++ /* Determine VM layout */ ++ dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); ++ dev_priv->vm_gart_size = NV50_VM_BLOCK; ++ ++ dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; ++ dev_priv->vm_vram_size = dev_priv->vram_size; ++ if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) ++ dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; ++ dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); ++ dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; ++ ++ dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; + +- BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63); +- BAR0_WI32(chan->vm_pd, 0x04, 0x00000000); ++ NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", ++ dev_priv->vm_gart_base, ++ dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); ++ NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", ++ dev_priv->vm_vram_base, ++ dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); + + /* VRAM page table(s), mapped into VM at +1GiB */ + for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, +- NV50_VM_BLOCK/65536*8, 0, 0, +- &chan->vm_vram_pt[i]); ++ ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, ++ 0, NVOBJ_FLAG_ZERO_ALLOC, ++ &chan->vm_vram_pt[i]); + if (ret) { +- NV_ERROR(dev, "Error creating VRAM page tables: %d\n", +- ret); ++ NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); + dev_priv->vm_vram_pt_nr = i; + return ret; + } +- dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj; ++ dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; + +- for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size; +- v += 4) +- BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0); +- +- BAR0_WI32(chan->vm_pd, 0x10 + (i*8), +- chan->vm_vram_pt[i]->instance | 0x61); +- BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0); ++ nv_wo32(chan->vm_pd, 0x10 + (i*8), ++ chan->vm_vram_pt[i]->vinst | 0x61); ++ nv_wo32(chan->vm_pd, 0x14 + (i*8), 0); + } + +- /* DMA object for PRAMIN BAR */ +- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0, +- &priv->pramin_bar); +- if (ret) +- return ret; +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000); +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1); +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000); +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000); +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000); +- BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000); +- + /* DMA object for FB BAR */ +- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0, +- &priv->fb_bar); ++ ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); + if (ret) + return ret; +- BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000); +- BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 + +- drm_get_resource_len(dev, 1) - 1); +- BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000); +- BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000); +- BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000); +- BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000); +- +- /* Poke the relevant regs, and pray it works :) */ +- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); +- nv_wr32(dev, NV50_PUNK_UNK1710, 0); +- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) | +- NV50_PUNK_BAR_CFG_BASE_VALID); +- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) | +- NV50_PUNK_BAR1_CTXDMA_VALID); +- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | +- NV50_PUNK_BAR3_CTXDMA_VALID); +- ++ nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); ++ nv_wo32(priv->fb_bar, 0x04, 0x40000000 + ++ pci_resource_len(dev->pdev, 1) - 1); ++ nv_wo32(priv->fb_bar, 0x08, 0x40000000); ++ nv_wo32(priv->fb_bar, 0x0c, 0x00000000); ++ nv_wo32(priv->fb_bar, 0x10, 0x00000000); ++ nv_wo32(priv->fb_bar, 0x14, 0x00000000); ++ ++ nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); + for (i = 0; i < 8; i++) + nv_wr32(dev, 0x1900 + (i*4), 0); + +- /* Assume that praying isn't enough, check that we can re-read the +- * entire fake channel back from the PRAMIN BAR */ +- dev_priv->engine.instmem.prepare_access(dev, false); +- for (i = 0; i < c_size; i += 4) { +- if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { +- NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", +- i); +- dev_priv->engine.instmem.finish_access(dev); +- return -EINVAL; +- } +- } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); - - /* Global PRAMIN heap */ +- +- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); +- +- /* Global PRAMIN heap */ - if (nouveau_mem_init_heap(&dev_priv->ramin_heap, - c_size, dev_priv->ramin_size - c_size)) { - dev_priv->ramin_heap = NULL; -+ if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) { - NV_ERROR(dev, "Failed to init RAMIN heap\n"); - } - - /*XXX: incorrect, but needed to make hash func "work" */ - dev_priv->ramht_offset = 0x10000; - dev_priv->ramht_bits = 9; +- NV_ERROR(dev, "Failed to init RAMIN heap\n"); +- } +- +- /*XXX: incorrect, but needed to make hash func "work" */ +- dev_priv->ramht_offset = 0x10000; +- dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); -+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; return 0; } -@@ -321,7 +316,7 @@ nv50_instmem_takedown(struct drm_device *dev) - nouveau_gpuobj_del(dev, &chan->vm_pd); - nouveau_gpuobj_ref_del(dev, &chan->ramfc); - nouveau_gpuobj_ref_del(dev, &chan->ramin); -- nouveau_mem_takedown(&chan->ramin_heap); -+ drm_mm_takedown(&chan->ramin_heap); +@@ -302,29 +246,24 @@ nv50_instmem_takedown(struct drm_device *dev) + if (!priv) + return; + ++ dev_priv->ramin_available = false; ++ + /* Restore state from before init */ + for (i = 0x1700; i <= 0x1710; i += 4) + nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); + +- nouveau_gpuobj_ref_del(dev, &priv->fb_bar); +- nouveau_gpuobj_ref_del(dev, &priv->pramin_bar); +- nouveau_gpuobj_ref_del(dev, &priv->pramin_pt); ++ nouveau_gpuobj_ref(NULL, &priv->fb_bar); ++ nouveau_gpuobj_ref(NULL, &priv->pramin_bar); ++ nouveau_gpuobj_ref(NULL, &priv->pramin_pt); + + /* Destroy dummy channel */ + if (chan) { +- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { +- nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); +- dev_priv->vm_vram_pt[i] = NULL; +- } ++ for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) ++ nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); + dev_priv->vm_vram_pt_nr = 0; + +- nouveau_gpuobj_del(dev, &chan->vm_pd); +- nouveau_gpuobj_ref_del(dev, &chan->ramfc); +- nouveau_gpuobj_ref_del(dev, &chan->ramin); +- nouveau_mem_takedown(&chan->ramin_heap); +- +- dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; +- kfree(chan); ++ nv50_channel_del(&dev_priv->fifos[0]); ++ dev_priv->fifos[127] = NULL; + } + + dev_priv->engine.instmem.priv = NULL; +@@ -336,14 +275,14 @@ nv50_instmem_suspend(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->fifos[0]; +- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; ++ struct nouveau_gpuobj *ramin = chan->ramin; + int i; + +- ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size); ++ ramin->im_backing_suspend = vmalloc(ramin->size); + if (!ramin->im_backing_suspend) + return -ENOMEM; + +- for (i = 0; i < ramin->im_pramin->size; i += 4) ++ for (i = 0; i < ramin->size; i += 4) + ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); + return 0; + } +@@ -354,23 +293,25 @@ nv50_instmem_resume(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; + struct nouveau_channel *chan = dev_priv->fifos[0]; +- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; ++ struct nouveau_gpuobj *ramin = chan->ramin; + int i; + +- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16)); +- for (i = 0; i < ramin->im_pramin->size; i += 4) +- BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]); ++ dev_priv->ramin_available = false; ++ dev_priv->ramin_base = ~0; ++ for (i = 0; i < ramin->size; i += 4) ++ nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]); ++ dev_priv->ramin_available = true; + vfree(ramin->im_backing_suspend); + ramin->im_backing_suspend = NULL; + + /* Poke the relevant regs, and pray it works :) */ +- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); ++ nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12)); + nv_wr32(dev, NV50_PUNK_UNK1710, 0); +- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) | ++ nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) | + NV50_PUNK_BAR_CFG_BASE_VALID); +- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) | ++ nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) | + NV50_PUNK_BAR1_CTXDMA_VALID); +- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | ++ nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) | + NV50_PUNK_BAR3_CTXDMA_VALID); + + for (i = 0; i < 8; i++) +@@ -386,7 +327,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, + if (gpuobj->im_backing) + return -EINVAL; + +- *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE); ++ *sz = ALIGN(*sz, 4096); + if (*sz == 0) + return -EINVAL; + +@@ -404,9 +345,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, + return ret; + } + +- gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; +- gpuobj->im_backing_start <<= PAGE_SHIFT; +- ++ gpuobj->vinst = gpuobj->im_backing->bo.mem.mm_node->start << PAGE_SHIFT; + return 0; + } + +@@ -429,23 +368,23 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; +- struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj; ++ struct nouveau_gpuobj *pramin_pt = priv->pramin_pt; + uint32_t pte, pte_end; + uint64_t vram; - dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; - kfree(chan); -@@ -436,14 +431,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) return -EINVAL; @@ -15918,14 +19161,18 @@ index 5f21df3..092057b 100644 pte = (gpuobj->im_pramin->start >> 12) << 1; pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; - vram = gpuobj->im_backing_start; +- vram = gpuobj->im_backing_start; ++ vram = gpuobj->vinst; - NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n", + NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", gpuobj->im_pramin->start, pte, pte_end); - NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); +- NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); ++ NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); -@@ -453,27 +448,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + vram |= 1; + if (dev_priv->vram_sys_base) { +@@ -453,27 +392,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) vram |= 0x30; } @@ -15933,11 +19180,8 @@ index 5f21df3..092057b 100644 while (pte < pte_end) { - nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); - nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); -+ nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); -+ nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); - vram += NV50_INSTMEM_PAGE_SIZE; -+ pte += 2; - } +- vram += NV50_INSTMEM_PAGE_SIZE; +- } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, 0x100c80, 0x00040001); @@ -15945,7 +19189,11 @@ index 5f21df3..092057b 100644 - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; -- } ++ nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); ++ nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); ++ vram += 0x1000; ++ pte += 2; + } + dev_priv->engine.instmem.flush(dev); - nv_wr32(dev, 0x100c80, 0x00060001); @@ -15959,7 +19207,14 @@ index 5f21df3..092057b 100644 gpuobj->im_bound = 1; return 0; -@@ -492,36 +476,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -489,39 +417,44 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + if (gpuobj->im_bound == 0) + return -EINVAL; + ++ /* can happen during late takedown */ ++ if (unlikely(!dev_priv->ramin_available)) ++ return 0; ++ pte = (gpuobj->im_pramin->start >> 12) << 1; pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; @@ -15967,8 +19222,8 @@ index 5f21df3..092057b 100644 while (pte < pte_end) { - nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); - nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); -+ nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 0, 0x00000000); -+ nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 4, 0x00000000); ++ nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000); ++ nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000); + pte += 2; } - dev_priv->engine.instmem.finish_access(dev); @@ -15987,7 +19242,7 @@ index 5f21df3..092057b 100644 - - priv->last_access_wr = write; + nv_wr32(dev, 0x00330c, 0x00000001); -+ if (!nv_wait(0x00330c, 0x00000002, 0x00000000)) ++ if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } @@ -16004,7 +19259,7 @@ index 5f21df3..092057b 100644 - NV_ERROR(dev, "PRAMIN flush timeout\n"); - } + nv_wr32(dev, 0x070000, 0x00000001); -+ if (!nv_wait(0x070000, 0x00000002, 0x00000000)) ++ if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } @@ -16012,11 +19267,11 @@ index 5f21df3..092057b 100644 +nv50_vm_flush(struct drm_device *dev, int engine) +{ + nv_wr32(dev, 0x100c80, (engine << 16) | 1); -+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) ++ if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) + NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); +} diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c -index 812778d..bcd4cf8 100644 +index 812778d..b4a5ecb 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -37,52 +37,32 @@ @@ -16104,7 +19359,24 @@ index 812778d..bcd4cf8 100644 nvenc->dcb->or != nv_encoder->dcb->or) continue; -@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) +@@ -110,7 +92,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) + } + + /* wait for it to be done */ +- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or), ++ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), + NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) { + NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or); + NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or, +@@ -126,15 +108,29 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) + + nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val | + NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING); +- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(or), ++ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or), + NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) { + NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or); + NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or, nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or))); } @@ -16264,10 +19536,10 @@ index 0000000..26a9960 +} diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c new file mode 100644 -index 0000000..45ca994 +index 0000000..2cdb7c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c -@@ -0,0 +1,95 @@ +@@ -0,0 +1,89 @@ +/* + * Copyright 2010 Red Hat Inc. + * @@ -16313,12 +19585,6 @@ index 0000000..45ca994 +} + +bool -+nvc0_fifo_cache_flush(struct drm_device *dev) -+{ -+ return true; -+} -+ -+bool +nvc0_fifo_cache_pull(struct drm_device *dev, bool enable) +{ + return false; @@ -16445,10 +19711,10 @@ index 0000000..edf2b21 +} diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c new file mode 100644 -index 0000000..9238c73 +index 0000000..152d8e8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c -@@ -0,0 +1,234 @@ +@@ -0,0 +1,229 @@ +/* + * Copyright 2010 Red Hat Inc. + * @@ -16501,8 +19767,7 @@ index 0000000..9238c73 + return ret; + } + -+ gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; -+ gpuobj->im_backing_start <<= PAGE_SHIFT; ++ gpuobj->vinst = gpuobj->im_backing->bo.mem.mm_node->start << PAGE_SHIFT; + return 0; +} + @@ -16535,11 +19800,11 @@ index 0000000..9238c73 + + pte = gpuobj->im_pramin->start >> 12; + pte_end = (gpuobj->im_pramin->size >> 12) + pte; -+ vram = gpuobj->im_backing_start; ++ vram = gpuobj->vinst; + + NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", + gpuobj->im_pramin->start, pte, pte_end); -+ NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); ++ NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); + + while (pte < pte_end) { + nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); @@ -16585,7 +19850,7 @@ index 0000000..9238c73 +nvc0_instmem_flush(struct drm_device *dev) +{ + nv_wr32(dev, 0x070000, 1); -+ if (!nv_wait(0x070000, 0x00000002, 0x00000000)) ++ if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); +} + @@ -16672,10 +19937,6 @@ index 0000000..9238c73 + return -ENOMEM; + } + -+ /*XXX: incorrect, but needed to make hash func "work" */ -+ dev_priv->ramht_offset = 0x10000; -+ dev_priv->ramht_bits = 9; -+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; + return 0; +} + diff --git a/kernel.spec b/kernel.spec index 4d2cd3eb8..134f6f334 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 22 +%global baserelease 23 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1921,6 +1921,9 @@ fi # and build. %changelog +* Wed Sep 08 2010 Ben Skeggs 2.6.35.4-23 +- nouveau: handle certain GPU errors better, AGP + misc fixes + * Tue Sep 07 2010 Dave Jones 2.6.35.4-22 - Disable hung task checker, it only ever causes false positives. (#630777) From 0fe99e9810c8eed7171b56d04fe18ee4f0801a66 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 8 Sep 2010 16:49:21 +1000 Subject: [PATCH 042/277] nouveau: fix compile error due to upstream differences --- drm-nouveau-updates.patch | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 9749a29c8..69567e7af 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,4 +1,4 @@ -From 71c6844b5918cd5b1f8b61735e52be12fb5f80e5 Mon Sep 17 00:00:00 2001 +From 65eb698a6879847281f18930145bb6e72ef62968 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Jun 2010 15:32:24 +1000 Subject: [PATCH] drm-nouveau-updates @@ -957,6 +957,8 @@ This commit also adds somewhat more useful logging when these exceptions occur. Signed-off-by: Ben Skeggs + +fix compile error due to upstream differences --- drivers/gpu/drm/drm_crtc_helper.c | 22 +- drivers/gpu/drm/i2c/ch7006_drv.c | 22 +- @@ -18627,7 +18629,7 @@ index 42a8fb2..336aab2 100644 size = (ctx->ctxvals_pos-offset)/8; } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c -index 5f21df3..c0eef78 100644 +index 5f21df3..457a8bc 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -32,41 +32,87 @@ @@ -18672,7 +18674,7 @@ index 5f21df3..c0eef78 100644 + + nouveau_gpuobj_ref(NULL, &chan->ramfc); + nouveau_gpuobj_ref(NULL, &chan->vm_pd); -+ if (chan->ramin_heap.free_stack.next) ++ if (chan->ramin_heap.fl_entry.next) + drm_mm_takedown(&chan->ramin_heap); + nouveau_gpuobj_ref(NULL, &chan->ramin); + kfree(chan); From 72b3bf972eb2e38958f600d05befb2cb83019214 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 8 Sep 2010 15:09:01 -0400 Subject: [PATCH 043/277] linux-2.6-defaults-pci_use_crs --- Makefile | 2 ++ config-debug | 2 ++ config-nodebug | 2 ++ kernel.spec | 5 +++++ linux-2.6-defaults-pci_use_crs.patch | 29 ++++++++++++++++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 linux-2.6-defaults-pci_use_crs.patch diff --git a/Makefile b/Makefile index ea1296b48..c08c2522c 100644 --- a/Makefile +++ b/Makefile @@ -88,6 +88,7 @@ debug: @perl -pi -e 's/# CONFIG_KDB_KEYBOARD is not set/CONFIG_KDB_KEYBOARD=y/' config-nodebug @perl -pi -e 's/# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set/CONFIG_CPU_NOTIFIER_ERROR_INJECT=m/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_PER_CPU_MAPS is not set/CONFIG_DEBUG_PER_CPU_MAPS=y/' config-nodebug + #@perl -pi -e 's/# CONFIG_PCI_DEFAULT_USE_CRS is not set/CONFIG_PCI_DEFAULT_USE_CRS=y/' config-nodebug @# just in case we're going from extremedebug -> debug @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug @@ -156,6 +157,7 @@ release: #@perl -pi -e 's/CONFIG_KGDB_KDB=y/# CONFIG_KGDB_KDB is not set/' config-nodebug #@perl -pi -e 's/CONFIG_KDB_KEYBOARD=y/# CONFIG_KDB_KEYBOARD is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_PER_CPU_MAPS=y/# CONFIG_DEBUG_PER_CPU_MAPS is not set/' config-nodebug + #@perl -pi -e 's/CONFIG_PCI_DEFAULT_USE_CRS=y/# CONFIG_PCI_DEFAULT_USE_CRS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-debug @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug diff --git a/config-debug b/config-debug index f8c7c00b1..6c6209e6b 100644 --- a/config-debug +++ b/config-debug @@ -87,5 +87,7 @@ CONFIG_PM_ADVANCED_DEBUG=y CONFIG_CEPH_FS_PRETTYDEBUG=y CONFIG_QUOTA_DEBUG=y +# CONFIG_PCI_DEFAULT_USE_CRS is not set + CONFIG_KGDB_KDB=y CONFIG_KDB_KEYBOARD=y diff --git a/config-nodebug b/config-nodebug index 5c7f4364e..e1f14bb59 100644 --- a/config-nodebug +++ b/config-nodebug @@ -87,5 +87,7 @@ CONFIG_PM_ADVANCED_DEBUG=y CONFIG_CEPH_FS_PRETTYDEBUG=y CONFIG_QUOTA_DEBUG=y +# CONFIG_PCI_DEFAULT_USE_CRS is not set + CONFIG_KGDB_KDB=y CONFIG_KDB_KEYBOARD=y diff --git a/kernel.spec b/kernel.spec index 134f6f334..48e29f5bb 100644 --- a/kernel.spec +++ b/kernel.spec @@ -615,6 +615,7 @@ Patch204: linux-2.6-debug-always-inline-kzalloc.patch Patch300: create-sys-fs-cgroup-to-mount-cgroupfs-on.patch Patch380: linux-2.6-defaults-pci_no_msi.patch +Patch381: linux-2.6-defaults-pci_use_crs.patch Patch383: linux-2.6-defaults-aspm.patch Patch384: pci-acpi-disable-aspm-if-no-osc.patch Patch385: pci-aspm-dont-enable-too-early.patch @@ -1206,6 +1207,7 @@ ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch # # make default state of PCI MSI a config option ApplyPatch linux-2.6-defaults-pci_no_msi.patch +ApplyPatch linux-2.6-defaults-pci_use_crs.patch # enable ASPM by default on hardware we expect to work ApplyPatch linux-2.6-defaults-aspm.patch # disable aspm if acpi doesn't provide an _OSC method @@ -1921,6 +1923,9 @@ fi # and build. %changelog +* Wed Sep 08 2010 Kyle McMartin +- Make pci=use_crs a config option. + * Wed Sep 08 2010 Ben Skeggs 2.6.35.4-23 - nouveau: handle certain GPU errors better, AGP + misc fixes diff --git a/linux-2.6-defaults-pci_use_crs.patch b/linux-2.6-defaults-pci_use_crs.patch new file mode 100644 index 000000000..18acee12d --- /dev/null +++ b/linux-2.6-defaults-pci_use_crs.patch @@ -0,0 +1,29 @@ +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index cea0cd9..c326065 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2142,3 +2142,8 @@ source "crypto/Kconfig" + source "arch/x86/kvm/Kconfig" + + source "lib/Kconfig" ++ ++config PCI_DEFAULT_USE_CRS ++ def_bool y ++ prompt "Use PCI Host Bridge Windows from ACPI by default?" ++ depends on ACPI +diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c +index 15466c0..3099406 100644 +--- a/arch/x86/pci/acpi.c ++++ b/arch/x86/pci/acpi.c +@@ -16,7 +16,11 @@ struct pci_root_info { + int busnum; + }; + ++#ifdef CONFIG_PCI_DEFAULT_USE_CRS + static bool pci_use_crs = true; ++#else ++static bool pci_use_crs = false; ++#endif + + static int __init set_use_crs(const struct dmi_system_id *id) + { From 3ceeb77a7936d20cd6dbc66e110fa6e41de97524 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 8 Sep 2010 20:52:22 -0400 Subject: [PATCH 044/277] enable GPIO_SYSFS --- config-generic | 2 +- kernel.spec | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config-generic b/config-generic index 1d079b5df..d7269a545 100644 --- a/config-generic +++ b/config-generic @@ -4274,7 +4274,7 @@ CONFIG_BLK_DEV_DRBD=m # CONFIG_DEBUG_GPIO is not set # CONFIG_W1_MASTER_GPIO is not set # CONFIG_LEDS_GPIO is not set -# CONFIG_GPIO_SYSFS is not set +CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_MAX732X is not set # CONFIG_GPIO_PCA953X is not set # CONFIG_GPIO_PCF857X is not set diff --git a/kernel.spec b/kernel.spec index 48e29f5bb..551b2917d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1923,6 +1923,9 @@ fi # and build. %changelog +* Wed Sep 08 2010 Kyle McMartin +- Enable GPIO_SYSFS. (#631958) + * Wed Sep 08 2010 Kyle McMartin - Make pci=use_crs a config option. From fbc4283e1216576bc93c9385735b6a3c2b48b37f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Aug 2010 10:02:52 +1000 Subject: [PATCH 045/277] nouveau: disable accel on nva3/nva5/nva8 --- drm-nouveau-nva3-noaccel.patch | 106 +++++++++++++++++++++++++++++++++ kernel.spec | 6 ++ 2 files changed, 112 insertions(+) create mode 100644 drm-nouveau-nva3-noaccel.patch diff --git a/drm-nouveau-nva3-noaccel.patch b/drm-nouveau-nva3-noaccel.patch new file mode 100644 index 000000000..7dd9678f4 --- /dev/null +++ b/drm-nouveau-nva3-noaccel.patch @@ -0,0 +1,106 @@ +From 07a51882863d9e45b0715dcffbb66491adf2fb4e Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Wed, 30 Jun 2010 13:34:05 +1000 +Subject: [PATCH] drm/nouveau: disable acceleration on NVA3/NVA5/NVA8 by default + +There's an GPU lockup problem for which the cause is currently unknown +on these chipsets. + +Until it's resolved, it's better to leave the user with a working system +without acceleration than to have random lockups. + +With this patch, acceleration will be off by default if a known problem +chipset is detected, but can be re-enabled with nouveau.noaccel=0 on +the kernel commandline. + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_drv.c | 2 +- + drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + + drivers/gpu/drm/nouveau/nouveau_state.c | 23 +++++++++++++++++++---- + 3 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c +index 946748a..9b69328 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.c +@@ -72,7 +72,7 @@ int nouveau_ignorelid = 0; + module_param_named(ignorelid, nouveau_ignorelid, int, 0400); + + MODULE_PARM_DESC(noaccel, "Disable all acceleration"); +-int nouveau_noaccel = 0; ++int nouveau_noaccel = -1; + module_param_named(noaccel, nouveau_noaccel, int, 0400); + + MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h +index 24b3d03..0cf1bee 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -504,6 +504,7 @@ enum nouveau_card_type { + + struct drm_nouveau_private { + struct drm_device *dev; ++ bool noaccel; + + /* the card type, takes NV_* as values */ + enum nouveau_card_type card_type; +diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c +index be85960..896f6ae 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -563,7 +563,7 @@ nouveau_card_init(struct drm_device *dev) + if (ret) + goto out_timer; + +- if (nouveau_noaccel) ++ if (dev_priv->noaccel) + engine->graph.accel_blocked = true; + else { + /* PGRAPH */ +@@ -613,10 +613,10 @@ out_irq: + out_display: + engine->display.destroy(dev); + out_fifo: +- if (!nouveau_noaccel) ++ if (!dev_priv->noaccel) + engine->fifo.takedown(dev); + out_graph: +- if (!nouveau_noaccel) ++ if (!dev_priv->noaccel) + engine->graph.takedown(dev); + out_fb: + engine->fb.takedown(dev); +@@ -655,7 +655,7 @@ static void nouveau_card_takedown(struct drm_device *dev) + dev_priv->channel = NULL; + } + +- if (!nouveau_noaccel) { ++ if (!dev_priv->noaccel) { + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + } +@@ -861,6 +861,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + if (ret) + goto err_mmio; + ++ if (nouveau_noaccel == -1) { ++ switch (dev_priv->chipset) { ++ case 0xa3: ++ case 0xa5: ++ case 0xa8: ++ dev_priv->noaccel = true; ++ break; ++ default: ++ dev_priv->noaccel = false; ++ break; ++ } ++ } else { ++ dev_priv->noaccel = (nouveau_noaccel != 0); ++ } ++ + /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ + if (dev_priv->card_type >= NV_40) { + int ramin_bar = 2; +-- +1.7.2.2 diff --git a/kernel.spec b/kernel.spec index 551b2917d..18b26973b 100644 --- a/kernel.spec +++ b/kernel.spec @@ -657,6 +657,7 @@ Patch1807: drm-i2c-ch7006-fix.patch # nouveau + drm fixes Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch +Patch1812: drm-nouveau-nva3-noaccel.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1273,6 +1274,8 @@ ApplyPatch drm-i2c-ch7006-fix.patch # Nouveau DRM + drm fixes ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch +ApplyPatch drm-nouveau-nva3-noaccel.patch + ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch ApplyPatch drm-intel-make-lvds-work.patch @@ -1923,6 +1926,9 @@ fi # and build. %changelog +* Fri Sep 10 2010 Ben Skeggs +- nouveau: disable acceleration on nva3/nva5/nva8 + * Wed Sep 08 2010 Kyle McMartin - Enable GPIO_SYSFS. (#631958) From 63fcde2459a3c8cd6b7960412488df20255b3b14 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Fri, 10 Sep 2010 10:17:06 -0400 Subject: [PATCH 046/277] Disable asynchronous suspend by default. --- kernel.spec | 7 ++++++- linux-2.6-defaults-no-pm-async.patch | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 linux-2.6-defaults-no-pm-async.patch diff --git a/kernel.spec b/kernel.spec index 18b26973b..cccddb135 100644 --- a/kernel.spec +++ b/kernel.spec @@ -616,6 +616,7 @@ Patch300: create-sys-fs-cgroup-to-mount-cgroupfs-on.patch Patch380: linux-2.6-defaults-pci_no_msi.patch Patch381: linux-2.6-defaults-pci_use_crs.patch +Patch382: linux-2.6-defaults-no-pm-async.patch Patch383: linux-2.6-defaults-aspm.patch Patch384: pci-acpi-disable-aspm-if-no-osc.patch Patch385: pci-aspm-dont-enable-too-early.patch @@ -1195,6 +1196,7 @@ ApplyPatch linux-2.6-defaults-acpi-video.patch ApplyPatch linux-2.6-acpi-video-dos.patch ApplyPatch acpi-ec-add-delay-before-write.patch ApplyPatch linux-2.6-acpi-debug-infinite-loop.patch +ApplyPatch linux-2.6-defaults-no-pm-async.patch # Various low-impact patches to aid debugging. ApplyPatch linux-2.6-debug-sizeof-structs.patch @@ -1926,7 +1928,10 @@ fi # and build. %changelog -* Fri Sep 10 2010 Ben Skeggs +* Fri Sep 10 2010 Chuck Ebbert +- Disable asynchronous suspend by default. + +* Fri Sep 10 2010 Ben Skeggs - 2.6.35.4-23 - nouveau: disable acceleration on nva3/nva5/nva8 * Wed Sep 08 2010 Kyle McMartin diff --git a/linux-2.6-defaults-no-pm-async.patch b/linux-2.6-defaults-no-pm-async.patch new file mode 100644 index 000000000..7050542ba --- /dev/null +++ b/linux-2.6-defaults-no-pm-async.patch @@ -0,0 +1,11 @@ +--- linux-2.6.34.noarch.orig/kernel/power/main.c ++++ linux-2.6.34.noarch/kernel/power/main.c +@@ -45,7 +45,7 @@ int pm_notifier_call_chain(unsigned long + } + + /* If set, devices may be suspended and resumed asynchronously. */ +-int pm_async_enabled = 1; ++int pm_async_enabled; + + static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) From 102e2d671806d134b32371aedbc78dfac9950fb9 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 10 Sep 2010 10:28:50 -0400 Subject: [PATCH 047/277] bz620313 --- bjorn-pci-crs-rollup-v3.patch | 256 ++++++++++++++++++++++++++++++++++ kernel.spec | 10 +- 2 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 bjorn-pci-crs-rollup-v3.patch diff --git a/bjorn-pci-crs-rollup-v3.patch b/bjorn-pci-crs-rollup-v3.patch new file mode 100644 index 000000000..dc9a2c94d --- /dev/null +++ b/bjorn-pci-crs-rollup-v3.patch @@ -0,0 +1,256 @@ +commit 023ce8434ec95ef8348bf4ac4068fdd9298bf1d2 +Author: Bjorn Helgaas +Date: Fri Sep 3 16:03:13 2010 -0600 + + x86/PCI: allocate space from the end of a region, not the beginning + + Allocate from the end of a region, not the beginning. + + For example, if we need to allocate 0x800 bytes for a device on bus + 0000:00 given these resources: + + [mem 0xbff00000-0xdfffffff] PCI Bus 0000:00 + [mem 0xc0000000-0xdfffffff] PCI Bus 0000:02 + + the available space at [mem 0xbff00000-0xbfffffff] is passed to the + alignment callback (pcibios_align_resource()). Prior to this patch, we + would put the new 0x800 byte resource at the beginning of that available + space, i.e., at [mem 0xbff00000-0xbff007ff]. + + With this patch, we put it at the end, at [mem 0xbffff800-0xbfffffff]. + + FIXME details about Windows practice + + Signed-off-by: Bjorn Helgaas + +diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c +index 5525309..1ff3e9f 100644 +--- a/arch/x86/pci/i386.c ++++ b/arch/x86/pci/i386.c +@@ -65,7 +65,10 @@ pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) + { + struct pci_dev *dev = data; +- resource_size_t start = res->start; ++ resource_size_t start = ALIGN(res->end - size + 1, align); ++ ++ if (start < res->start) ++ start = res->start; + + if (res->flags & IORESOURCE_IO) { + if (skip_isa_ioresource_align(dev)) +commit 23a85e85345fafcbc5dd5c1fc4868706290ef684 +Author: Bjorn Helgaas +Date: Tue Sep 7 16:33:00 2010 -0600 + + resources: allocate space within a region from the top down + + Allocate space from the top of a region first, then work downward. + + When we allocate space from a resource, we look for gaps between children + of the resource. Previously, we looked at gaps from the bottom up. For + example, given this: + + [mem 0xbff00000-0xf7ffffff] PCI Bus 0000:00 + [mem 0xc0000000-0xdfffffff] PCI Bus 0000:02 + + we attempted to allocate from the [mem 0xbff00000-0xbfffffff] gap first, + then the [mem 0xe0000000-0xf7ffffff] gap. + + With this patch, we allocate from [mem 0xe0000000-0xf7ffffff] first. + + Low addresses are generally scarce, so it's better to use high addresses + when possible. This follows Windows practice for PCI allocation. + + FIXME ref for Windows practice + + Signed-off-by: Bjorn Helgaas + +diff --git a/kernel/resource.c b/kernel/resource.c +index 7b36976..e83ff7c 100644 +--- a/kernel/resource.c ++++ b/kernel/resource.c +@@ -358,6 +358,20 @@ int __weak page_is_ram(unsigned long pfn) + } + + /* ++ * Find the resource before "child" in the sibling list of "root" children. ++ */ ++static struct resource *find_sibling_prev(struct resource *root, struct resource *child) ++{ ++ struct resource *this; ++ ++ for (this = root->child; this; this = this->sibling) ++ if (this->sibling == child) ++ return this; ++ ++ return NULL; ++} ++ ++/* + * Find empty slot in the resource tree given range and alignment. + */ + static int find_resource(struct resource *root, struct resource *new, +@@ -369,23 +383,17 @@ static int find_resource(struct resource *root, struct resource *new, + resource_size_t), + void *alignf_data) + { +- struct resource *this = root->child; ++ struct resource *this; + struct resource tmp = *new; + +- tmp.start = root->start; +- /* +- * Skip past an allocated resource that starts at 0, since the assignment +- * of this->start - 1 to tmp->end below would cause an underflow. +- */ +- if (this && this->start == 0) { +- tmp.start = this->end + 1; +- this = this->sibling; +- } +- for(;;) { ++ tmp.end = root->end; ++ ++ this = find_sibling_prev(root, NULL); ++ for (;;) { + if (this) +- tmp.end = this->start - 1; ++ tmp.start = this->end + 1; + else +- tmp.end = root->end; ++ tmp.start = root->start; + if (tmp.start < min) + tmp.start = min; + if (tmp.end > max) +@@ -398,10 +406,10 @@ static int find_resource(struct resource *root, struct resource *new, + new->end = tmp.start + size - 1; + return 0; + } +- if (!this) ++ if (!this || this->start == root->start) + break; +- tmp.start = this->end + 1; +- this = this->sibling; ++ tmp.end = this->start - 1; ++ this = find_sibling_prev(root, this); + } + return -EBUSY; + } +commit 7e50b2f8590ffe4870e2575c796386c88d006558 +Author: Bjorn Helgaas +Date: Thu Sep 9 12:37:56 2010 -0600 + + PCI: allocate bus resources from the top down + + Allocate space from the highest-address PCI bus resource first, then work + downward. + + Previously, we looked for space in PCI host bridge windows in the order + we discovered the windows. For example, given the following windows + (discovered via an ACPI _CRS method): + + pci_root PNP0A03:00: host bridge window [mem 0x000a0000-0x000bffff] + pci_root PNP0A03:00: host bridge window [mem 0x000c0000-0x000effff] + pci_root PNP0A03:00: host bridge window [mem 0x000f0000-0x000fffff] + pci_root PNP0A03:00: host bridge window [mem 0xbff00000-0xf7ffffff] + pci_root PNP0A03:00: host bridge window [mem 0xff980000-0xff980fff] + pci_root PNP0A03:00: host bridge window [mem 0xff97c000-0xff97ffff] + pci_root PNP0A03:00: host bridge window [mem 0xfed20000-0xfed9ffff] + + we attempted to allocate from [mem 0x000a0000-0x000bffff] first, then + [mem 0x000c0000-0x000effff], and so on. + + With this patch, we allocate from [mem 0xff980000-0xff980fff] first, then + [mem 0xff97c000-0xff97ffff], [mem 0xfed20000-0xfed9ffff], etc. + + Allocating top-down follows Windows practice, so we're less likely to + trip over BIOS defects in the _CRS description. On the machine above, + the [mem 0xbff00000-0xbfffffff] region doesn't actually work and is + likely a BIOS defect. + + Bug: https://bugzilla.kernel.org/show_bug.cgi?id=16228 + Bug: https://bugzilla.redhat.com/show_bug.cgi?id=620313 + Bug: https://bugzilla.redhat.com/show_bug.cgi?id=629933 + + Signed-off-by: Bjorn Helgaas + +diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c +index 7f0af0e..172bf26 100644 +--- a/drivers/pci/bus.c ++++ b/drivers/pci/bus.c +@@ -64,6 +64,49 @@ void pci_bus_remove_resources(struct pci_bus *bus) + } + } + ++/* ++ * Find the highest-address bus resource below the cursor "res". If the ++ * cursor is NULL, return the highest resource. ++ */ ++static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, ++ unsigned int type, ++ struct resource *res) ++{ ++ struct resource *r, *prev = NULL; ++ int i; ++ ++ pci_bus_for_each_resource(bus, r, i) { ++ if (!r) ++ continue; ++ ++ if ((r->flags & IORESOURCE_TYPE_BITS) != type) ++ continue; ++ ++ /* If this resource is at or past the cursor, skip it */ ++ if (res) { ++ if (r == res) ++ continue; ++ if (r->end > res->end) ++ continue; ++ if (r->end == res->end && r->start > res->start) ++ continue; ++ } ++ ++ if (!prev) ++ prev = r; ++ ++ /* ++ * A small resource is higher than a large one that ends at ++ * the same address. ++ */ ++ if (r->end > prev->end || ++ (r->end == prev->end && r->start > prev->start)) ++ prev = r; ++ } ++ ++ return prev; ++} ++ + /** + * pci_bus_alloc_resource - allocate a resource from a parent bus + * @bus: PCI bus +@@ -89,9 +132,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + resource_size_t), + void *alignf_data) + { +- int i, ret = -ENOMEM; ++ int ret = -ENOMEM; + struct resource *r; + resource_size_t max = -1; ++ unsigned int type = res->flags & IORESOURCE_TYPE_BITS; + + type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + +@@ -99,10 +143,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + if (!(res->flags & IORESOURCE_MEM_64)) + max = PCIBIOS_MAX_MEM_32; + +- pci_bus_for_each_resource(bus, r, i) { +- if (!r) +- continue; +- ++ /* Look for space at highest addresses first */ ++ r = pci_bus_find_resource_prev(bus, type, NULL); ++ for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) { + /* type_mask must match */ + if ((res->flags ^ r->flags) & type_mask) + continue; diff --git a/kernel.spec b/kernel.spec index cccddb135..62a4c2176 100644 --- a/kernel.spec +++ b/kernel.spec @@ -23,7 +23,7 @@ Summary: The Linux kernel # # (Uncomment the '#' and both spaces below to set the buildid.) # -# % define buildid .local +%define buildid .bz620313 ################################################################### # The buildid can also be specified on the rpmbuild command line @@ -614,6 +614,8 @@ Patch204: linux-2.6-debug-always-inline-kzalloc.patch Patch300: create-sys-fs-cgroup-to-mount-cgroupfs-on.patch +Patch370: bjorn-pci-crs-rollup-v3.patch + Patch380: linux-2.6-defaults-pci_no_msi.patch Patch381: linux-2.6-defaults-pci_use_crs.patch Patch382: linux-2.6-defaults-no-pm-async.patch @@ -1210,7 +1212,8 @@ ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch # # make default state of PCI MSI a config option ApplyPatch linux-2.6-defaults-pci_no_msi.patch -ApplyPatch linux-2.6-defaults-pci_use_crs.patch +#ApplyPatch linux-2.6-defaults-pci_use_crs.patch +ApplyPatch bjorn-pci-crs-rollup-v3.patch # enable ASPM by default on hardware we expect to work ApplyPatch linux-2.6-defaults-aspm.patch # disable aspm if acpi doesn't provide an _OSC method @@ -1928,6 +1931,9 @@ fi # and build. %changelog +* Fri Sep 10 2010 Kyle McMartin +- Suck in patch from Bjorn to try to fix pci=use_crs + * Fri Sep 10 2010 Chuck Ebbert - Disable asynchronous suspend by default. From 88a50a0b1db983928abbe0b7417644632fbac348 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 10 Sep 2010 10:33:28 -0400 Subject: [PATCH 048/277] Revert 102e2d67 This reverts commit 102e2d671806d134b32371aedbc78dfac9950fb9 which accidentally snuck into the wrong branch. --- bjorn-pci-crs-rollup-v3.patch | 256 ---------------------------------- kernel.spec | 10 +- 2 files changed, 2 insertions(+), 264 deletions(-) delete mode 100644 bjorn-pci-crs-rollup-v3.patch diff --git a/bjorn-pci-crs-rollup-v3.patch b/bjorn-pci-crs-rollup-v3.patch deleted file mode 100644 index dc9a2c94d..000000000 --- a/bjorn-pci-crs-rollup-v3.patch +++ /dev/null @@ -1,256 +0,0 @@ -commit 023ce8434ec95ef8348bf4ac4068fdd9298bf1d2 -Author: Bjorn Helgaas -Date: Fri Sep 3 16:03:13 2010 -0600 - - x86/PCI: allocate space from the end of a region, not the beginning - - Allocate from the end of a region, not the beginning. - - For example, if we need to allocate 0x800 bytes for a device on bus - 0000:00 given these resources: - - [mem 0xbff00000-0xdfffffff] PCI Bus 0000:00 - [mem 0xc0000000-0xdfffffff] PCI Bus 0000:02 - - the available space at [mem 0xbff00000-0xbfffffff] is passed to the - alignment callback (pcibios_align_resource()). Prior to this patch, we - would put the new 0x800 byte resource at the beginning of that available - space, i.e., at [mem 0xbff00000-0xbff007ff]. - - With this patch, we put it at the end, at [mem 0xbffff800-0xbfffffff]. - - FIXME details about Windows practice - - Signed-off-by: Bjorn Helgaas - -diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c -index 5525309..1ff3e9f 100644 ---- a/arch/x86/pci/i386.c -+++ b/arch/x86/pci/i386.c -@@ -65,7 +65,10 @@ pcibios_align_resource(void *data, const struct resource *res, - resource_size_t size, resource_size_t align) - { - struct pci_dev *dev = data; -- resource_size_t start = res->start; -+ resource_size_t start = ALIGN(res->end - size + 1, align); -+ -+ if (start < res->start) -+ start = res->start; - - if (res->flags & IORESOURCE_IO) { - if (skip_isa_ioresource_align(dev)) -commit 23a85e85345fafcbc5dd5c1fc4868706290ef684 -Author: Bjorn Helgaas -Date: Tue Sep 7 16:33:00 2010 -0600 - - resources: allocate space within a region from the top down - - Allocate space from the top of a region first, then work downward. - - When we allocate space from a resource, we look for gaps between children - of the resource. Previously, we looked at gaps from the bottom up. For - example, given this: - - [mem 0xbff00000-0xf7ffffff] PCI Bus 0000:00 - [mem 0xc0000000-0xdfffffff] PCI Bus 0000:02 - - we attempted to allocate from the [mem 0xbff00000-0xbfffffff] gap first, - then the [mem 0xe0000000-0xf7ffffff] gap. - - With this patch, we allocate from [mem 0xe0000000-0xf7ffffff] first. - - Low addresses are generally scarce, so it's better to use high addresses - when possible. This follows Windows practice for PCI allocation. - - FIXME ref for Windows practice - - Signed-off-by: Bjorn Helgaas - -diff --git a/kernel/resource.c b/kernel/resource.c -index 7b36976..e83ff7c 100644 ---- a/kernel/resource.c -+++ b/kernel/resource.c -@@ -358,6 +358,20 @@ int __weak page_is_ram(unsigned long pfn) - } - - /* -+ * Find the resource before "child" in the sibling list of "root" children. -+ */ -+static struct resource *find_sibling_prev(struct resource *root, struct resource *child) -+{ -+ struct resource *this; -+ -+ for (this = root->child; this; this = this->sibling) -+ if (this->sibling == child) -+ return this; -+ -+ return NULL; -+} -+ -+/* - * Find empty slot in the resource tree given range and alignment. - */ - static int find_resource(struct resource *root, struct resource *new, -@@ -369,23 +383,17 @@ static int find_resource(struct resource *root, struct resource *new, - resource_size_t), - void *alignf_data) - { -- struct resource *this = root->child; -+ struct resource *this; - struct resource tmp = *new; - -- tmp.start = root->start; -- /* -- * Skip past an allocated resource that starts at 0, since the assignment -- * of this->start - 1 to tmp->end below would cause an underflow. -- */ -- if (this && this->start == 0) { -- tmp.start = this->end + 1; -- this = this->sibling; -- } -- for(;;) { -+ tmp.end = root->end; -+ -+ this = find_sibling_prev(root, NULL); -+ for (;;) { - if (this) -- tmp.end = this->start - 1; -+ tmp.start = this->end + 1; - else -- tmp.end = root->end; -+ tmp.start = root->start; - if (tmp.start < min) - tmp.start = min; - if (tmp.end > max) -@@ -398,10 +406,10 @@ static int find_resource(struct resource *root, struct resource *new, - new->end = tmp.start + size - 1; - return 0; - } -- if (!this) -+ if (!this || this->start == root->start) - break; -- tmp.start = this->end + 1; -- this = this->sibling; -+ tmp.end = this->start - 1; -+ this = find_sibling_prev(root, this); - } - return -EBUSY; - } -commit 7e50b2f8590ffe4870e2575c796386c88d006558 -Author: Bjorn Helgaas -Date: Thu Sep 9 12:37:56 2010 -0600 - - PCI: allocate bus resources from the top down - - Allocate space from the highest-address PCI bus resource first, then work - downward. - - Previously, we looked for space in PCI host bridge windows in the order - we discovered the windows. For example, given the following windows - (discovered via an ACPI _CRS method): - - pci_root PNP0A03:00: host bridge window [mem 0x000a0000-0x000bffff] - pci_root PNP0A03:00: host bridge window [mem 0x000c0000-0x000effff] - pci_root PNP0A03:00: host bridge window [mem 0x000f0000-0x000fffff] - pci_root PNP0A03:00: host bridge window [mem 0xbff00000-0xf7ffffff] - pci_root PNP0A03:00: host bridge window [mem 0xff980000-0xff980fff] - pci_root PNP0A03:00: host bridge window [mem 0xff97c000-0xff97ffff] - pci_root PNP0A03:00: host bridge window [mem 0xfed20000-0xfed9ffff] - - we attempted to allocate from [mem 0x000a0000-0x000bffff] first, then - [mem 0x000c0000-0x000effff], and so on. - - With this patch, we allocate from [mem 0xff980000-0xff980fff] first, then - [mem 0xff97c000-0xff97ffff], [mem 0xfed20000-0xfed9ffff], etc. - - Allocating top-down follows Windows practice, so we're less likely to - trip over BIOS defects in the _CRS description. On the machine above, - the [mem 0xbff00000-0xbfffffff] region doesn't actually work and is - likely a BIOS defect. - - Bug: https://bugzilla.kernel.org/show_bug.cgi?id=16228 - Bug: https://bugzilla.redhat.com/show_bug.cgi?id=620313 - Bug: https://bugzilla.redhat.com/show_bug.cgi?id=629933 - - Signed-off-by: Bjorn Helgaas - -diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c -index 7f0af0e..172bf26 100644 ---- a/drivers/pci/bus.c -+++ b/drivers/pci/bus.c -@@ -64,6 +64,49 @@ void pci_bus_remove_resources(struct pci_bus *bus) - } - } - -+/* -+ * Find the highest-address bus resource below the cursor "res". If the -+ * cursor is NULL, return the highest resource. -+ */ -+static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, -+ unsigned int type, -+ struct resource *res) -+{ -+ struct resource *r, *prev = NULL; -+ int i; -+ -+ pci_bus_for_each_resource(bus, r, i) { -+ if (!r) -+ continue; -+ -+ if ((r->flags & IORESOURCE_TYPE_BITS) != type) -+ continue; -+ -+ /* If this resource is at or past the cursor, skip it */ -+ if (res) { -+ if (r == res) -+ continue; -+ if (r->end > res->end) -+ continue; -+ if (r->end == res->end && r->start > res->start) -+ continue; -+ } -+ -+ if (!prev) -+ prev = r; -+ -+ /* -+ * A small resource is higher than a large one that ends at -+ * the same address. -+ */ -+ if (r->end > prev->end || -+ (r->end == prev->end && r->start > prev->start)) -+ prev = r; -+ } -+ -+ return prev; -+} -+ - /** - * pci_bus_alloc_resource - allocate a resource from a parent bus - * @bus: PCI bus -@@ -89,9 +132,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, - resource_size_t), - void *alignf_data) - { -- int i, ret = -ENOMEM; -+ int ret = -ENOMEM; - struct resource *r; - resource_size_t max = -1; -+ unsigned int type = res->flags & IORESOURCE_TYPE_BITS; - - type_mask |= IORESOURCE_IO | IORESOURCE_MEM; - -@@ -99,10 +143,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, - if (!(res->flags & IORESOURCE_MEM_64)) - max = PCIBIOS_MAX_MEM_32; - -- pci_bus_for_each_resource(bus, r, i) { -- if (!r) -- continue; -- -+ /* Look for space at highest addresses first */ -+ r = pci_bus_find_resource_prev(bus, type, NULL); -+ for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) { - /* type_mask must match */ - if ((res->flags ^ r->flags) & type_mask) - continue; diff --git a/kernel.spec b/kernel.spec index 62a4c2176..cccddb135 100644 --- a/kernel.spec +++ b/kernel.spec @@ -23,7 +23,7 @@ Summary: The Linux kernel # # (Uncomment the '#' and both spaces below to set the buildid.) # -%define buildid .bz620313 +# % define buildid .local ################################################################### # The buildid can also be specified on the rpmbuild command line @@ -614,8 +614,6 @@ Patch204: linux-2.6-debug-always-inline-kzalloc.patch Patch300: create-sys-fs-cgroup-to-mount-cgroupfs-on.patch -Patch370: bjorn-pci-crs-rollup-v3.patch - Patch380: linux-2.6-defaults-pci_no_msi.patch Patch381: linux-2.6-defaults-pci_use_crs.patch Patch382: linux-2.6-defaults-no-pm-async.patch @@ -1212,8 +1210,7 @@ ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch # # make default state of PCI MSI a config option ApplyPatch linux-2.6-defaults-pci_no_msi.patch -#ApplyPatch linux-2.6-defaults-pci_use_crs.patch -ApplyPatch bjorn-pci-crs-rollup-v3.patch +ApplyPatch linux-2.6-defaults-pci_use_crs.patch # enable ASPM by default on hardware we expect to work ApplyPatch linux-2.6-defaults-aspm.patch # disable aspm if acpi doesn't provide an _OSC method @@ -1931,9 +1928,6 @@ fi # and build. %changelog -* Fri Sep 10 2010 Kyle McMartin -- Suck in patch from Bjorn to try to fix pci=use_crs - * Fri Sep 10 2010 Chuck Ebbert - Disable asynchronous suspend by default. From ea6d873cc2d9e8111960a7d8ec4c905a8584494d Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 10 Sep 2010 16:11:56 +0100 Subject: [PATCH 049/277] - Update AppleIR patch to work, and support the enter key on newer remotes --- add-appleir-usb-driver.patch | 221 ++++++++++++++++++++++++----------- kernel.spec | 6 +- 2 files changed, 161 insertions(+), 66 deletions(-) diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch index 821d200be..210f289f8 100644 --- a/add-appleir-usb-driver.patch +++ b/add-appleir-usb-driver.patch @@ -1,47 +1,38 @@ -commit 92c912df2a0725d719263357176f98b2201a2acd -Author: Bastien Nocera -Date: Wed Apr 21 14:51:58 2010 +0100 +From e11e9e78799a7641fe0dc5289f35f2604a4b71a3 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Sun, 17 Jan 2010 00:40:15 +0000 +Subject: [PATCH] Input: add appleir USB driver - Input: add appleir USB driver - - This driver was originally written by James McKenzie, updated by - Greg Kroah-Hartman, further updated by myself, with suspend support - added. - - More recent versions of the IR receiver are also supported through - a patch by Alex Karpenko. - - Tested on a MacbookAir1,1 - - Signed-off-by: Bastien Nocera +This driver was originally written by James McKenzie, updated by +Greg Kroah-Hartman, further updated by myself, with suspend support +added. -commit 6ffcbf68913840e9e882db14441576ffee6eba0c -Author: Bastien Nocera -Date: Fri Apr 16 17:19:50 2010 +0100 +More recent versions of the IR receiver are also supported through +a patch by Alex Karpenko. The patch also adds support for the 2nd +and 5th generation of the controller, and the menu key on newer +brushed metal remotes. - Add HID_QUIRK_HIDDEV_FORCE and HID_QUIRK_NO_IGNORE - - Add two quirks to make it possible for usbhid module options to - override whether a device is ignored (HID_QUIRK_NO_IGNORE) and - whether to connect a hiddev device (HID_QUIRK_HIDDEV_FORCE). - - Passing HID_QUIRK_NO_IGNORE for your device means that it will - not be ignored by the HID layer, even if present in a blacklist. - - HID_QUIRK_HIDDEV_FORCE will force the creation of a hiddev for that - device, making it accessible from user-space. - - Tested with an Apple IR Receiver, switching it from using appleir - to using lirc's macmini driver. - - Signed-off-by: Bastien Nocera +Tested on a MacbookAir1,1 + +Signed-off-by: Bastien Nocera +--- + Documentation/input/appleir.txt | 46 ++++ + drivers/hid/hid-apple.c | 4 - + drivers/hid/hid-core.c | 7 +- + drivers/hid/hid-ids.h | 5 +- + drivers/input/misc/Kconfig | 13 + + drivers/input/misc/Makefile | 1 + + drivers/input/misc/appleir.c | 519 +++++++++++++++++++++++++++++++++++++++ + 7 files changed, 588 insertions(+), 7 deletions(-) + create mode 100644 Documentation/input/appleir.txt + create mode 100644 drivers/input/misc/appleir.c diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt new file mode 100644 -index 0000000..0267a4b +index 0000000..db637fb --- /dev/null +++ b/Documentation/input/appleir.txt -@@ -0,0 +1,45 @@ +@@ -0,0 +1,46 @@ +Apple IR receiver Driver (appleir) +---------------------------------- + Copyright (C) 2009 Bastien Nocera @@ -58,7 +49,8 @@ index 0000000..0267a4b +James McKenzie (original driver) +Alex Karpenko (05ac:8242 support) +Greg Kroah-Hartman (cleanups and original submission) -+Bastien Nocera (further cleanups and suspend support) ++Bastien Nocera (further cleanups, brushed metal "enter" ++button support and suspend support) + +Supported hardware +------------------ @@ -66,11 +58,11 @@ index 0000000..0267a4b +- All Apple laptops and desktops from 2005 onwards, except: + - the unibody Macbook (2009) + - Mac Pro (all versions) -+- Apple TV (all revisions) ++- Apple TV (all revisions prior to September 2010) + -+The remote will only support the 6 buttons of the original remotes -+as sold by Apple. See the next section if you want to use other remotes -+or want to use lirc with the device instead of the kernel driver. ++The remote will only support the 6 (old white) or 7 (brushed metal) buttons ++of the remotes as sold by Apple. See the next section if you want to use ++other remotes or want to use lirc with the device instead of the kernel driver. + +Using lirc (native) instead of the kernel driver +------------------------------------------------ @@ -88,10 +80,10 @@ index 0000000..0267a4b +This should force the creation of a hiddev device for the receiver, and +make it usable under lirc. diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index 5b4d66d..b0e1811 100644 +index bba05d0..0059d5a 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c -@@ -353,10 +353,6 @@ static void apple_remove(struct hid_device *hdev) +@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev) } static const struct hid_device_id apple_devices[] = { @@ -102,23 +94,53 @@ index 5b4d66d..b0e1811 100644 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index baa25ad..abc5bd7 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1244,8 +1244,6 @@ static const struct hid_device_id hid_blacklist[] = { + #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE) + { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, + #endif +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, +@@ -1577,6 +1575,11 @@ static const struct hid_device_id hid_ignore_list[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 793691f..9255c1a 100644 +index 11af537..360a5ca 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -93,6 +93,7 @@ +@@ -100,8 +100,11 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +-#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 +#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 - #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 ++#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 ++#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 ++#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 + #define USB_VENDOR_ID_ASUS 0x0486 + #define USB_DEVICE_ID_ASUS_T91MT 0x0185 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index 16ec523..4340986 100644 +index 60de906..2f2f2e7 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig -@@ -149,6 +149,19 @@ config INPUT_KEYSPAN_REMOTE +@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE To compile this driver as a module, choose M here: the module will be called keyspan_remote. @@ -130,7 +152,7 @@ index 16ec523..4340986 100644 + Say Y here if you want to use a Apple infrared remote control. All + the Apple computers from 2005 onwards include such a port, except + the unibody Macbook (2009), and Mac Pros. This receiver is also -+ used in the Apple TV set-top box. ++ used in the Apple TV set-top box prior to the 2010 model. + + To compile this driver as a module, choose M here: the module will + be called appleir. @@ -139,12 +161,12 @@ index 16ec523..4340986 100644 tristate "Griffin PowerMate and Contour Jog support" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index a8b8485..041e6f5 100644 +index 1fe1f6c..d5ef2b9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile -@@ -5,6 +5,7 @@ - obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o - obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o +@@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o + obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o + obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o +obj-$(CONFIG_INPUT_APPLEIR) += appleir.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o @@ -152,10 +174,10 @@ index a8b8485..041e6f5 100644 obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c new file mode 100644 -index 0000000..cff4df6 +index 0000000..3817a3c --- /dev/null +++ b/drivers/input/misc/appleir.c -@@ -0,0 +1,453 @@ +@@ -0,0 +1,519 @@ +/* + * appleir: USB driver for the apple ir device + * @@ -194,12 +216,14 @@ index 0000000..cff4df6 + +#define USB_VENDOR_ID_APPLE 0x05ac +#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 ++#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 ++#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 +#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 ++#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 + +#define URB_SIZE 32 + -+#define MAX_KEYS 8 ++#define MAX_KEYS 9 +#define MAX_KEYS_MASK (MAX_KEYS - 1) + +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) @@ -239,6 +263,13 @@ index 0000000..cff4df6 +/* 25 87 ee 47 02 menu */ +/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */ + ++/* Bastien Nocera's "new" remote */ ++/* 25 87 ee 91 5f followed by ++ * 25 87 ee 91 05 gives you >" ++ * ++ * 25 87 ee 91 5c followed by ++ * 25 87 ee 91 05 gives you the middle button */ ++ +static const unsigned short appleir_key_table[] = { + KEY_RESERVED, + KEY_MENU, @@ -247,6 +278,7 @@ index 0000000..cff4df6 + KEY_BACK, + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, ++ KEY_ENTER, + KEY_RESERVED, +}; + @@ -260,6 +292,7 @@ index 0000000..cff4df6 + struct urb *urb; + struct timer_list key_up_timer; + int current_key; ++ int prev_key_idx; + char phys[32]; +}; + @@ -272,8 +305,10 @@ index 0000000..cff4df6 + +static struct usb_device_id appleir_ids[] = { + { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, + { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, ++ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, + {} +}; +MODULE_DEVICE_TABLE(usb, appleir_ids); @@ -286,7 +321,43 @@ index 0000000..cff4df6 + + for (i = 0; i < len; ++i) + printk(" %02x", data[i]); -+ printk("\n"); ++ printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK); ++} ++ ++static int get_key(int data) ++{ ++ switch (data) { ++ case 0x02: ++ case 0x03: ++ /* menu */ ++ return 1; ++ case 0x04: ++ case 0x05: ++ /* >" */ ++ return 2; ++ case 0x06: ++ case 0x07: ++ /* >> */ ++ return 3; ++ case 0x08: ++ case 0x09: ++ /* << */ ++ return 4; ++ case 0x0a: ++ case 0x0b: ++ /* + */ ++ return 5; ++ case 0x0c: ++ case 0x0d: ++ /* - */ ++ return 6; ++ case 0x5c: ++ /* Middle button, on newer remotes, ++ * part of a 2 packet-command */ ++ return -7; ++ default: ++ return -1; ++ } +} + +static void key_up(struct appleir *appleir, int key) @@ -331,20 +402,37 @@ index 0000000..cff4df6 + return; + + if (!memcmp(data, keydown, sizeof(keydown))) { ++ int index; ++ + /* If we already have a key down, take it up before marking + this one down */ + if (appleir->current_key) + key_up(appleir, appleir->current_key); -+ appleir->current_key = appleir->keymap[(data[4] >> 1) & MAX_KEYS_MASK]; + -+ key_down(appleir, appleir->current_key); -+ /* Remote doesn't do key up, either pull them up, in the test -+ above, or here set a timer which pulls them up after 1/8 s */ -+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); ++ /* Handle dual packet commands */ ++ if (appleir->prev_key_idx > 0) ++ index = appleir->prev_key_idx; ++ else ++ index = get_key(data[4]); + -+ return; ++ if (index > 0) { ++ appleir->current_key = appleir->keymap[index]; ++ ++ key_down(appleir, appleir->current_key); ++ /* Remote doesn't do key up, either pull them up, in the test ++ above, or here set a timer which pulls them up after 1/8 s */ ++ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); ++ appleir->prev_key_idx = 0; ++ return; ++ } else if (index == -7) { ++ /* Remember key for next packet */ ++ appleir->prev_key_idx = 0 - index; ++ return; ++ } + } + ++ appleir->prev_key_idx = 0; ++ + if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) { + key_down(appleir, appleir->current_key); + /* Remote doesn't do key up, either pull them up, in the test @@ -609,3 +697,6 @@ index 0000000..cff4df6 + +module_init(appleir_init); +module_exit(appleir_exit); +-- +1.7.2.2 + diff --git a/kernel.spec b/kernel.spec index cccddb135..c7f8bdd1e 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 23 +%global baserelease 25 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1928,6 +1928,10 @@ fi # and build. %changelog +* Fri Sep 10 2010 Bastien Nocera - 2.6.35.4-25 +- Update AppleIR patch to work, and support the enter key on + newer remotes + * Fri Sep 10 2010 Chuck Ebbert - Disable asynchronous suspend by default. From 9ea075ebba8d1c0cba66c4b47f179005450d7d2b Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 10 Sep 2010 16:42:02 +0100 Subject: [PATCH 050/277] Fix patch application --- add-appleir-usb-driver.patch | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch index 210f289f8..999ee2e69 100644 --- a/add-appleir-usb-driver.patch +++ b/add-appleir-usb-driver.patch @@ -1,6 +1,6 @@ -From e11e9e78799a7641fe0dc5289f35f2604a4b71a3 Mon Sep 17 00:00:00 2001 +From 46fadae732d825141f45bf2fbd6381451da26ad7 Mon Sep 17 00:00:00 2001 From: Bastien Nocera -Date: Sun, 17 Jan 2010 00:40:15 +0000 +Date: Fri, 10 Sep 2010 16:40:46 +0100 Subject: [PATCH] Input: add appleir USB driver This driver was originally written by James McKenzie, updated by @@ -95,19 +95,19 @@ index bba05d0..0059d5a 100644 .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index baa25ad..abc5bd7 100644 +index 866e54e..1d5e284 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c -@@ -1244,8 +1244,6 @@ static const struct hid_device_id hid_blacklist[] = { - #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE) - { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, - #endif +@@ -1239,8 +1239,6 @@ static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, -@@ -1577,6 +1575,11 @@ static const struct hid_device_id hid_ignore_list[] = { +@@ -1571,6 +1569,11 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, @@ -120,10 +120,10 @@ index baa25ad..abc5bd7 100644 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 11af537..360a5ca 100644 +index 31601ee..9afe3bc 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -100,8 +100,11 @@ +@@ -98,8 +98,11 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b @@ -137,10 +137,10 @@ index 11af537..360a5ca 100644 #define USB_VENDOR_ID_ASUS 0x0486 #define USB_DEVICE_ID_ASUS_T91MT 0x0185 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index 60de906..2f2f2e7 100644 +index c44b9ea..76a12b7 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig -@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE +@@ -199,6 +199,19 @@ config INPUT_KEYSPAN_REMOTE To compile this driver as a module, choose M here: the module will be called keyspan_remote. @@ -161,12 +161,12 @@ index 60de906..2f2f2e7 100644 tristate "Griffin PowerMate and Contour Jog support" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index 1fe1f6c..d5ef2b9 100644 +index 71fe57d..62a5c60 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o - obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o - obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o +@@ -9,6 +9,7 @@ obj-$(CONFIG_INPUT_AD714X) += ad714x.o + obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o + obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o +obj-$(CONFIG_INPUT_APPLEIR) += appleir.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o From 17a76a95c4958dbe264bbd1b2cdb84be681fbef8 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 10 Sep 2010 11:57:42 -0400 Subject: [PATCH 051/277] ir-core rebase to current upstream Signed-off-by: Jarod Wilson --- config-generic | 3 + kernel.spec | 6 +- linux-2.6-v4l-dvb-ir-core-update-2.patch | 3989 ++++++++++++++++++++++ 3 files changed, 3997 insertions(+), 1 deletion(-) create mode 100644 linux-2.6-v4l-dvb-ir-core-update-2.patch diff --git a/config-generic b/config-generic index d7269a545..cf8619a71 100644 --- a/config-generic +++ b/config-generic @@ -2582,6 +2582,7 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y # CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set CONFIG_RC_MAP=m +CONFIG_IR_CORE=m CONFIG_IR_NEC_DECODER=m CONFIG_IR_RC5_DECODER=m CONFIG_IR_RC6_DECODER=m @@ -2589,9 +2590,11 @@ CONFIG_IR_JVC_DECODER=m CONFIG_IR_SONY_DECODER=m CONFIG_IR_RC5_SZ_DECODER=m CONFIG_IR_LIRC_CODEC=m +CONFIG_IR_ENE=m CONFIG_IR_IMON=m CONFIG_IR_MCEUSB=m CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set diff --git a/kernel.spec b/kernel.spec index c7f8bdd1e..e4fc6789a 100644 --- a/kernel.spec +++ b/kernel.spec @@ -691,6 +691,7 @@ Patch2914: linux-2.6-v4l-dvb-ir-core-streamzap.patch Patch2915: lirc-staging-2.6.36.patch #Patch2916: lirc-staging-2.6.36-fixes.patch Patch2917: hdpvr-ir-enable.patch +Patch2918: linux-2.6-v4l-dvb-ir-core-update-2.patch Patch3000: linux-2.6-via-velocity-dma-fix.patch @@ -1310,6 +1311,7 @@ ApplyPatch lirc-staging-2.6.36.patch #ApplyOptionalPatch lirc-staging-2.6.36-fixes.patch # enable IR receiver on Hauppauge HD PVR (v4l-dvb merge pending) ApplyPatch hdpvr-ir-enable.patch +ApplyPatch linux-2.6-v4l-dvb-ir-core-update-2.patch # Fix DMA bug on via-velocity ApplyPatch linux-2.6-via-velocity-dma-fix.patch @@ -1341,7 +1343,6 @@ ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch # bz #575873 ApplyPatch flexcop-fix-xlate_proc_name-warning.patch - # END OF PATCH APPLICATIONS %endif @@ -1928,6 +1929,9 @@ fi # and build. %changelog +* Fri Sep 10 2010 Jarod Wilson 2.6.35.4-26 +- ir-core rebase to current upstream + * Fri Sep 10 2010 Bastien Nocera - 2.6.35.4-25 - Update AppleIR patch to work, and support the enter key on newer remotes diff --git a/linux-2.6-v4l-dvb-ir-core-update-2.patch b/linux-2.6-v4l-dvb-ir-core-update-2.patch new file mode 100644 index 000000000..449b496c6 --- /dev/null +++ b/linux-2.6-v4l-dvb-ir-core-update-2.patch @@ -0,0 +1,3989 @@ +diff -Naurp linux-2.6.35/drivers/media/IR/ene_ir.c linux-2.6.35.new/drivers/media/IR/ene_ir.c +--- linux-2.6.35/drivers/media/IR/ene_ir.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/ene_ir.c 2010-09-09 23:21:49.000000000 -0400 +@@ -0,0 +1,1023 @@ ++/* ++ * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX) ++ * ++ * Copyright (C) 2010 Maxim Levitsky ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ * USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ene_ir.h" ++ ++ ++static int sample_period = -1; ++static int enable_idle = 1; ++static int input = 1; ++static int debug; ++static int txsim; ++ ++static int ene_irq_status(struct ene_device *dev); ++ ++/* read a hardware register */ ++static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) ++{ ++ u8 retval; ++ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); ++ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); ++ retval = inb(dev->hw_io + ENE_IO); ++ ++ ene_dbg_verbose("reg %04x == %02x", reg, retval); ++ return retval; ++} ++ ++/* write a hardware register */ ++static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) ++{ ++ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); ++ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); ++ outb(value, dev->hw_io + ENE_IO); ++ ++ ene_dbg_verbose("reg %04x <- %02x", reg, value); ++} ++ ++/* change specific bits in hardware register */ ++static void ene_hw_write_reg_mask(struct ene_device *dev, ++ u16 reg, u8 value, u8 mask) ++{ ++ u8 regvalue; ++ ++ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); ++ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); ++ ++ regvalue = inb(dev->hw_io + ENE_IO) & ~mask; ++ regvalue |= (value & mask); ++ outb(regvalue, dev->hw_io + ENE_IO); ++ ++ ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask); ++} ++ ++/* detect hardware features */ ++static int ene_hw_detect(struct ene_device *dev) ++{ ++ u8 chip_major, chip_minor; ++ u8 hw_revision, old_ver; ++ u8 tmp; ++ u8 fw_capabilities; ++ int pll_freq; ++ ++ tmp = ene_hw_read_reg(dev, ENE_HW_UNK); ++ ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); ++ ++ chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); ++ chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); ++ ++ ene_hw_write_reg(dev, ENE_HW_UNK, tmp); ++ hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); ++ old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); ++ ++ pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) + ++ (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4); ++ ++ if (pll_freq != 1000) ++ dev->rx_period_adjust = 4; ++ else ++ dev->rx_period_adjust = 2; ++ ++ ++ ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq); ++ ++ if (hw_revision == 0xFF) { ++ ++ ene_printk(KERN_WARNING, "device seems to be disabled\n"); ++ ene_printk(KERN_WARNING, ++ "send a mail to lirc-list@lists.sourceforge.net\n"); ++ ene_printk(KERN_WARNING, "please attach output of acpidump\n"); ++ return -ENODEV; ++ } ++ ++ if (chip_major == 0x33) { ++ ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n"); ++ return -ENODEV; ++ } ++ ++ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { ++ dev->hw_revision = ENE_HW_C; ++ } else if (old_ver == 0x24 && hw_revision == 0xC0) { ++ dev->hw_revision = ENE_HW_B; ++ ene_printk(KERN_NOTICE, "KB3926B detected\n"); ++ } else { ++ dev->hw_revision = ENE_HW_D; ++ ene_printk(KERN_WARNING, ++ "unknown ENE chip detected, assuming KB3926D\n"); ++ ene_printk(KERN_WARNING, ++ "driver support might be not complete"); ++ ++ } ++ ++ ene_printk(KERN_DEBUG, ++ "chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n", ++ chip_major, chip_minor, old_ver, hw_revision); ++ ++ /* detect features hardware supports */ ++ if (dev->hw_revision < ENE_HW_C) ++ return 0; ++ ++ fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); ++ ene_dbg("Firmware capabilities: %02x", fw_capabilities); ++ ++ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; ++ dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; ++ ++ dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && ++ (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN); ++ ++ ene_printk(KERN_NOTICE, "hardware features:\n"); ++ ene_printk(KERN_NOTICE, ++ "learning and transmit %s, gpio40_learn %s, fan_in %s\n", ++ dev->hw_learning_and_tx_capable ? "on" : "off", ++ dev->hw_gpio40_learning ? "on" : "off", ++ dev->hw_fan_as_normal_input ? "on" : "off"); ++ ++ if (dev->hw_learning_and_tx_capable) { ++ ene_printk(KERN_WARNING, ++ "Device supports transmitting, but that support is\n"); ++ ene_printk(KERN_WARNING, ++ "lightly tested. Please test it and mail\n"); ++ ene_printk(KERN_WARNING, ++ "lirc-list@lists.sourceforge.net\n"); ++ } ++ return 0; ++} ++ ++/* this enables/disables IR input via gpio40*/ ++static void ene_enable_gpio40_receive(struct ene_device *dev, int enable) ++{ ++ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ? ++ 0 : ENE_CIR_CONF2_GPIO40DIS, ++ ENE_CIR_CONF2_GPIO40DIS); ++} ++ ++/* this enables/disables IR via standard input */ ++static void ene_enable_normal_receive(struct ene_device *dev, int enable) ++{ ++ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0); ++} ++ ++/* this enables/disables IR input via unused fan tachtometer input */ ++static void ene_enable_fan_receive(struct ene_device *dev, int enable) ++{ ++ if (!enable) ++ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); ++ else { ++ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); ++ ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); ++ } ++ dev->rx_fan_input_inuse = enable; ++} ++ ++ ++/* Sense current received carrier */ ++static int ene_rx_sense_carrier(struct ene_device *dev) ++{ ++ int period = ene_hw_read_reg(dev, ENE_RX_CARRIER); ++ int carrier; ++ ene_dbg("RX: hardware carrier period = %02x", period); ++ ++ if (!(period & ENE_RX_CARRIER_VALID)) ++ return 0; ++ ++ period &= ~ENE_RX_CARRIER_VALID; ++ ++ if (!period) ++ return 0; ++ ++ carrier = 2000000 / period; ++ ene_dbg("RX: sensed carrier = %d Hz", carrier); ++ return carrier; ++} ++ ++/* determine which input to use*/ ++static void ene_rx_set_inputs(struct ene_device *dev) ++{ ++ int learning_mode = dev->learning_enabled; ++ ++ ene_dbg("RX: setup receiver, learning mode = %d", learning_mode); ++ ++ ene_enable_normal_receive(dev, 1); ++ ++ /* old hardware doesn't support learning mode for sure */ ++ if (dev->hw_revision <= ENE_HW_B) ++ return; ++ ++ /* receiver not learning capable, still set gpio40 correctly */ ++ if (!dev->hw_learning_and_tx_capable) { ++ ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); ++ return; ++ } ++ ++ /* enable learning mode */ ++ if (learning_mode) { ++ ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning); ++ ++ /* fan input is not used for learning */ ++ if (dev->hw_fan_as_normal_input) ++ ene_enable_fan_receive(dev, 0); ++ ++ /* disable learning mode */ ++ } else { ++ if (dev->hw_fan_as_normal_input) { ++ ene_enable_fan_receive(dev, 1); ++ ene_enable_normal_receive(dev, 0); ++ } else ++ ene_enable_gpio40_receive(dev, ++ !dev->hw_gpio40_learning); ++ } ++ ++ /* set few additional settings for this mode */ ++ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ? ++ ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); ++ ++ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ? ++ ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); ++ ++ if (dev->rx_fan_input_inuse) { ++ dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000; ++ ++ dev->props->timeout = ++ ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000; ++ } else { ++ dev->props->rx_resolution = sample_period * 1000; ++ dev->props->timeout = ENE_MAXGAP * 1000; ++ } ++} ++ ++/* Enable the device for receive */ ++static void ene_rx_enable(struct ene_device *dev) ++{ ++ u8 reg_value; ++ ++ if (dev->hw_revision < ENE_HW_C) { ++ ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); ++ ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); ++ } else { ++ reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; ++ reg_value |= ENEC_IRQ_UNK_EN; ++ reg_value &= ~ENEC_IRQ_STATUS; ++ reg_value |= (dev->irq & ENEC_IRQ_MASK); ++ ene_hw_write_reg(dev, ENEC_IRQ, reg_value); ++ ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); ++ } ++ ++ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); ++ ene_rx_set_inputs(dev); ++ ++ /* set sampling period */ ++ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); ++ ++ /* ack any pending irqs - just in case */ ++ ene_irq_status(dev); ++ ++ /* enable firmware bits */ ++ ene_hw_write_reg_mask(dev, ENE_FW1, ++ ENE_FW1_ENABLE | ENE_FW1_IRQ, ++ ENE_FW1_ENABLE | ENE_FW1_IRQ); ++ ++ /* enter idle mode */ ++ ir_raw_event_set_idle(dev->idev, 1); ++ ir_raw_event_reset(dev->idev); ++ ++} ++ ++/* Disable the device receiver */ ++static void ene_rx_disable(struct ene_device *dev) ++{ ++ /* disable inputs */ ++ ene_enable_normal_receive(dev, 0); ++ ++ if (dev->hw_fan_as_normal_input) ++ ene_enable_fan_receive(dev, 0); ++ ++ /* disable hardware IRQ and firmware flag */ ++ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); ++ ++ ir_raw_event_set_idle(dev->idev, 1); ++ ir_raw_event_reset(dev->idev); ++} ++ ++ ++/* prepare transmission */ ++static void ene_tx_prepare(struct ene_device *dev) ++{ ++ u8 conf1; ++ ++ conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1); ++ dev->saved_conf1 = conf1; ++ ++ if (dev->hw_revision == ENE_HW_C) ++ conf1 &= ~ENE_CIR_CONF1_TX_CLEAR; ++ ++ /* Enable TX engine */ ++ conf1 |= ENE_CIR_CONF1_TX_ON; ++ ++ /* Set carrier */ ++ if (dev->tx_period) { ++ ++ /* NOTE: duty cycle handling is just a guess, it might ++ not be aviable. Default values were tested */ ++ int tx_period_in500ns = dev->tx_period * 2; ++ ++ int tx_pulse_width_in_500ns = ++ tx_period_in500ns / (100 / dev->tx_duty_cycle); ++ ++ if (!tx_pulse_width_in_500ns) ++ tx_pulse_width_in_500ns = 1; ++ ++ ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns); ++ ene_dbg("TX: pulse width = %d * 500 ns", ++ tx_pulse_width_in_500ns); ++ ++ ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT | ++ tx_period_in500ns); ++ ++ ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE, ++ tx_pulse_width_in_500ns); ++ ++ conf1 |= ENE_CIR_CONF1_TX_CARR; ++ } else ++ conf1 &= ~ENE_CIR_CONF1_TX_CARR; ++ ++ ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1); ++ ++} ++ ++/* end transmission */ ++static void ene_tx_complete(struct ene_device *dev) ++{ ++ ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1); ++ dev->tx_buffer = NULL; ++} ++ ++/* set transmit mask */ ++static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev) ++{ ++ u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN; ++ u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN; ++ ++ if (dev->transmitter_mask & 0x01) ++ txport1 |= ENE_TX_PORT1_EN; ++ ++ if (dev->transmitter_mask & 0x02) ++ txport2 |= ENE_TX_PORT2_EN; ++ ++ ene_hw_write_reg(dev, ENE_TX_PORT1, txport1); ++ ene_hw_write_reg(dev, ENE_TX_PORT2, txport2); ++} ++ ++/* TX one sample - must be called with dev->hw_lock*/ ++static void ene_tx_sample(struct ene_device *dev) ++{ ++ u8 raw_tx; ++ u32 sample; ++ ++ if (!dev->tx_buffer) { ++ ene_dbg("TX: attempt to transmit NULL buffer"); ++ return; ++ } ++ ++ /* Grab next TX sample */ ++ if (!dev->tx_sample) { ++again: ++ if (dev->tx_pos == dev->tx_len + 1) { ++ if (!dev->tx_done) { ++ ene_dbg("TX: no more data to send"); ++ dev->tx_done = 1; ++ goto exit; ++ } else { ++ ene_dbg("TX: last sample sent by hardware"); ++ ene_tx_complete(dev); ++ complete(&dev->tx_complete); ++ return; ++ } ++ } ++ ++ sample = dev->tx_buffer[dev->tx_pos++]; ++ dev->tx_sample_pulse = !dev->tx_sample_pulse; ++ ++ ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ? ++ "pulse" : "space"); ++ ++ dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD); ++ ++ /* guard against too short samples */ ++ if (!dev->tx_sample) ++ goto again; ++ } ++ ++ raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK); ++ dev->tx_sample -= raw_tx; ++ ++ if (dev->tx_sample_pulse) ++ raw_tx |= ENE_TX_PULSE_MASK; ++ ++ ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx); ++ dev->tx_reg = !dev->tx_reg; ++exit: ++ /* simulate TX done interrupt */ ++ if (txsim) ++ mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500); ++} ++ ++/* timer to simulate tx done interrupt */ ++static void ene_tx_irqsim(unsigned long data) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ ene_tx_sample(dev); ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++} ++ ++ ++/* read irq status and ack it */ ++static int ene_irq_status(struct ene_device *dev) ++{ ++ u8 irq_status; ++ u8 fw_flags1, fw_flags2; ++ int cur_rx_pointer; ++ int retval = 0; ++ ++ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); ++ cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH); ++ ++ if (dev->hw_revision < ENE_HW_C) { ++ irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); ++ ++ if (!(irq_status & ENEB_IRQ_STATUS_IR)) ++ return 0; ++ ++ ene_hw_write_reg(dev, ENEB_IRQ_STATUS, ++ irq_status & ~ENEB_IRQ_STATUS_IR); ++ dev->rx_pointer = cur_rx_pointer; ++ return ENE_IRQ_RX; ++ } ++ ++ irq_status = ene_hw_read_reg(dev, ENEC_IRQ); ++ ++ if (!(irq_status & ENEC_IRQ_STATUS)) ++ return 0; ++ ++ /* original driver does that twice - a workaround ? */ ++ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); ++ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); ++ ++ /* clear unknown flag in F8F9 */ ++ if (fw_flags2 & ENE_FW2_IRQ_CLR) ++ ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); ++ ++ /* check if this is a TX interrupt */ ++ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); ++ if (fw_flags1 & ENE_FW1_TXIRQ) { ++ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); ++ retval |= ENE_IRQ_TX; ++ } ++ ++ /* Check if this is RX interrupt */ ++ if (dev->rx_pointer != cur_rx_pointer) { ++ retval |= ENE_IRQ_RX; ++ dev->rx_pointer = cur_rx_pointer; ++ ++ } else if (!(retval & ENE_IRQ_TX)) { ++ ene_dbg("RX: interrupt without change in RX pointer(%d)", ++ dev->rx_pointer); ++ retval |= ENE_IRQ_RX; ++ } ++ ++ if ((retval & ENE_IRQ_RX) && (retval & ENE_IRQ_TX)) ++ ene_dbg("both RX and TX interrupt at same time"); ++ ++ return retval; ++} ++ ++/* interrupt handler */ ++static irqreturn_t ene_isr(int irq, void *data) ++{ ++ u16 hw_value; ++ int i, hw_sample; ++ int pulse; ++ int irq_status; ++ unsigned long flags; ++ int carrier = 0; ++ irqreturn_t retval = IRQ_NONE; ++ struct ene_device *dev = (struct ene_device *)data; ++ struct ir_raw_event ev; ++ ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ irq_status = ene_irq_status(dev); ++ ++ if (!irq_status) ++ goto unlock; ++ ++ retval = IRQ_HANDLED; ++ ++ if (irq_status & ENE_IRQ_TX) { ++ ++ if (!dev->hw_learning_and_tx_capable) { ++ ene_dbg("TX interrupt on unsupported device!"); ++ goto unlock; ++ } ++ ene_tx_sample(dev); ++ } ++ ++ if (!(irq_status & ENE_IRQ_RX)) ++ goto unlock; ++ ++ ++ if (dev->carrier_detect_enabled || debug) ++ carrier = ene_rx_sense_carrier(dev); ++#if 0 ++ /* TODO */ ++ if (dev->carrier_detect_enabled && carrier) ++ ir_raw_event_report_frequency(dev->idev, carrier); ++#endif ++ ++ for (i = 0; i < ENE_SAMPLES_SIZE; i++) { ++ hw_value = ene_hw_read_reg(dev, ++ ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i); ++ ++ if (dev->rx_fan_input_inuse) { ++ /* read high part of the sample */ ++ hw_value |= ene_hw_read_reg(dev, ++ ENE_SAMPLE_BUFFER_FAN + ++ dev->rx_pointer * 4 + i) << 8; ++ pulse = hw_value & ENE_FAN_SMPL_PULS_MSK; ++ ++ /* clear space bit, and other unused bits */ ++ hw_value &= ENE_FAN_VALUE_MASK; ++ hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; ++ ++ } else { ++ pulse = !(hw_value & ENE_SAMPLE_SPC_MASK); ++ hw_value &= ENE_SAMPLE_VALUE_MASK; ++ hw_sample = hw_value * sample_period; ++ ++ if (dev->rx_period_adjust) { ++ hw_sample *= (100 - dev->rx_period_adjust); ++ hw_sample /= 100; ++ } ++ } ++ /* no more data */ ++ if (!(hw_value)) ++ break; ++ ++ ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); ++ ++ ++ ev.duration = hw_sample * 1000; ++ ev.pulse = pulse; ++ ir_raw_event_store_with_filter(dev->idev, &ev); ++ } ++ ++ ir_raw_event_handle(dev->idev); ++unlock: ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ return retval; ++} ++ ++/* Initialize default settings */ ++static void ene_setup_settings(struct ene_device *dev) ++{ ++ dev->tx_period = 32; ++ dev->tx_duty_cycle = 25; /*%*/ ++ dev->transmitter_mask = 3; ++ ++ /* Force learning mode if (input == 2), otherwise ++ let user set it with LIRC_SET_REC_CARRIER */ ++ dev->learning_enabled = ++ (input == 2 && dev->hw_learning_and_tx_capable); ++ ++ dev->rx_pointer = -1; ++ ++} ++ ++/* outside interface: called on first open*/ ++static int ene_open(void *data) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ dev->in_use = 1; ++ ene_setup_settings(dev); ++ ene_rx_enable(dev); ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ return 0; ++} ++ ++/* outside interface: called on device close*/ ++static void ene_close(void *data) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ ++ ene_rx_disable(dev); ++ dev->in_use = 0; ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++} ++ ++/* outside interface: set transmitter mask */ ++static int ene_set_tx_mask(void *data, u32 tx_mask) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask); ++ ++ /* invalid txmask */ ++ if (!tx_mask || tx_mask & ~0x3) { ++ ene_dbg("TX: invalid mask"); ++ /* return count of transmitters */ ++ return 2; ++ } ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ dev->transmitter_mask = tx_mask; ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ return 0; ++} ++ ++/* outside interface : set tx carrier */ ++static int ene_set_tx_carrier(void *data, u32 carrier) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */ ++ ++ ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier); ++ ++ if (period && (period > ENE_TX_PERIOD_MAX || ++ period < ENE_TX_PERIOD_MIN)) { ++ ++ ene_dbg("TX: out of range %d-%d carrier, " ++ "falling back to 32 kHz", ++ 1000 / ENE_TX_PERIOD_MIN, ++ 1000 / ENE_TX_PERIOD_MAX); ++ ++ period = 32; /* this is just a coincidence!!! */ ++ } ++ ene_dbg("TX: set carrier to %d kHz", carrier); ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ dev->tx_period = period; ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ return 0; ++} ++ ++ ++/* outside interface: enable learning mode */ ++static int ene_set_learning_mode(void *data, int enable) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ if (enable == dev->learning_enabled) ++ return 0; ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ dev->learning_enabled = enable; ++ ene_rx_set_inputs(dev); ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ return 0; ++} ++ ++/* outside interface: set rec carrier */ ++static int ene_set_rec_carrier(void *data, u32 min, u32 max) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ ene_set_learning_mode(dev, ++ max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW); ++ return 0; ++} ++ ++/* outside interface: enable or disable idle mode */ ++static void ene_rx_set_idle(void *data, int idle) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ ene_dbg("%sabling idle mode", idle ? "en" : "dis"); ++ ++ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, ++ (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW, ++ ENE_CIR_SAMPLE_OVERFLOW); ++} ++ ++ ++/* outside interface: transmit */ ++static int ene_transmit(void *data, int *buf, u32 n) ++{ ++ struct ene_device *dev = (struct ene_device *)data; ++ unsigned long flags; ++ ++ dev->tx_buffer = buf; ++ dev->tx_len = n / sizeof(int); ++ dev->tx_pos = 0; ++ dev->tx_reg = 0; ++ dev->tx_done = 0; ++ dev->tx_sample = 0; ++ dev->tx_sample_pulse = 0; ++ ++ ene_dbg("TX: %d samples", dev->tx_len); ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ ++ ene_tx_hw_set_transmiter_mask(dev); ++ ene_tx_prepare(dev); ++ ++ /* Transmit first two samples */ ++ ene_tx_sample(dev); ++ ene_tx_sample(dev); ++ ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ ++ if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { ++ ene_dbg("TX: timeout"); ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ ene_tx_complete(dev); ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ } else ++ ene_dbg("TX: done"); ++ return n; ++} ++ ++ ++/* probe entry */ ++static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) ++{ ++ int error = -ENOMEM; ++ struct ir_dev_props *ir_props; ++ struct input_dev *input_dev; ++ struct ene_device *dev; ++ ++ /* allocate memory */ ++ input_dev = input_allocate_device(); ++ ir_props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); ++ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); ++ ++ if (!input_dev || !ir_props || !dev) ++ goto error; ++ ++ /* validate resources */ ++ error = -ENODEV; ++ ++ if (!pnp_port_valid(pnp_dev, 0) || ++ pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) ++ goto error; ++ ++ if (!pnp_irq_valid(pnp_dev, 0)) ++ goto error; ++ ++ dev->hw_io = pnp_port_start(pnp_dev, 0); ++ dev->irq = pnp_irq(pnp_dev, 0); ++ spin_lock_init(&dev->hw_lock); ++ ++ /* claim the resources */ ++ error = -EBUSY; ++ if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) ++ goto error; ++ ++ if (request_irq(dev->irq, ene_isr, ++ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) ++ goto error; ++ ++ pnp_set_drvdata(pnp_dev, dev); ++ dev->pnp_dev = pnp_dev; ++ ++ /* detect hardware version and features */ ++ error = ene_hw_detect(dev); ++ if (error) ++ goto error; ++ ++ ene_setup_settings(dev); ++ ++ if (!dev->hw_learning_and_tx_capable && txsim) { ++ dev->hw_learning_and_tx_capable = 1; ++ setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, ++ (long unsigned int)dev); ++ ene_printk(KERN_WARNING, ++ "Simulation of TX activated\n"); ++ } ++ ++ ir_props->driver_type = RC_DRIVER_IR_RAW; ++ ir_props->allowed_protos = IR_TYPE_ALL; ++ ir_props->priv = dev; ++ ir_props->open = ene_open; ++ ir_props->close = ene_close; ++ ir_props->min_timeout = ENE_MINGAP * 1000; ++ ir_props->max_timeout = ENE_MAXGAP * 1000; ++ ir_props->timeout = ENE_MAXGAP * 1000; ++ ++ if (dev->hw_revision == ENE_HW_B) ++ ir_props->s_idle = ene_rx_set_idle; ++ ++ ++ dev->props = ir_props; ++ dev->idev = input_dev; ++ ++ /* don't allow too short/long sample periods */ ++ if (sample_period < 5 || sample_period > 0x7F) ++ sample_period = -1; ++ ++ /* choose default sample period */ ++ if (sample_period == -1) { ++ ++ sample_period = 50; ++ ++ /* on revB, hardware idle mode eats first sample ++ if we set too low sample period */ ++ if (dev->hw_revision == ENE_HW_B && enable_idle) ++ sample_period = 75; ++ } ++ ++ ir_props->rx_resolution = sample_period * 1000; ++ ++ if (dev->hw_learning_and_tx_capable) { ++ ++ ir_props->s_learning_mode = ene_set_learning_mode; ++ ++ if (input == 0) ++ ir_props->s_rx_carrier_range = ene_set_rec_carrier; ++ ++ init_completion(&dev->tx_complete); ++ ir_props->tx_ir = ene_transmit; ++ ir_props->s_tx_mask = ene_set_tx_mask; ++ ir_props->s_tx_carrier = ene_set_tx_carrier; ++ ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000; ++ /* ir_props->s_carrier_report = ene_set_carrier_report; */ ++ } ++ ++ ++ device_set_wakeup_capable(&pnp_dev->dev, 1); ++ device_set_wakeup_enable(&pnp_dev->dev, 1); ++ ++ if (dev->hw_learning_and_tx_capable) ++ input_dev->name = "ENE eHome Infrared Remote Transceiver"; ++ else ++ input_dev->name = "ENE eHome Infrared Remote Receiver"; ++ ++ ++ error = -ENODEV; ++ if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props, ++ ENE_DRIVER_NAME)) ++ goto error; ++ ++ ++ ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); ++ return 0; ++error: ++ if (dev->irq) ++ free_irq(dev->irq, dev); ++ if (dev->hw_io) ++ release_region(dev->hw_io, ENE_MAX_IO); ++ ++ input_free_device(input_dev); ++ kfree(ir_props); ++ kfree(dev); ++ return error; ++} ++ ++/* main unload function */ ++static void ene_remove(struct pnp_dev *pnp_dev) ++{ ++ struct ene_device *dev = pnp_get_drvdata(pnp_dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->hw_lock, flags); ++ ene_rx_disable(dev); ++ spin_unlock_irqrestore(&dev->hw_lock, flags); ++ ++ free_irq(dev->irq, dev); ++ release_region(dev->hw_io, ENE_MAX_IO); ++ ir_input_unregister(dev->idev); ++ kfree(dev->props); ++ kfree(dev); ++} ++ ++/* enable wake on IR (wakes on specific button on original remote) */ ++static void ene_enable_wake(struct ene_device *dev, int enable) ++{ ++ enable = enable && device_may_wakeup(&dev->pnp_dev->dev); ++ ++ ene_dbg("wake on IR %s", enable ? "enabled" : "disabled"); ++ ++ ene_hw_write_reg_mask(dev, ENE_FW1, enable ? ++ ENE_FW1_WAKE : 0, ENE_FW1_WAKE); ++} ++ ++#ifdef CONFIG_PM ++static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) ++{ ++ struct ene_device *dev = pnp_get_drvdata(pnp_dev); ++ ene_enable_wake(dev, 1); ++ return 0; ++} ++ ++static int ene_resume(struct pnp_dev *pnp_dev) ++{ ++ struct ene_device *dev = pnp_get_drvdata(pnp_dev); ++ if (dev->in_use) ++ ene_rx_enable(dev); ++ ++ ene_enable_wake(dev, 0); ++ return 0; ++} ++#endif ++ ++static void ene_shutdown(struct pnp_dev *pnp_dev) ++{ ++ struct ene_device *dev = pnp_get_drvdata(pnp_dev); ++ ene_enable_wake(dev, 1); ++} ++ ++static const struct pnp_device_id ene_ids[] = { ++ {.id = "ENE0100",}, ++ {.id = "ENE0200",}, ++ {.id = "ENE0201",}, ++ {.id = "ENE0202",}, ++ {}, ++}; ++ ++static struct pnp_driver ene_driver = { ++ .name = ENE_DRIVER_NAME, ++ .id_table = ene_ids, ++ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, ++ ++ .probe = ene_probe, ++ .remove = __devexit_p(ene_remove), ++#ifdef CONFIG_PM ++ .suspend = ene_suspend, ++ .resume = ene_resume, ++#endif ++ .shutdown = ene_shutdown, ++}; ++ ++static int __init ene_init(void) ++{ ++ return pnp_register_driver(&ene_driver); ++} ++ ++static void ene_exit(void) ++{ ++ pnp_unregister_driver(&ene_driver); ++} ++ ++module_param(sample_period, int, S_IRUGO); ++MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); ++ ++module_param(enable_idle, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(enable_idle, ++ "Enables turning off signal sampling after long inactivity time; " ++ "if disabled might help detecting input signal (default: enabled)" ++ " (KB3926B only)"); ++ ++module_param(input, bool, S_IRUGO); ++MODULE_PARM_DESC(input, "select which input to use " ++ "0 - auto, 1 - standard, 2 - wideband(KB3926C+)"); ++ ++module_param(debug, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)"); ++ ++module_param(txsim, bool, S_IRUGO); ++MODULE_PARM_DESC(txsim, ++ "Simulate TX features on unsupported hardware (dangerous)"); ++ ++MODULE_DEVICE_TABLE(pnp, ene_ids); ++MODULE_DESCRIPTION ++ ("Infrared input driver for KB3926B/KB3926C/KB3926D " ++ "(aka ENE0100/ENE0200/ENE0201) CIR port"); ++ ++MODULE_AUTHOR("Maxim Levitsky"); ++MODULE_LICENSE("GPL"); ++ ++module_init(ene_init); ++module_exit(ene_exit); +diff -Naurp linux-2.6.35/drivers/media/IR/ene_ir.h linux-2.6.35.new/drivers/media/IR/ene_ir.h +--- linux-2.6.35/drivers/media/IR/ene_ir.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/ene_ir.h 2010-09-09 23:21:49.000000000 -0400 +@@ -0,0 +1,235 @@ ++/* ++ * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX) ++ * ++ * Copyright (C) 2010 Maxim Levitsky ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ * USA ++ */ ++#include ++ ++ ++/* hardware address */ ++#define ENE_STATUS 0 /* hardware status - unused */ ++#define ENE_ADDR_HI 1 /* hi byte of register address */ ++#define ENE_ADDR_LO 2 /* low byte of register address */ ++#define ENE_IO 3 /* read/write window */ ++#define ENE_MAX_IO 4 ++ ++/* 8 bytes of samples, divided in 2 halfs*/ ++#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ ++#define ENE_SAMPLE_SPC_MASK 0x80 /* sample is space */ ++#define ENE_SAMPLE_VALUE_MASK 0x7F ++#define ENE_SAMPLE_OVERFLOW 0x7F ++#define ENE_SAMPLES_SIZE 4 ++ ++/* fan input sample buffer */ ++#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ ++ /* each sample of normal buffer */ ++#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ ++ /* if set, says that sample is pulse */ ++#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ ++ ++/* first firmware register */ ++#define ENE_FW1 0xF8F8 ++#define ENE_FW1_ENABLE 0x01 /* enable fw processing */ ++#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */ ++#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ ++#define ENE_FW1_IRQ 0x80 /* enable interrupt */ ++ ++/* second firmware register */ ++#define ENE_FW2 0xF8F9 ++#define ENE_FW2_BUF_HIGH 0x01 /* which half of the buffer to read */ ++#define ENE_FW2_IRQ_CLR 0x04 /* clear this on IRQ */ ++#define ENE_FW2_GP40_AS_LEARN 0x08 /* normal input is used as */ ++ /* learning input */ ++#define ENE_FW2_FAN_AS_NRML_IN 0x40 /* fan is used as normal input */ ++#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ ++ ++/* transmitter ports */ ++#define ENE_TX_PORT2 0xFC01 /* this enables one or both */ ++#define ENE_TX_PORT2_EN 0x20 /* TX ports */ ++#define ENE_TX_PORT1 0xFC08 ++#define ENE_TX_PORT1_EN 0x02 ++ ++/* IRQ registers block (for revision B) */ ++#define ENEB_IRQ 0xFD09 /* IRQ number */ ++#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ ++#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ ++#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ ++ ++/* fan as input settings - only if learning capable */ ++#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ ++#define ENE_FAN_AS_IN1_EN 0xCD ++#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ ++#define ENE_FAN_AS_IN2_EN 0x03 ++#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ ++ ++/* IRQ registers block (for revision C,D) */ ++#define ENEC_IRQ 0xFE9B /* new irq settings register */ ++#define ENEC_IRQ_MASK 0x0F /* irq number mask */ ++#define ENEC_IRQ_UNK_EN 0x10 /* always enabled */ ++#define ENEC_IRQ_STATUS 0x20 /* irq status and ACK */ ++ ++/* CIR block settings */ ++#define ENE_CIR_CONF1 0xFEC0 ++#define ENE_CIR_CONF1_TX_CLEAR 0x01 /* clear that on revC */ ++ /* while transmitting */ ++#define ENE_CIR_CONF1_RX_ON 0x07 /* normal receiver enabled */ ++#define ENE_CIR_CONF1_LEARN1 0x08 /* enabled on learning mode */ ++#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ ++#define ENE_CIR_CONF1_TX_CARR 0x80 /* send TX carrier or not */ ++ ++#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ ++#define ENE_CIR_CONF2_LEARN2 0x10 /* set on enable learning */ ++#define ENE_CIR_CONF2_GPIO40DIS 0x20 /* disable input via gpio40 */ ++ ++#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ ++#define ENE_CIR_SAMPLE_OVERFLOW 0x80 /* interrupt on overflows if set */ ++ ++ ++/* Two byte tx buffer */ ++#define ENE_TX_INPUT1 0xFEC9 ++#define ENE_TX_INPUT2 0xFECA ++#define ENE_TX_PULSE_MASK 0x80 /* Transmitted sample is pulse */ ++#define ENE_TX_SMLP_MASK 0x7F ++#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period - fixed */ ++ ++ ++/* Unknown TX setting - TX sample period ??? */ ++#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ ++ ++/* Current received carrier period */ ++#define ENE_RX_CARRIER 0xFECC /* RX period (500 ns) */ ++#define ENE_RX_CARRIER_VALID 0x80 /* Register content valid */ ++ ++ ++/* TX period (1/carrier) */ ++#define ENE_TX_PERIOD 0xFECE /* TX period (500 ns) */ ++#define ENE_TX_PERIOD_UNKBIT 0x80 /* This bit set on transmit*/ ++#define ENE_TX_PERIOD_PULSE 0xFECF /* TX pulse period (500 ns)*/ ++ ++/* Hardware versions */ ++#define ENE_HW_VERSION 0xFF00 /* hardware revision */ ++#define ENE_PLLFRH 0xFF16 ++#define ENE_PLLFRL 0xFF17 ++ ++#define ENE_HW_UNK 0xFF1D ++#define ENE_HW_UNK_CLR 0x04 ++#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ ++#define ENE_HW_VER_MINOR 0xFF1F ++#define ENE_HW_VER_OLD 0xFD00 ++ ++/* Normal/Learning carrier ranges - only valid if we have learning input*/ ++/* TODO: test */ ++#define ENE_NORMAL_RX_LOW 34 ++#define ENE_NORMAL_RX_HI 38 ++ ++/* Tx carrier range */ ++/* Hardware might be able to do more, but this range is enough for ++ all purposes */ ++#define ENE_TX_PERIOD_MAX 32 /* corresponds to 29.4 kHz */ ++#define ENE_TX_PERIOD_MIN 16 /* corrsponds to 62.5 kHz */ ++ ++ ++ ++/* Minimal and maximal gaps */ ++ ++/* Normal case: ++ Minimal gap is 0x7F * sample period ++ Maximum gap depends on hardware. ++ For KB3926B, it is unlimited, for newer models its around ++ 250000, after which HW stops sending samples, and that is ++ not possible to change */ ++ ++/* Fan case: ++ Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61 ++ And there is nothing to change this setting ++*/ ++ ++#define ENE_MAXGAP 250000 ++#define ENE_MINGAP (127 * sample_period) ++ ++/******************************************************************************/ ++ ++#define ENE_DRIVER_NAME "ene_ir" ++ ++#define ENE_IRQ_RX 1 ++#define ENE_IRQ_TX 2 ++ ++#define ENE_HW_B 1 /* 3926B */ ++#define ENE_HW_C 2 /* 3926C */ ++#define ENE_HW_D 3 /* 3926D */ ++ ++#define ene_printk(level, text, ...) \ ++ printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) ++ ++#define ene_dbg(text, ...) \ ++ if (debug) \ ++ printk(KERN_DEBUG \ ++ ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__) ++ ++#define ene_dbg_verbose(text, ...) \ ++ if (debug > 1) \ ++ printk(KERN_DEBUG \ ++ ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__) ++ ++ ++struct ene_device { ++ struct pnp_dev *pnp_dev; ++ struct input_dev *idev; ++ struct ir_dev_props *props; ++ int in_use; ++ ++ /* hw IO settings */ ++ unsigned long hw_io; ++ int irq; ++ spinlock_t hw_lock; ++ ++ /* HW features */ ++ int hw_revision; /* hardware revision */ ++ bool hw_learning_and_tx_capable; /* learning capable */ ++ bool hw_gpio40_learning; /* gpio40 is learning */ ++ bool hw_fan_as_normal_input; /* fan input is used as */ ++ /* regular input */ ++ /* HW state*/ ++ int rx_pointer; /* hw pointer to rx buffer */ ++ bool rx_fan_input_inuse; /* is fan input in use for rx*/ ++ int tx_reg; /* current reg used for TX */ ++ u8 saved_conf1; /* saved FEC0 reg */ ++ ++ /* TX sample handling */ ++ unsigned int tx_sample; /* current sample for TX */ ++ bool tx_sample_pulse; /* current sample is pulse */ ++ ++ /* TX buffer */ ++ int *tx_buffer; /* input samples buffer*/ ++ int tx_pos; /* position in that bufer */ ++ int tx_len; /* current len of tx buffer */ ++ int tx_done; /* done transmitting */ ++ /* one more sample pending*/ ++ struct completion tx_complete; /* TX completion */ ++ struct timer_list tx_sim_timer; ++ ++ /* TX settings */ ++ int tx_period; ++ int tx_duty_cycle; ++ int transmitter_mask; ++ ++ /* RX settings */ ++ bool learning_enabled; /* learning input enabled */ ++ bool carrier_detect_enabled; /* carrier detect enabled */ ++ int rx_period_adjust; ++}; +diff -Naurp linux-2.6.35/drivers/media/IR/imon.c linux-2.6.35.new/drivers/media/IR/imon.c +--- linux-2.6.35/drivers/media/IR/imon.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/imon.c 2010-09-09 23:21:42.000000000 -0400 +@@ -406,7 +406,7 @@ static int display_close(struct inode *i + struct imon_context *ictx = NULL; + int retval = 0; + +- ictx = (struct imon_context *)file->private_data; ++ ictx = file->private_data; + + if (!ictx) { + err("%s: no context for device", __func__); +@@ -811,7 +811,7 @@ static ssize_t vfd_write(struct file *fi + const unsigned char vfd_packet6[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; + +- ictx = (struct imon_context *)file->private_data; ++ ictx = file->private_data; + if (!ictx) { + err("%s: no context for device", __func__); + return -ENODEV; +@@ -895,7 +895,7 @@ static ssize_t lcd_write(struct file *fi + int retval = 0; + struct imon_context *ictx; + +- ictx = (struct imon_context *)file->private_data; ++ ictx = file->private_data; + if (!ictx) { + err("%s: no context for device", __func__); + return -ENODEV; +diff -Naurp linux-2.6.35/drivers/media/IR/ir-core-priv.h linux-2.6.35.new/drivers/media/IR/ir-core-priv.h +--- linux-2.6.35/drivers/media/IR/ir-core-priv.h 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-core-priv.h 2010-09-09 23:21:49.000000000 -0400 +@@ -32,7 +32,7 @@ struct ir_raw_handler { + + struct ir_raw_event_ctrl { + struct list_head list; /* to keep track of raw clients */ +- struct work_struct rx_work; /* for the rx decoding workqueue */ ++ struct task_struct *thread; + struct kfifo kfifo; /* fifo for the pulse/space durations */ + ktime_t last_event; /* when last event occurred */ + enum raw_event_type last_type; /* last event type */ +@@ -41,10 +41,13 @@ struct ir_raw_event_ctrl { + + /* raw decoder state follows */ + struct ir_raw_event prev_ev; ++ struct ir_raw_event this_ev; + struct nec_dec { + int state; + unsigned count; + u32 bits; ++ bool is_nec_x; ++ bool necx_repeat; + } nec; + struct rc5_dec { + int state; +@@ -82,7 +85,7 @@ struct ir_raw_event_ctrl { + struct lirc_codec { + struct ir_input_dev *ir_dev; + struct lirc_driver *drv; +- int lircdata; ++ int carrier_low; + } lirc; + }; + +@@ -110,10 +113,9 @@ static inline void decrease_duration(str + ev->duration -= duration; + } + +-#define TO_US(duration) (((duration) + 500) / 1000) ++#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) + #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") + #define IS_RESET(ev) (ev.duration == 0) +- + /* + * Routines from ir-sysfs.c - Meant to be called only internally inside + * ir-core +@@ -132,7 +134,8 @@ int ir_raw_handler_register(struct ir_ra + void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); + void ir_raw_init(void); + +- ++int ir_rcmap_init(void); ++void ir_rcmap_cleanup(void); + /* + * Decoder initialization code + * +diff -Naurp linux-2.6.35/drivers/media/IR/ir-jvc-decoder.c linux-2.6.35.new/drivers/media/IR/ir-jvc-decoder.c +--- linux-2.6.35/drivers/media/IR/ir-jvc-decoder.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-jvc-decoder.c 2010-09-09 23:21:49.000000000 -0400 +@@ -32,6 +32,7 @@ enum jvc_state { + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, ++ STATE_CHECK_REPEAT, + }; + + /** +@@ -60,6 +61,7 @@ static int ir_jvc_decode(struct input_de + IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + ++again: + switch (data->state) { + + case STATE_INACTIVE: +@@ -149,8 +151,18 @@ static int ir_jvc_decode(struct input_de + } + + data->count = 0; +- data->state = STATE_BIT_PULSE; ++ data->state = STATE_CHECK_REPEAT; + return 0; ++ ++ case STATE_CHECK_REPEAT: ++ if (!ev.pulse) ++ break; ++ ++ if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) ++ data->state = STATE_INACTIVE; ++ else ++ data->state = STATE_BIT_PULSE; ++ goto again; + } + + out: +diff -Naurp linux-2.6.35/drivers/media/IR/ir-keytable.c linux-2.6.35.new/drivers/media/IR/ir-keytable.c +--- linux-2.6.35/drivers/media/IR/ir-keytable.c 2010-08-01 18:11:14.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-keytable.c 2010-09-09 23:21:49.000000000 -0400 +@@ -339,6 +339,8 @@ void ir_repeat(struct input_dev *dev) + + spin_lock_irqsave(&ir->keylock, flags); + ++ input_event(dev, EV_MSC, MSC_SCAN, ir->last_scancode); ++ + if (!ir->keypressed) + goto out; + +@@ -370,6 +372,8 @@ void ir_keydown(struct input_dev *dev, i + + spin_lock_irqsave(&ir->keylock, flags); + ++ input_event(dev, EV_MSC, MSC_SCAN, scancode); ++ + /* Repeat event? */ + if (ir->keypressed && + ir->last_scancode == scancode && +@@ -383,9 +387,11 @@ void ir_keydown(struct input_dev *dev, i + ir->last_toggle = toggle; + ir->last_keycode = keycode; + ++ + if (keycode == KEY_RESERVED) + goto out; + ++ + /* Register a keypress */ + ir->keypressed = true; + IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", +@@ -428,7 +434,7 @@ static void ir_close(struct input_dev *i + */ + int __ir_input_register(struct input_dev *input_dev, + const struct ir_scancode_table *rc_tab, +- const struct ir_dev_props *props, ++ struct ir_dev_props *props, + const char *driver_name) + { + struct ir_input_dev *ir_dev; +@@ -480,6 +486,8 @@ int __ir_input_register(struct input_dev + + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_REP, input_dev->evbit); ++ set_bit(EV_MSC, input_dev->evbit); ++ set_bit(MSC_SCAN, input_dev->mscbit); + + if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) { + rc = -ENOMEM; +@@ -497,8 +505,10 @@ int __ir_input_register(struct input_dev + goto out_event; + } + +- IR_dprintk(1, "Registered input device on %s for %s remote.\n", +- driver_name, rc_tab->name); ++ IR_dprintk(1, "Registered input device on %s for %s remote%s.\n", ++ driver_name, rc_tab->name, ++ (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ? ++ " in raw mode" : ""); + + return 0; + +diff -Naurp linux-2.6.35/drivers/media/IR/ir-lirc-codec.c linux-2.6.35.new/drivers/media/IR/ir-lirc-codec.c +--- linux-2.6.35/drivers/media/IR/ir-lirc-codec.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-lirc-codec.c 2010-09-09 23:21:49.000000000 -0400 +@@ -32,6 +32,7 @@ + static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ int sample; + + if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) + return 0; +@@ -39,18 +40,20 @@ static int ir_lirc_decode(struct input_d + if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) + return -EINVAL; + ++ if (IS_RESET(ev)) ++ return 0; ++ + IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", + TO_US(ev.duration), TO_STR(ev.pulse)); + +- ir_dev->raw->lirc.lircdata += ev.duration / 1000; ++ sample = ev.duration / 1000; + if (ev.pulse) +- ir_dev->raw->lirc.lircdata |= PULSE_BIT; ++ sample |= PULSE_BIT; + + lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, +- (unsigned char *) &ir_dev->raw->lirc.lircdata); ++ (unsigned char *) &sample); + wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); + +- ir_dev->raw->lirc.lircdata = 0; + + return 0; + } +@@ -74,14 +77,9 @@ static ssize_t ir_lirc_transmit_ir(struc + if (count > LIRCBUF_SIZE || count % 2 == 0) + return -EINVAL; + +- txbuf = kzalloc(sizeof(int) * LIRCBUF_SIZE, GFP_KERNEL); +- if (!txbuf) +- return -ENOMEM; +- +- if (copy_from_user(txbuf, buf, n)) { +- ret = -EFAULT; +- goto out; +- } ++ txbuf = memdup_user(buf, n); ++ if (IS_ERR(txbuf)) ++ return PTR_ERR(txbuf); + + ir_dev = lirc->ir_dev; + if (!ir_dev) { +@@ -97,13 +95,14 @@ out: + return ret; + } + +-static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, ++ unsigned long __user arg) + { + struct lirc_codec *lirc; + struct ir_input_dev *ir_dev; + int ret = 0; + void *drv_data; +- unsigned long val; ++ unsigned long val = 0; + + lirc = lirc_get_pdata(filep); + if (!lirc) +@@ -115,47 +114,106 @@ static long ir_lirc_ioctl(struct file *f + + drv_data = ir_dev->props->priv; + +- switch (cmd) { +- case LIRC_SET_TRANSMITTER_MASK: ++ if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = get_user(val, (unsigned long *)arg); + if (ret) + return ret; ++ } ++ ++ switch (cmd) { ++ ++ /* legacy support */ ++ case LIRC_GET_SEND_MODE: ++ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; ++ break; + +- if (ir_dev->props && ir_dev->props->s_tx_mask) ++ case LIRC_SET_SEND_MODE: ++ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) ++ return -EINVAL; ++ break; ++ ++ /* TX settings */ ++ case LIRC_SET_TRANSMITTER_MASK: ++ if (ir_dev->props->s_tx_mask) + ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); + else + return -EINVAL; + break; + + case LIRC_SET_SEND_CARRIER: +- ret = get_user(val, (unsigned long *)arg); +- if (ret) +- return ret; +- +- if (ir_dev->props && ir_dev->props->s_tx_carrier) ++ if (ir_dev->props->s_tx_carrier) + ir_dev->props->s_tx_carrier(drv_data, (u32)val); + else + return -EINVAL; + break; + +- case LIRC_GET_SEND_MODE: +- val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; +- ret = put_user(val, (unsigned long *)arg); ++ case LIRC_SET_SEND_DUTY_CYCLE: ++ if (!ir_dev->props->s_tx_duty_cycle) ++ return -ENOSYS; ++ ++ if (val <= 0 || val >= 100) ++ return -EINVAL; ++ ++ ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val); + break; + +- case LIRC_SET_SEND_MODE: +- ret = get_user(val, (unsigned long *)arg); +- if (ret) +- return ret; ++ /* RX settings */ ++ case LIRC_SET_REC_CARRIER: ++ if (ir_dev->props->s_rx_carrier_range) ++ ret = ir_dev->props->s_rx_carrier_range( ++ ir_dev->props->priv, ++ ir_dev->raw->lirc.carrier_low, val); ++ else ++ return -ENOSYS; + +- if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) ++ if (!ret) ++ ir_dev->raw->lirc.carrier_low = 0; ++ break; ++ ++ case LIRC_SET_REC_CARRIER_RANGE: ++ if (val >= 0) ++ ir_dev->raw->lirc.carrier_low = val; ++ break; ++ ++ ++ case LIRC_GET_REC_RESOLUTION: ++ val = ir_dev->props->rx_resolution; ++ break; ++ ++ case LIRC_SET_WIDEBAND_RECEIVER: ++ if (ir_dev->props->s_learning_mode) ++ return ir_dev->props->s_learning_mode( ++ ir_dev->props->priv, !!val); ++ else ++ return -ENOSYS; ++ ++ /* Generic timeout support */ ++ case LIRC_GET_MIN_TIMEOUT: ++ if (!ir_dev->props->max_timeout) ++ return -ENOSYS; ++ val = ir_dev->props->min_timeout / 1000; ++ break; ++ ++ case LIRC_GET_MAX_TIMEOUT: ++ if (!ir_dev->props->max_timeout) ++ return -ENOSYS; ++ val = ir_dev->props->max_timeout / 1000; ++ break; ++ ++ case LIRC_SET_REC_TIMEOUT: ++ if (val < ir_dev->props->min_timeout || ++ val > ir_dev->props->max_timeout) + return -EINVAL; ++ ir_dev->props->timeout = val * 1000; + break; + + default: + return lirc_dev_fop_ioctl(filep, cmd, arg); + } + ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ ret = put_user(val, (unsigned long *)arg); ++ + return ret; + } + +@@ -192,7 +250,7 @@ static int ir_lirc_register(struct input + return rc; + + rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); +- if (!drv) ++ if (!rbuf) + goto rbuf_alloc_failed; + + rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); +@@ -201,13 +259,28 @@ static int ir_lirc_register(struct input + + features = LIRC_CAN_REC_MODE2; + if (ir_dev->props->tx_ir) { ++ + features |= LIRC_CAN_SEND_PULSE; + if (ir_dev->props->s_tx_mask) + features |= LIRC_CAN_SET_TRANSMITTER_MASK; + if (ir_dev->props->s_tx_carrier) + features |= LIRC_CAN_SET_SEND_CARRIER; ++ ++ if (ir_dev->props->s_tx_duty_cycle) ++ features |= LIRC_CAN_SET_REC_DUTY_CYCLE; + } + ++ if (ir_dev->props->s_rx_carrier_range) ++ features |= LIRC_CAN_SET_REC_CARRIER | ++ LIRC_CAN_SET_REC_CARRIER_RANGE; ++ ++ if (ir_dev->props->s_learning_mode) ++ features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; ++ ++ if (ir_dev->props->max_timeout) ++ features |= LIRC_CAN_SET_REC_TIMEOUT; ++ ++ + snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", + ir_dev->driver_name); + drv->minor = -1; +@@ -229,8 +302,6 @@ static int ir_lirc_register(struct input + + ir_dev->raw->lirc.drv = drv; + ir_dev->raw->lirc.ir_dev = ir_dev; +- ir_dev->raw->lirc.lircdata = PULSE_MASK; +- + return 0; + + lirc_register_failed: +diff -Naurp linux-2.6.35/drivers/media/IR/ir-nec-decoder.c linux-2.6.35.new/drivers/media/IR/ir-nec-decoder.c +--- linux-2.6.35/drivers/media/IR/ir-nec-decoder.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-nec-decoder.c 2010-09-09 23:21:49.000000000 -0400 +@@ -20,12 +20,13 @@ + #define NEC_HEADER_PULSE (16 * NEC_UNIT) + #define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */ + #define NEC_HEADER_SPACE (8 * NEC_UNIT) +-#define NEC_REPEAT_SPACE (8 * NEC_UNIT) ++#define NEC_REPEAT_SPACE (4 * NEC_UNIT) + #define NEC_BIT_PULSE (1 * NEC_UNIT) + #define NEC_BIT_0_SPACE (1 * NEC_UNIT) + #define NEC_BIT_1_SPACE (3 * NEC_UNIT) + #define NEC_TRAILER_PULSE (1 * NEC_UNIT) + #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ ++#define NECX_REPEAT_BITS 1 + + enum nec_state { + STATE_INACTIVE, +@@ -67,8 +68,12 @@ static int ir_nec_decode(struct input_de + if (!ev.pulse) + break; + +- if (!eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2) && +- !eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2)) ++ if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) { ++ data->is_nec_x = false; ++ data->necx_repeat = false; ++ } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2)) ++ data->is_nec_x = true; ++ else + break; + + data->count = 0; +@@ -105,6 +110,17 @@ static int ir_nec_decode(struct input_de + if (ev.pulse) + break; + ++ if (data->necx_repeat && data->count == NECX_REPEAT_BITS && ++ geq_margin(ev.duration, ++ NEC_TRAILER_SPACE, NEC_UNIT / 2)) { ++ IR_dprintk(1, "Repeat last key\n"); ++ ir_repeat(input_dev); ++ data->state = STATE_INACTIVE; ++ return 0; ++ ++ } else if (data->count > NECX_REPEAT_BITS) ++ data->necx_repeat = false; ++ + data->bits <<= 1; + if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) + data->bits |= 1; +@@ -159,6 +175,9 @@ static int ir_nec_decode(struct input_de + IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); + } + ++ if (data->is_nec_x) ++ data->necx_repeat = true; ++ + ir_keydown(input_dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; +diff -Naurp linux-2.6.35/drivers/media/IR/ir-raw-event.c linux-2.6.35.new/drivers/media/IR/ir-raw-event.c +--- linux-2.6.35/drivers/media/IR/ir-raw-event.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-raw-event.c 2010-09-09 23:21:49.000000000 -0400 +@@ -12,9 +12,10 @@ + * GNU General Public License for more details. + */ + +-#include +-#include ++#include ++#include + #include ++#include + #include "ir-core-priv.h" + + /* Define the max number of pulse/space transitions to buffer */ +@@ -24,7 +25,7 @@ + static LIST_HEAD(ir_raw_client_list); + + /* Used to handle IR raw handler extensions */ +-static DEFINE_SPINLOCK(ir_raw_handler_lock); ++static DEFINE_MUTEX(ir_raw_handler_lock); + static LIST_HEAD(ir_raw_handler_list); + static u64 available_protocols; + +@@ -33,20 +34,30 @@ static u64 available_protocols; + static struct work_struct wq_load; + #endif + +-static void ir_raw_event_work(struct work_struct *work) ++static int ir_raw_event_thread(void *data) + { + struct ir_raw_event ev; + struct ir_raw_handler *handler; +- struct ir_raw_event_ctrl *raw = +- container_of(work, struct ir_raw_event_ctrl, rx_work); ++ struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; + +- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { +- spin_lock(&ir_raw_handler_lock); +- list_for_each_entry(handler, &ir_raw_handler_list, list) +- handler->decode(raw->input_dev, ev); +- spin_unlock(&ir_raw_handler_lock); +- raw->prev_ev = ev; ++ while (!kthread_should_stop()) { ++ try_to_freeze(); ++ ++ mutex_lock(&ir_raw_handler_lock); ++ ++ while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { ++ list_for_each_entry(handler, &ir_raw_handler_list, list) ++ handler->decode(raw->input_dev, ev); ++ raw->prev_ev = ev; ++ } ++ ++ mutex_unlock(&ir_raw_handler_lock); ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); + } ++ ++ return 0; + } + + /** +@@ -66,6 +77,9 @@ int ir_raw_event_store(struct input_dev + if (!ir->raw) + return -EINVAL; + ++ IR_dprintk(2, "sample: (05%dus %s)\n", ++ TO_US(ev->duration), TO_STR(ev->pulse)); ++ + if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) + return -ENOMEM; + +@@ -126,6 +140,90 @@ int ir_raw_event_store_edge(struct input + EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); + + /** ++ * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing ++ * @input_dev: the struct input_dev device descriptor ++ * @type: the type of the event that has occurred ++ * ++ * This routine (which may be called from an interrupt context) works ++ * in similiar manner to ir_raw_event_store_edge. ++ * This routine is intended for devices with limited internal buffer ++ * It automerges samples of same type, and handles timeouts ++ */ ++int ir_raw_event_store_with_filter(struct input_dev *input_dev, ++ struct ir_raw_event *ev) ++{ ++ struct ir_input_dev *ir = input_get_drvdata(input_dev); ++ struct ir_raw_event_ctrl *raw = ir->raw; ++ ++ if (!raw || !ir->props) ++ return -EINVAL; ++ ++ /* Ignore spaces in idle mode */ ++ if (ir->idle && !ev->pulse) ++ return 0; ++ else if (ir->idle) ++ ir_raw_event_set_idle(input_dev, 0); ++ ++ if (!raw->this_ev.duration) { ++ raw->this_ev = *ev; ++ } else if (ev->pulse == raw->this_ev.pulse) { ++ raw->this_ev.duration += ev->duration; ++ } else { ++ ir_raw_event_store(input_dev, &raw->this_ev); ++ raw->this_ev = *ev; ++ } ++ ++ /* Enter idle mode if nessesary */ ++ if (!ev->pulse && ir->props->timeout && ++ raw->this_ev.duration >= ir->props->timeout) ++ ir_raw_event_set_idle(input_dev, 1); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); ++ ++void ir_raw_event_set_idle(struct input_dev *input_dev, int idle) ++{ ++ struct ir_input_dev *ir = input_get_drvdata(input_dev); ++ struct ir_raw_event_ctrl *raw = ir->raw; ++ ktime_t now; ++ u64 delta; ++ ++ if (!ir->props) ++ return; ++ ++ if (!ir->raw) ++ goto out; ++ ++ if (idle) { ++ IR_dprintk(2, "enter idle mode\n"); ++ raw->last_event = ktime_get(); ++ } else { ++ IR_dprintk(2, "exit idle mode\n"); ++ ++ now = ktime_get(); ++ delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event)); ++ ++ WARN_ON(raw->this_ev.pulse); ++ ++ raw->this_ev.duration = ++ min(raw->this_ev.duration + delta, ++ (u64)IR_MAX_DURATION); ++ ++ ir_raw_event_store(input_dev, &raw->this_ev); ++ ++ if (raw->this_ev.duration == IR_MAX_DURATION) ++ ir_raw_event_reset(input_dev); ++ ++ raw->this_ev.duration = 0; ++ } ++out: ++ if (ir->props->s_idle) ++ ir->props->s_idle(ir->props->priv, idle); ++ ir->idle = idle; ++} ++EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); ++ ++/** + * ir_raw_event_handle() - schedules the decoding of stored ir data + * @input_dev: the struct input_dev device descriptor + * +@@ -138,7 +236,7 @@ void ir_raw_event_handle(struct input_de + if (!ir->raw) + return; + +- schedule_work(&ir->raw->rx_work); ++ wake_up_process(ir->raw->thread); + } + EXPORT_SYMBOL_GPL(ir_raw_event_handle); + +@@ -147,9 +245,9 @@ u64 + ir_raw_get_allowed_protocols() + { + u64 protocols; +- spin_lock(&ir_raw_handler_lock); ++ mutex_lock(&ir_raw_handler_lock); + protocols = available_protocols; +- spin_unlock(&ir_raw_handler_lock); ++ mutex_unlock(&ir_raw_handler_lock); + return protocols; + } + +@@ -167,7 +265,7 @@ int ir_raw_event_register(struct input_d + return -ENOMEM; + + ir->raw->input_dev = input_dev; +- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); ++ + ir->raw->enabled_protocols = ~0; + rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, + GFP_KERNEL); +@@ -177,12 +275,23 @@ int ir_raw_event_register(struct input_d + return rc; + } + +- spin_lock(&ir_raw_handler_lock); ++ ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw, ++ "rc%u", (unsigned int)ir->devno); ++ ++ if (IS_ERR(ir->raw->thread)) { ++ int ret = PTR_ERR(ir->raw->thread); ++ ++ kfree(ir->raw); ++ ir->raw = NULL; ++ return ret; ++ } ++ ++ mutex_lock(&ir_raw_handler_lock); + list_add_tail(&ir->raw->list, &ir_raw_client_list); + list_for_each_entry(handler, &ir_raw_handler_list, list) + if (handler->raw_register) + handler->raw_register(ir->raw->input_dev); +- spin_unlock(&ir_raw_handler_lock); ++ mutex_unlock(&ir_raw_handler_lock); + + return 0; + } +@@ -195,14 +304,14 @@ void ir_raw_event_unregister(struct inpu + if (!ir->raw) + return; + +- cancel_work_sync(&ir->raw->rx_work); ++ kthread_stop(ir->raw->thread); + +- spin_lock(&ir_raw_handler_lock); ++ mutex_lock(&ir_raw_handler_lock); + list_del(&ir->raw->list); + list_for_each_entry(handler, &ir_raw_handler_list, list) + if (handler->raw_unregister) + handler->raw_unregister(ir->raw->input_dev); +- spin_unlock(&ir_raw_handler_lock); ++ mutex_unlock(&ir_raw_handler_lock); + + kfifo_free(&ir->raw->kfifo); + kfree(ir->raw); +@@ -217,13 +326,13 @@ int ir_raw_handler_register(struct ir_ra + { + struct ir_raw_event_ctrl *raw; + +- spin_lock(&ir_raw_handler_lock); ++ mutex_lock(&ir_raw_handler_lock); + list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); + if (ir_raw_handler->raw_register) + list_for_each_entry(raw, &ir_raw_client_list, list) + ir_raw_handler->raw_register(raw->input_dev); + available_protocols |= ir_raw_handler->protocols; +- spin_unlock(&ir_raw_handler_lock); ++ mutex_unlock(&ir_raw_handler_lock); + + return 0; + } +@@ -233,13 +342,13 @@ void ir_raw_handler_unregister(struct ir + { + struct ir_raw_event_ctrl *raw; + +- spin_lock(&ir_raw_handler_lock); ++ mutex_lock(&ir_raw_handler_lock); + list_del(&ir_raw_handler->list); + if (ir_raw_handler->raw_unregister) + list_for_each_entry(raw, &ir_raw_client_list, list) + ir_raw_handler->raw_unregister(raw->input_dev); + available_protocols &= ~ir_raw_handler->protocols; +- spin_unlock(&ir_raw_handler_lock); ++ mutex_unlock(&ir_raw_handler_lock); + } + EXPORT_SYMBOL(ir_raw_handler_unregister); + +diff -Naurp linux-2.6.35/drivers/media/IR/ir-sysfs.c linux-2.6.35.new/drivers/media/IR/ir-sysfs.c +--- linux-2.6.35/drivers/media/IR/ir-sysfs.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/ir-sysfs.c 2010-09-09 23:21:49.000000000 -0400 +@@ -33,6 +33,22 @@ static struct class ir_input_class = { + .devnode = ir_devnode, + }; + ++static struct { ++ u64 type; ++ char *name; ++} proto_names[] = { ++ { IR_TYPE_UNKNOWN, "unknown" }, ++ { IR_TYPE_RC5, "rc-5" }, ++ { IR_TYPE_NEC, "nec" }, ++ { IR_TYPE_RC6, "rc-6" }, ++ { IR_TYPE_JVC, "jvc" }, ++ { IR_TYPE_SONY, "sony" }, ++ { IR_TYPE_RC5_SZ, "rc-5-sz" }, ++ { IR_TYPE_LIRC, "lirc" }, ++}; ++ ++#define PROTO_NONE "none" ++ + /** + * show_protocols() - shows the current IR protocol(s) + * @d: the device descriptor +@@ -50,6 +66,7 @@ static ssize_t show_protocols(struct dev + struct ir_input_dev *ir_dev = dev_get_drvdata(d); + u64 allowed, enabled; + char *tmp = buf; ++ int i; + + if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { + enabled = ir_dev->rc_tab.ir_type; +@@ -63,45 +80,12 @@ static ssize_t show_protocols(struct dev + (long long)allowed, + (long long)enabled); + +- if (allowed & enabled & IR_TYPE_UNKNOWN) +- tmp += sprintf(tmp, "[unknown] "); +- else if (allowed & IR_TYPE_UNKNOWN) +- tmp += sprintf(tmp, "unknown "); +- +- if (allowed & enabled & IR_TYPE_RC5) +- tmp += sprintf(tmp, "[rc5] "); +- else if (allowed & IR_TYPE_RC5) +- tmp += sprintf(tmp, "rc5 "); +- +- if (allowed & enabled & IR_TYPE_NEC) +- tmp += sprintf(tmp, "[nec] "); +- else if (allowed & IR_TYPE_NEC) +- tmp += sprintf(tmp, "nec "); +- +- if (allowed & enabled & IR_TYPE_RC6) +- tmp += sprintf(tmp, "[rc6] "); +- else if (allowed & IR_TYPE_RC6) +- tmp += sprintf(tmp, "rc6 "); +- +- if (allowed & enabled & IR_TYPE_JVC) +- tmp += sprintf(tmp, "[jvc] "); +- else if (allowed & IR_TYPE_JVC) +- tmp += sprintf(tmp, "jvc "); +- +- if (allowed & enabled & IR_TYPE_SONY) +- tmp += sprintf(tmp, "[sony] "); +- else if (allowed & IR_TYPE_SONY) +- tmp += sprintf(tmp, "sony "); +- +- if (allowed & enabled & IR_TYPE_RC5_SZ) +- tmp += sprintf(tmp, "[rc5sz] "); +- else if (allowed & IR_TYPE_RC5_SZ) +- tmp += sprintf(tmp, "rc5sz "); +- +- if (allowed & enabled & IR_TYPE_LIRC) +- tmp += sprintf(tmp, "[lirc] "); +- else if (allowed & IR_TYPE_LIRC) +- tmp += sprintf(tmp, "lirc "); ++ for (i = 0; i < ARRAY_SIZE(proto_names); i++) { ++ if (allowed & enabled & proto_names[i].type) ++ tmp += sprintf(tmp, "[%s] ", proto_names[i].name); ++ else if (allowed & proto_names[i].type) ++ tmp += sprintf(tmp, "%s ", proto_names[i].name); ++ } + + if (tmp != buf) + tmp--; +@@ -121,6 +105,7 @@ static ssize_t show_protocols(struct dev + * Writing "+proto" will add a protocol to the list of enabled protocols. + * Writing "-proto" will remove a protocol from the list of enabled protocols. + * Writing "proto" will enable only "proto". ++ * Writing "none" will disable all protocols. + * Returns -EINVAL if an invalid protocol combination or unknown protocol name + * is used, otherwise @len. + */ +@@ -134,71 +119,63 @@ static ssize_t store_protocols(struct de + const char *tmp; + u64 type; + u64 mask; +- int rc; ++ int rc, i, count = 0; + unsigned long flags; + +- tmp = skip_spaces(data); ++ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) ++ type = ir_dev->rc_tab.ir_type; ++ else ++ type = ir_dev->raw->enabled_protocols; + +- if (*tmp == '+') { +- enable = true; +- disable = false; +- tmp++; +- } else if (*tmp == '-') { +- enable = false; +- disable = true; +- tmp++; +- } else { +- enable = false; +- disable = false; +- } ++ while ((tmp = strsep((char **) &data, " \n")) != NULL) { ++ if (!*tmp) ++ break; ++ ++ if (*tmp == '+') { ++ enable = true; ++ disable = false; ++ tmp++; ++ } else if (*tmp == '-') { ++ enable = false; ++ disable = true; ++ tmp++; ++ } else { ++ enable = false; ++ disable = false; ++ } + +- if (!strncasecmp(tmp, "unknown", 7)) { +- tmp += 7; +- mask = IR_TYPE_UNKNOWN; +- } else if (!strncasecmp(tmp, "rc5", 3)) { +- tmp += 3; +- mask = IR_TYPE_RC5; +- } else if (!strncasecmp(tmp, "nec", 3)) { +- tmp += 3; +- mask = IR_TYPE_NEC; +- } else if (!strncasecmp(tmp, "rc6", 3)) { +- tmp += 3; +- mask = IR_TYPE_RC6; +- } else if (!strncasecmp(tmp, "jvc", 3)) { +- tmp += 3; +- mask = IR_TYPE_JVC; +- } else if (!strncasecmp(tmp, "sony", 4)) { +- tmp += 4; +- mask = IR_TYPE_SONY; +- } else if (!strncasecmp(tmp, "rc5sz", 5)) { +- tmp += 5; +- mask = IR_TYPE_RC5_SZ; +- } else if (!strncasecmp(tmp, "lirc", 4)) { +- tmp += 4; +- mask = IR_TYPE_LIRC; +- } else { +- IR_dprintk(1, "Unknown protocol\n"); +- return -EINVAL; ++ if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) { ++ tmp += sizeof(PROTO_NONE); ++ mask = 0; ++ count++; ++ } else { ++ for (i = 0; i < ARRAY_SIZE(proto_names); i++) { ++ if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) { ++ tmp += strlen(proto_names[i].name); ++ mask = proto_names[i].type; ++ break; ++ } ++ } ++ if (i == ARRAY_SIZE(proto_names)) { ++ IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); ++ return -EINVAL; ++ } ++ count++; ++ } ++ ++ if (enable) ++ type |= mask; ++ else if (disable) ++ type &= ~mask; ++ else ++ type = mask; + } + +- tmp = skip_spaces(tmp); +- if (*tmp != '\0') { +- IR_dprintk(1, "Invalid trailing characters\n"); ++ if (!count) { ++ IR_dprintk(1, "Protocol not specified\n"); + return -EINVAL; + } + +- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) +- type = ir_dev->rc_tab.ir_type; +- else +- type = ir_dev->raw->enabled_protocols; +- +- if (enable) +- type |= mask; +- else if (disable) +- type &= ~mask; +- else +- type = mask; +- + if (ir_dev->props && ir_dev->props->change_protocol) { + rc = ir_dev->props->change_protocol(ir_dev->props->priv, + type); +@@ -217,7 +194,6 @@ static ssize_t store_protocols(struct de + ir_dev->raw->enabled_protocols = type; + } + +- + IR_dprintk(1, "Current protocol(s): 0x%llx\n", + (long long)type); + +@@ -286,6 +262,7 @@ int ir_register_class(struct input_dev * + return devno; + + ir_dev->dev.type = &rc_dev_type; ++ + ir_dev->dev.class = &ir_input_class; + ir_dev->dev.parent = input_dev->dev.parent; + dev_set_name(&ir_dev->dev, "rc%d", devno); +@@ -349,6 +326,7 @@ static int __init ir_core_init(void) + + /* Initialize/load the decoders/keymap code that will be used */ + ir_raw_init(); ++ ir_rcmap_init(); + + return 0; + } +@@ -356,6 +334,7 @@ static int __init ir_core_init(void) + static void __exit ir_core_exit(void) + { + class_unregister(&ir_input_class); ++ ir_rcmap_cleanup(); + } + + module_init(ir_core_init); +diff -Naurp linux-2.6.35/drivers/media/IR/Kconfig linux-2.6.35.new/drivers/media/IR/Kconfig +--- linux-2.6.35/drivers/media/IR/Kconfig 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/Kconfig 2010-09-09 23:21:49.000000000 -0400 +@@ -1,13 +1,22 @@ +-config IR_CORE +- tristate ++menuconfig IR_CORE ++ tristate "Infrared remote controller adapters" + depends on INPUT + default INPUT ++ ---help--- ++ Enable support for Remote Controllers on Linux. This is ++ needed in order to support several video capture adapters. ++ ++ Enable this option if you have a video capture board even ++ if you don't need IR, as otherwise, you may not be able to ++ compile the driver for your adapter. + + config VIDEO_IR + tristate + depends on IR_CORE + default IR_CORE + ++if IR_CORE ++ + config LIRC + tristate + default y +@@ -16,7 +25,7 @@ config LIRC + Enable this option to build the Linux Infrared Remote + Control (LIRC) core device interface driver. The LIRC + interface passes raw IR to and from userspace, where the +- LIRC daemon handles protocol decoding for IR reception ann ++ LIRC daemon handles protocol decoding for IR reception and + encoding for IR transmitting (aka "blasting"). + + source "drivers/media/IR/keymaps/Kconfig" +@@ -44,6 +53,7 @@ config IR_RC5_DECODER + config IR_RC6_DECODER + tristate "Enable IR raw decoder for the RC6 protocol" + depends on IR_CORE ++ select BITREVERSE + default y + + ---help--- +@@ -77,7 +87,9 @@ config IR_RC5_SZ_DECODER + + ---help--- + Enable this option if you have IR with RC-5 (streamzap) protocol, +- and if the IR is decoded in software. ++ and if the IR is decoded in software. (The Streamzap PC Remote ++ uses an IR protocol that is almost standard RC-5, but not quite, ++ as it uses an additional bit). + + config IR_LIRC_CODEC + tristate "Enable IR to LIRC bridge" +@@ -113,6 +125,20 @@ config IR_MCEUSB + To compile this driver as a module, choose M here: the + module will be called mceusb. + ++config IR_ENE ++ tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)" ++ depends on PNP ++ depends on IR_CORE ++ ---help--- ++ Say Y here to enable support for integrated infrared receiver ++ /transciever made by ENE. ++ ++ You can see if you have it by looking at lspnp output. ++ Output should include ENE0100 ENE0200 or something similiar. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ene_ir. ++ + config IR_STREAMZAP + tristate "Streamzap PC Remote IR Receiver" + depends on USB_ARCH_HAS_HCD +@@ -124,3 +150,5 @@ config IR_STREAMZAP + + To compile this driver as a module, choose M here: the + module will be called streamzap. ++ ++endif #IR_CORE +diff -Naurp linux-2.6.35/drivers/media/IR/keymaps/Makefile linux-2.6.35.new/drivers/media/IR/keymaps/Makefile +--- linux-2.6.35/drivers/media/IR/keymaps/Makefile 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/keymaps/Makefile 2010-09-09 23:21:42.000000000 -0400 +@@ -14,10 +14,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t + rc-budget-ci-old.o \ + rc-cinergy-1400.o \ + rc-cinergy.o \ ++ rc-dib0700-nec.o \ ++ rc-dib0700-rc5.o \ + rc-dm1105-nec.o \ + rc-dntv-live-dvb-t.o \ + rc-dntv-live-dvbt-pro.o \ +- rc-empty.o \ + rc-em-terratec.o \ + rc-encore-enltv2.o \ + rc-encore-enltv.o \ +diff -Naurp linux-2.6.35/drivers/media/IR/keymaps/rc-dib0700-nec.c linux-2.6.35.new/drivers/media/IR/keymaps/rc-dib0700-nec.c +--- linux-2.6.35/drivers/media/IR/keymaps/rc-dib0700-nec.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/keymaps/rc-dib0700-nec.c 2010-09-09 23:21:42.000000000 -0400 +@@ -0,0 +1,124 @@ ++/* rc-dvb0700-big.c - Keytable for devices in dvb0700 ++ * ++ * Copyright (c) 2010 by Mauro Carvalho Chehab ++ * ++ * TODO: This table is a real mess, as it merges RC codes from several ++ * devices into a big table. It also has both RC-5 and NEC codes inside. ++ * It should be broken into small tables, and the protocols should properly ++ * be indentificated. ++ * ++ * The table were imported from dib0700_devices.c. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++static struct ir_scancode dib0700_nec_table[] = { ++ /* Key codes for the Pixelview SBTVD remote */ ++ { 0x8613, KEY_MUTE }, ++ { 0x8612, KEY_POWER }, ++ { 0x8601, KEY_1 }, ++ { 0x8602, KEY_2 }, ++ { 0x8603, KEY_3 }, ++ { 0x8604, KEY_4 }, ++ { 0x8605, KEY_5 }, ++ { 0x8606, KEY_6 }, ++ { 0x8607, KEY_7 }, ++ { 0x8608, KEY_8 }, ++ { 0x8609, KEY_9 }, ++ { 0x8600, KEY_0 }, ++ { 0x860d, KEY_CHANNELUP }, ++ { 0x8619, KEY_CHANNELDOWN }, ++ { 0x8610, KEY_VOLUMEUP }, ++ { 0x860c, KEY_VOLUMEDOWN }, ++ ++ { 0x860a, KEY_CAMERA }, ++ { 0x860b, KEY_ZOOM }, ++ { 0x861b, KEY_BACKSPACE }, ++ { 0x8615, KEY_ENTER }, ++ ++ { 0x861d, KEY_UP }, ++ { 0x861e, KEY_DOWN }, ++ { 0x860e, KEY_LEFT }, ++ { 0x860f, KEY_RIGHT }, ++ ++ { 0x8618, KEY_RECORD }, ++ { 0x861a, KEY_STOP }, ++ ++ /* Key codes for the EvolutePC TVWay+ remote */ ++ { 0x7a00, KEY_MENU }, ++ { 0x7a01, KEY_RECORD }, ++ { 0x7a02, KEY_PLAY }, ++ { 0x7a03, KEY_STOP }, ++ { 0x7a10, KEY_CHANNELUP }, ++ { 0x7a11, KEY_CHANNELDOWN }, ++ { 0x7a12, KEY_VOLUMEUP }, ++ { 0x7a13, KEY_VOLUMEDOWN }, ++ { 0x7a40, KEY_POWER }, ++ { 0x7a41, KEY_MUTE }, ++ ++ /* Key codes for the Elgato EyeTV Diversity silver remote */ ++ { 0x4501, KEY_POWER }, ++ { 0x4502, KEY_MUTE }, ++ { 0x4503, KEY_1 }, ++ { 0x4504, KEY_2 }, ++ { 0x4505, KEY_3 }, ++ { 0x4506, KEY_4 }, ++ { 0x4507, KEY_5 }, ++ { 0x4508, KEY_6 }, ++ { 0x4509, KEY_7 }, ++ { 0x450a, KEY_8 }, ++ { 0x450b, KEY_9 }, ++ { 0x450c, KEY_LAST }, ++ { 0x450d, KEY_0 }, ++ { 0x450e, KEY_ENTER }, ++ { 0x450f, KEY_RED }, ++ { 0x4510, KEY_CHANNELUP }, ++ { 0x4511, KEY_GREEN }, ++ { 0x4512, KEY_VOLUMEDOWN }, ++ { 0x4513, KEY_OK }, ++ { 0x4514, KEY_VOLUMEUP }, ++ { 0x4515, KEY_YELLOW }, ++ { 0x4516, KEY_CHANNELDOWN }, ++ { 0x4517, KEY_BLUE }, ++ { 0x4518, KEY_LEFT }, /* Skip backwards */ ++ { 0x4519, KEY_PLAYPAUSE }, ++ { 0x451a, KEY_RIGHT }, /* Skip forward */ ++ { 0x451b, KEY_REWIND }, ++ { 0x451c, KEY_L }, /* Live */ ++ { 0x451d, KEY_FASTFORWARD }, ++ { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */ ++ { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */ ++ { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */ ++ { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */ ++ { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */ ++}; ++ ++static struct rc_keymap dib0700_nec_map = { ++ .map = { ++ .scan = dib0700_nec_table, ++ .size = ARRAY_SIZE(dib0700_nec_table), ++ .ir_type = IR_TYPE_NEC, ++ .name = RC_MAP_DIB0700_NEC_TABLE, ++ } ++}; ++ ++static int __init init_rc_map(void) ++{ ++ return ir_register_map(&dib0700_nec_map); ++} ++ ++static void __exit exit_rc_map(void) ++{ ++ ir_unregister_map(&dib0700_nec_map); ++} ++ ++module_init(init_rc_map) ++module_exit(exit_rc_map) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mauro Carvalho Chehab "); +diff -Naurp linux-2.6.35/drivers/media/IR/keymaps/rc-dib0700-rc5.c linux-2.6.35.new/drivers/media/IR/keymaps/rc-dib0700-rc5.c +--- linux-2.6.35/drivers/media/IR/keymaps/rc-dib0700-rc5.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/keymaps/rc-dib0700-rc5.c 2010-09-09 23:21:42.000000000 -0400 +@@ -0,0 +1,235 @@ ++/* rc-dvb0700-big.c - Keytable for devices in dvb0700 ++ * ++ * Copyright (c) 2010 by Mauro Carvalho Chehab ++ * ++ * TODO: This table is a real mess, as it merges RC codes from several ++ * devices into a big table. It also has both RC-5 and NEC codes inside. ++ * It should be broken into small tables, and the protocols should properly ++ * be indentificated. ++ * ++ * The table were imported from dib0700_devices.c. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++static struct ir_scancode dib0700_rc5_table[] = { ++ /* Key codes for the tiny Pinnacle remote*/ ++ { 0x0700, KEY_MUTE }, ++ { 0x0701, KEY_MENU }, /* Pinnacle logo */ ++ { 0x0739, KEY_POWER }, ++ { 0x0703, KEY_VOLUMEUP }, ++ { 0x0709, KEY_VOLUMEDOWN }, ++ { 0x0706, KEY_CHANNELUP }, ++ { 0x070c, KEY_CHANNELDOWN }, ++ { 0x070f, KEY_1 }, ++ { 0x0715, KEY_2 }, ++ { 0x0710, KEY_3 }, ++ { 0x0718, KEY_4 }, ++ { 0x071b, KEY_5 }, ++ { 0x071e, KEY_6 }, ++ { 0x0711, KEY_7 }, ++ { 0x0721, KEY_8 }, ++ { 0x0712, KEY_9 }, ++ { 0x0727, KEY_0 }, ++ { 0x0724, KEY_SCREEN }, /* 'Square' key */ ++ { 0x072a, KEY_TEXT }, /* 'T' key */ ++ { 0x072d, KEY_REWIND }, ++ { 0x0730, KEY_PLAY }, ++ { 0x0733, KEY_FASTFORWARD }, ++ { 0x0736, KEY_RECORD }, ++ { 0x073c, KEY_STOP }, ++ { 0x073f, KEY_CANCEL }, /* '?' key */ ++ ++ /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ ++ { 0xeb01, KEY_POWER }, ++ { 0xeb02, KEY_1 }, ++ { 0xeb03, KEY_2 }, ++ { 0xeb04, KEY_3 }, ++ { 0xeb05, KEY_4 }, ++ { 0xeb06, KEY_5 }, ++ { 0xeb07, KEY_6 }, ++ { 0xeb08, KEY_7 }, ++ { 0xeb09, KEY_8 }, ++ { 0xeb0a, KEY_9 }, ++ { 0xeb0b, KEY_VIDEO }, ++ { 0xeb0c, KEY_0 }, ++ { 0xeb0d, KEY_REFRESH }, ++ { 0xeb0f, KEY_EPG }, ++ { 0xeb10, KEY_UP }, ++ { 0xeb11, KEY_LEFT }, ++ { 0xeb12, KEY_OK }, ++ { 0xeb13, KEY_RIGHT }, ++ { 0xeb14, KEY_DOWN }, ++ { 0xeb16, KEY_INFO }, ++ { 0xeb17, KEY_RED }, ++ { 0xeb18, KEY_GREEN }, ++ { 0xeb19, KEY_YELLOW }, ++ { 0xeb1a, KEY_BLUE }, ++ { 0xeb1b, KEY_CHANNELUP }, ++ { 0xeb1c, KEY_VOLUMEUP }, ++ { 0xeb1d, KEY_MUTE }, ++ { 0xeb1e, KEY_VOLUMEDOWN }, ++ { 0xeb1f, KEY_CHANNELDOWN }, ++ { 0xeb40, KEY_PAUSE }, ++ { 0xeb41, KEY_HOME }, ++ { 0xeb42, KEY_MENU }, /* DVD Menu */ ++ { 0xeb43, KEY_SUBTITLE }, ++ { 0xeb44, KEY_TEXT }, /* Teletext */ ++ { 0xeb45, KEY_DELETE }, ++ { 0xeb46, KEY_TV }, ++ { 0xeb47, KEY_DVD }, ++ { 0xeb48, KEY_STOP }, ++ { 0xeb49, KEY_VIDEO }, ++ { 0xeb4a, KEY_AUDIO }, /* Music */ ++ { 0xeb4b, KEY_SCREEN }, /* Pic */ ++ { 0xeb4c, KEY_PLAY }, ++ { 0xeb4d, KEY_BACK }, ++ { 0xeb4e, KEY_REWIND }, ++ { 0xeb4f, KEY_FASTFORWARD }, ++ { 0xeb54, KEY_PREVIOUS }, ++ { 0xeb58, KEY_RECORD }, ++ { 0xeb5c, KEY_NEXT }, ++ ++ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ ++ { 0x1e00, KEY_0 }, ++ { 0x1e01, KEY_1 }, ++ { 0x1e02, KEY_2 }, ++ { 0x1e03, KEY_3 }, ++ { 0x1e04, KEY_4 }, ++ { 0x1e05, KEY_5 }, ++ { 0x1e06, KEY_6 }, ++ { 0x1e07, KEY_7 }, ++ { 0x1e08, KEY_8 }, ++ { 0x1e09, KEY_9 }, ++ { 0x1e0a, KEY_KPASTERISK }, ++ { 0x1e0b, KEY_RED }, ++ { 0x1e0c, KEY_RADIO }, ++ { 0x1e0d, KEY_MENU }, ++ { 0x1e0e, KEY_GRAVE }, /* # */ ++ { 0x1e0f, KEY_MUTE }, ++ { 0x1e10, KEY_VOLUMEUP }, ++ { 0x1e11, KEY_VOLUMEDOWN }, ++ { 0x1e12, KEY_CHANNEL }, ++ { 0x1e14, KEY_UP }, ++ { 0x1e15, KEY_DOWN }, ++ { 0x1e16, KEY_LEFT }, ++ { 0x1e17, KEY_RIGHT }, ++ { 0x1e18, KEY_VIDEO }, ++ { 0x1e19, KEY_AUDIO }, ++ { 0x1e1a, KEY_MEDIA }, ++ { 0x1e1b, KEY_EPG }, ++ { 0x1e1c, KEY_TV }, ++ { 0x1e1e, KEY_NEXT }, ++ { 0x1e1f, KEY_BACK }, ++ { 0x1e20, KEY_CHANNELUP }, ++ { 0x1e21, KEY_CHANNELDOWN }, ++ { 0x1e24, KEY_LAST }, /* Skip backwards */ ++ { 0x1e25, KEY_OK }, ++ { 0x1e29, KEY_BLUE}, ++ { 0x1e2e, KEY_GREEN }, ++ { 0x1e30, KEY_PAUSE }, ++ { 0x1e32, KEY_REWIND }, ++ { 0x1e34, KEY_FASTFORWARD }, ++ { 0x1e35, KEY_PLAY }, ++ { 0x1e36, KEY_STOP }, ++ { 0x1e37, KEY_RECORD }, ++ { 0x1e38, KEY_YELLOW }, ++ { 0x1e3b, KEY_GOTO }, ++ { 0x1e3d, KEY_POWER }, ++ ++ /* Key codes for the Leadtek Winfast DTV Dongle */ ++ { 0x0042, KEY_POWER }, ++ { 0x077c, KEY_TUNER }, ++ { 0x0f4e, KEY_PRINT }, /* PREVIEW */ ++ { 0x0840, KEY_SCREEN }, /* full screen toggle*/ ++ { 0x0f71, KEY_DOT }, /* frequency */ ++ { 0x0743, KEY_0 }, ++ { 0x0c41, KEY_1 }, ++ { 0x0443, KEY_2 }, ++ { 0x0b7f, KEY_3 }, ++ { 0x0e41, KEY_4 }, ++ { 0x0643, KEY_5 }, ++ { 0x097f, KEY_6 }, ++ { 0x0d7e, KEY_7 }, ++ { 0x057c, KEY_8 }, ++ { 0x0a40, KEY_9 }, ++ { 0x0e4e, KEY_CLEAR }, ++ { 0x047c, KEY_CHANNEL }, /* show channel number */ ++ { 0x0f41, KEY_LAST }, /* recall */ ++ { 0x0342, KEY_MUTE }, ++ { 0x064c, KEY_RESERVED }, /* PIP button*/ ++ { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */ ++ { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ ++ { 0x0b70, KEY_RECORD }, ++ { 0x037d, KEY_VOLUMEUP }, ++ { 0x017d, KEY_VOLUMEDOWN }, ++ { 0x0242, KEY_CHANNELUP }, ++ { 0x007d, KEY_CHANNELDOWN }, ++ ++ /* Key codes for Nova-TD "credit card" remote control. */ ++ { 0x1d00, KEY_0 }, ++ { 0x1d01, KEY_1 }, ++ { 0x1d02, KEY_2 }, ++ { 0x1d03, KEY_3 }, ++ { 0x1d04, KEY_4 }, ++ { 0x1d05, KEY_5 }, ++ { 0x1d06, KEY_6 }, ++ { 0x1d07, KEY_7 }, ++ { 0x1d08, KEY_8 }, ++ { 0x1d09, KEY_9 }, ++ { 0x1d0a, KEY_TEXT }, ++ { 0x1d0d, KEY_MENU }, ++ { 0x1d0f, KEY_MUTE }, ++ { 0x1d10, KEY_VOLUMEUP }, ++ { 0x1d11, KEY_VOLUMEDOWN }, ++ { 0x1d12, KEY_CHANNEL }, ++ { 0x1d14, KEY_UP }, ++ { 0x1d15, KEY_DOWN }, ++ { 0x1d16, KEY_LEFT }, ++ { 0x1d17, KEY_RIGHT }, ++ { 0x1d1c, KEY_TV }, ++ { 0x1d1e, KEY_NEXT }, ++ { 0x1d1f, KEY_BACK }, ++ { 0x1d20, KEY_CHANNELUP }, ++ { 0x1d21, KEY_CHANNELDOWN }, ++ { 0x1d24, KEY_LAST }, ++ { 0x1d25, KEY_OK }, ++ { 0x1d30, KEY_PAUSE }, ++ { 0x1d32, KEY_REWIND }, ++ { 0x1d34, KEY_FASTFORWARD }, ++ { 0x1d35, KEY_PLAY }, ++ { 0x1d36, KEY_STOP }, ++ { 0x1d37, KEY_RECORD }, ++ { 0x1d3b, KEY_GOTO }, ++ { 0x1d3d, KEY_POWER }, ++}; ++ ++static struct rc_keymap dib0700_rc5_map = { ++ .map = { ++ .scan = dib0700_rc5_table, ++ .size = ARRAY_SIZE(dib0700_rc5_table), ++ .ir_type = IR_TYPE_RC5, ++ .name = RC_MAP_DIB0700_RC5_TABLE, ++ } ++}; ++ ++static int __init init_rc_map(void) ++{ ++ return ir_register_map(&dib0700_rc5_map); ++} ++ ++static void __exit exit_rc_map(void) ++{ ++ ir_unregister_map(&dib0700_rc5_map); ++} ++ ++module_init(init_rc_map) ++module_exit(exit_rc_map) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mauro Carvalho Chehab "); +diff -Naurp linux-2.6.35/drivers/media/IR/keymaps/rc-rc6-mce.c linux-2.6.35.new/drivers/media/IR/keymaps/rc-rc6-mce.c +--- linux-2.6.35/drivers/media/IR/keymaps/rc-rc6-mce.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/keymaps/rc-rc6-mce.c 2010-09-09 23:21:49.000000000 -0400 +@@ -74,6 +74,8 @@ static struct ir_scancode rc6_mce[] = { + { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ + { 0x800f044d, KEY_TITLE }, + ++ { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ ++ + { 0x800f040c, KEY_POWER }, + { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ + +diff -Naurp linux-2.6.35/drivers/media/IR/keymaps/rc-streamzap.c linux-2.6.35.new/drivers/media/IR/keymaps/rc-streamzap.c +--- linux-2.6.35/drivers/media/IR/keymaps/rc-streamzap.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/keymaps/rc-streamzap.c 2010-09-09 23:21:42.000000000 -0400 +@@ -60,7 +60,7 @@ static struct rc_keymap streamzap_map = + .map = { + .scan = streamzap, + .size = ARRAY_SIZE(streamzap), +- .ir_type = IR_TYPE_RC5, ++ .ir_type = IR_TYPE_RC5_SZ, + .name = RC_MAP_STREAMZAP, + } + }; +diff -Naurp linux-2.6.35/drivers/media/IR/Makefile linux-2.6.35.new/drivers/media/IR/Makefile +--- linux-2.6.35/drivers/media/IR/Makefile 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/Makefile 2010-09-09 23:21:42.000000000 -0400 +@@ -17,4 +17,5 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-c + # stand-alone IR receivers/transmitters + obj-$(CONFIG_IR_IMON) += imon.o + obj-$(CONFIG_IR_MCEUSB) += mceusb.o ++obj-$(CONFIG_IR_ENE) += ene_ir.o + obj-$(CONFIG_IR_STREAMZAP) += streamzap.o +diff -Naurp linux-2.6.35/drivers/media/IR/mceusb.c linux-2.6.35.new/drivers/media/IR/mceusb.c +--- linux-2.6.35/drivers/media/IR/mceusb.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/mceusb.c 2010-09-09 23:21:49.000000000 -0400 +@@ -120,6 +120,10 @@ static struct usb_device_id mceusb_dev_t + { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, + /* Philips eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, ++ /* Philips/Spinel plus IR transceiver for ASUS */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, ++ /* Philips/Spinel plus IR transceiver for ASUS */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, + /* Realtek MCE IR Receiver */ + { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, + /* SMK/Toshiba G83C0004D410 */ +@@ -427,7 +431,7 @@ static void mceusb_dev_printdata(struct + } + } + +-static void usb_async_callback(struct urb *urb, struct pt_regs *regs) ++static void mce_async_callback(struct urb *urb, struct pt_regs *regs) + { + struct mceusb_dev *ir; + int len; +@@ -476,7 +480,7 @@ static void mce_request_packet(struct mc + /* outbound data */ + usb_fill_int_urb(async_urb, ir->usbdev, + usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), +- async_buf, size, (usb_complete_t) usb_async_callback, ++ async_buf, size, (usb_complete_t)mce_async_callback, + ir, ep->bInterval); + memcpy(async_buf, data, size); + +@@ -919,7 +923,6 @@ static int __devinit mceusb_dev_probe(st + struct usb_endpoint_descriptor *ep = NULL; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; +- struct usb_host_config *config; + struct mceusb_dev *ir = NULL; + int pipe, maxp, i; + char buf[63], name[128] = ""; +@@ -929,7 +932,6 @@ static int __devinit mceusb_dev_probe(st + + dev_dbg(&intf->dev, ": %s called\n", __func__); + +- config = dev->actconfig; + idesc = intf->cur_altsetting; + + is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0; +diff -Naurp linux-2.6.35/drivers/media/IR/rc-map.c linux-2.6.35.new/drivers/media/IR/rc-map.c +--- linux-2.6.35/drivers/media/IR/rc-map.c 2010-08-01 18:11:14.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/rc-map.c 2010-09-09 23:21:49.000000000 -0400 +@@ -82,3 +82,26 @@ void ir_unregister_map(struct rc_keymap + } + EXPORT_SYMBOL_GPL(ir_unregister_map); + ++ ++static struct ir_scancode empty[] = { ++ { 0x2a, KEY_COFFEE }, ++}; ++ ++static struct rc_keymap empty_map = { ++ .map = { ++ .scan = empty, ++ .size = ARRAY_SIZE(empty), ++ .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */ ++ .name = RC_MAP_EMPTY, ++ } ++}; ++ ++int ir_rcmap_init(void) ++{ ++ return ir_register_map(&empty_map); ++} ++ ++void ir_rcmap_cleanup(void) ++{ ++ ir_unregister_map(&empty_map); ++} +diff -Naurp linux-2.6.35/drivers/media/IR/rc-map.c.orig linux-2.6.35.new/drivers/media/IR/rc-map.c.orig +--- linux-2.6.35/drivers/media/IR/rc-map.c.orig 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/rc-map.c.orig 2010-09-09 23:21:42.000000000 -0400 +@@ -0,0 +1,84 @@ ++/* ir-raw-event.c - handle IR Pulse/Space event ++ * ++ * Copyright (C) 2010 by Mauro Carvalho Chehab ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++/* Used to handle IR raw handler extensions */ ++static LIST_HEAD(rc_map_list); ++static DEFINE_SPINLOCK(rc_map_lock); ++ ++static struct rc_keymap *seek_rc_map(const char *name) ++{ ++ struct rc_keymap *map = NULL; ++ ++ spin_lock(&rc_map_lock); ++ list_for_each_entry(map, &rc_map_list, list) { ++ if (!strcmp(name, map->map.name)) { ++ spin_unlock(&rc_map_lock); ++ return map; ++ } ++ } ++ spin_unlock(&rc_map_lock); ++ ++ return NULL; ++} ++ ++struct ir_scancode_table *get_rc_map(const char *name) ++{ ++ ++ struct rc_keymap *map; ++ ++ map = seek_rc_map(name); ++#ifdef MODULE ++ if (!map) { ++ int rc = request_module(name); ++ if (rc < 0) { ++ printk(KERN_ERR "Couldn't load IR keymap %s\n", name); ++ return NULL; ++ } ++ msleep(20); /* Give some time for IR to register */ ++ ++ map = seek_rc_map(name); ++ } ++#endif ++ if (!map) { ++ printk(KERN_ERR "IR keymap %s not found\n", name); ++ return NULL; ++ } ++ ++ printk(KERN_INFO "Registered IR keymap %s\n", map->map.name); ++ ++ return &map->map; ++} ++EXPORT_SYMBOL_GPL(get_rc_map); ++ ++int ir_register_map(struct rc_keymap *map) ++{ ++ spin_lock(&rc_map_lock); ++ list_add_tail(&map->list, &rc_map_list); ++ spin_unlock(&rc_map_lock); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ir_register_map); ++ ++void ir_unregister_map(struct rc_keymap *map) ++{ ++ spin_lock(&rc_map_lock); ++ list_del(&map->list); ++ spin_unlock(&rc_map_lock); ++} ++EXPORT_SYMBOL_GPL(ir_unregister_map); ++ +diff -Naurp linux-2.6.35/drivers/media/IR/rc-map.c.rej linux-2.6.35.new/drivers/media/IR/rc-map.c.rej +--- linux-2.6.35/drivers/media/IR/rc-map.c.rej 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.35.new/drivers/media/IR/rc-map.c.rej 2010-09-09 23:21:42.000000000 -0400 +@@ -0,0 +1,13 @@ ++--- drivers/media/IR/rc-map.c +++++ drivers/media/IR/rc-map.c ++@@ -100,8 +100,10 @@ ++ { ++ return ir_register_map(&empty_map); ++ } +++EXPORT_SYMBOL_GPL(ir_rcmap_init); ++ ++ void ir_rcmap_cleanup(void) ++ { ++ ir_unregister_map(&empty_map); ++ } +++EXPORT_SYMBOL_GPL(ir_rcmap_cleanup); +diff -Naurp linux-2.6.35/drivers/media/IR/streamzap.c linux-2.6.35.new/drivers/media/IR/streamzap.c +--- linux-2.6.35/drivers/media/IR/streamzap.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/media/IR/streamzap.c 2010-09-09 23:21:42.000000000 -0400 +@@ -71,9 +71,9 @@ MODULE_DEVICE_TABLE(usb, streamzap_table + + /* from ir-rc5-sz-decoder.c */ + #ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE +-#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") ++#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") + #else +-#define load_rc5_sz_decode() 0 ++#define load_rc5_sz_decode() 0 + #endif + + enum StreamzapDecoderState { +@@ -244,9 +244,9 @@ static void streamzap_callback(struct ur + break; + } + +- dev_info(sz->dev, "%s: received urb, len %d\n", __func__, len); ++ dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); + for (i = 0; i < len; i++) { +- dev_info(sz->dev, "sz idx %d: %x\n", ++ dev_dbg(sz->dev, "sz idx %d: %x\n", + i, (unsigned char)sz->buf_in[i]); + switch (sz->decoder_state) { + case PulseSpace: +diff -Naurp linux-2.6.35/drivers/staging/lirc/Kconfig linux-2.6.35.new/drivers/staging/lirc/Kconfig +--- linux-2.6.35/drivers/staging/lirc/Kconfig 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/staging/lirc/Kconfig 2010-09-09 23:21:42.000000000 -0400 +@@ -18,14 +18,6 @@ config LIRC_BT829 + help + Driver for the IR interface on BT829-based hardware + +-config LIRC_ENE0100 +- tristate "ENE KB3924/ENE0100 CIR Port Reciever" +- depends on LIRC_STAGING && PNP +- help +- This is a driver for CIR port handled by ENE KB3924 embedded +- controller found on some notebooks. +- It appears on PNP list as ENE0100. +- + config LIRC_I2C + tristate "I2C Based IR Receivers" + depends on LIRC_STAGING && I2C +diff -Naurp linux-2.6.35/drivers/staging/lirc/lirc_ene0100.c linux-2.6.35.new/drivers/staging/lirc/lirc_ene0100.c +--- linux-2.6.35/drivers/staging/lirc/lirc_ene0100.c 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/staging/lirc/lirc_ene0100.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,646 +0,0 @@ +-/* +- * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) +- * +- * Copyright (C) 2009 Maxim Levitsky +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation; either version 2 of the +- * License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +- * USA +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include "lirc_ene0100.h" +- +-static int sample_period = 75; +-static int enable_idle = 1; +-static int enable_learning; +- +-static void ene_set_idle(struct ene_device *dev, int idle); +-static void ene_set_inputs(struct ene_device *dev, int enable); +- +-/* read a hardware register */ +-static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) +-{ +- outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); +- outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); +- return inb(dev->hw_io + ENE_IO); +-} +- +-/* write a hardware register */ +-static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) +-{ +- outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); +- outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); +- outb(value, dev->hw_io + ENE_IO); +-} +- +-/* change specific bits in hardware register */ +-static void ene_hw_write_reg_mask(struct ene_device *dev, +- u16 reg, u8 value, u8 mask) +-{ +- u8 regvalue; +- +- outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); +- outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); +- +- regvalue = inb(dev->hw_io + ENE_IO) & ~mask; +- regvalue |= (value & mask); +- outb(regvalue, dev->hw_io + ENE_IO); +-} +- +-/* read irq status and ack it */ +-static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer) +-{ +- u8 irq_status; +- u8 fw_flags1, fw_flags2; +- +- fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); +- +- if (buffer_pointer) +- *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH); +- +- if (dev->hw_revision < ENE_HW_C) { +- irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); +- +- if (!(irq_status & ENEB_IRQ_STATUS_IR)) +- return 0; +- ene_hw_write_reg(dev, ENEB_IRQ_STATUS, +- irq_status & ~ENEB_IRQ_STATUS_IR); +- +- /* rev B support only recieving */ +- return ENE_IRQ_RX; +- } +- +- irq_status = ene_hw_read_reg(dev, ENEC_IRQ); +- +- if (!(irq_status & ENEC_IRQ_STATUS)) +- return 0; +- +- /* original driver does that twice - a workaround ? */ +- ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); +- ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); +- +- /* clear unknown flag in F8F9 */ +- if (fw_flags2 & ENE_FW2_IRQ_CLR) +- ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); +- +- /* check if this is a TX interrupt */ +- fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); +- +- if (fw_flags1 & ENE_FW1_TXIRQ) { +- ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); +- return ENE_IRQ_TX; +- } else +- return ENE_IRQ_RX; +-} +- +-static int ene_hw_detect(struct ene_device *dev) +-{ +- u8 chip_major, chip_minor; +- u8 hw_revision, old_ver; +- u8 tmp; +- u8 fw_capabilities; +- +- tmp = ene_hw_read_reg(dev, ENE_HW_UNK); +- ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); +- +- chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); +- chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); +- +- ene_hw_write_reg(dev, ENE_HW_UNK, tmp); +- hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); +- old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); +- +- if (hw_revision == 0xFF) { +- +- ene_printk(KERN_WARNING, "device seems to be disabled\n"); +- ene_printk(KERN_WARNING, +- "send a mail to lirc-list@lists.sourceforge.net\n"); +- ene_printk(KERN_WARNING, "please attach output of acpidump\n"); +- +- return -ENODEV; +- } +- +- if (chip_major == 0x33) { +- ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n"); +- return -ENODEV; +- } +- +- if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { +- dev->hw_revision = ENE_HW_C; +- ene_printk(KERN_WARNING, +- "KB3926C detected, driver support is not complete!\n"); +- +- } else if (old_ver == 0x24 && hw_revision == 0xC0) { +- dev->hw_revision = ENE_HW_B; +- ene_printk(KERN_NOTICE, "KB3926B detected\n"); +- } else { +- dev->hw_revision = ENE_HW_D; +- ene_printk(KERN_WARNING, +- "unknown ENE chip detected, assuming KB3926D\n"); +- ene_printk(KERN_WARNING, "driver support incomplete"); +- +- } +- +- ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n", +- chip_major, chip_minor, old_ver, hw_revision); +- +- +- /* detect features hardware supports */ +- +- if (dev->hw_revision < ENE_HW_C) +- return 0; +- +- fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); +- +- dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; +- dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; +- +- dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && +- fw_capabilities & ENE_FW2_FAN_AS_NRML_IN; +- +- ene_printk(KERN_NOTICE, "hardware features:\n"); +- ene_printk(KERN_NOTICE, +- "learning and tx %s, gpio40_learn %s, fan_in %s\n", +- dev->hw_learning_and_tx_capable ? "on" : "off", +- dev->hw_gpio40_learning ? "on" : "off", +- dev->hw_fan_as_normal_input ? "on" : "off"); +- +- if (!dev->hw_learning_and_tx_capable && enable_learning) +- enable_learning = 0; +- +- if (dev->hw_learning_and_tx_capable) { +- ene_printk(KERN_WARNING, +- "Device supports transmitting, but the driver doesn't\n"); +- ene_printk(KERN_WARNING, +- "due to lack of hardware to test against.\n"); +- ene_printk(KERN_WARNING, +- "Send a mail to: lirc-list@lists.sourceforge.net\n"); +- } +- return 0; +-} +- +-/* hardware initialization */ +-static int ene_hw_init(void *data) +-{ +- u8 reg_value; +- struct ene_device *dev = (struct ene_device *)data; +- dev->in_use = 1; +- +- if (dev->hw_revision < ENE_HW_C) { +- ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); +- ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); +- } else { +- reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; +- reg_value |= ENEC_IRQ_UNK_EN; +- reg_value &= ~ENEC_IRQ_STATUS; +- reg_value |= (dev->irq & ENEC_IRQ_MASK); +- ene_hw_write_reg(dev, ENEC_IRQ, reg_value); +- ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); +- } +- +- ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); +- ene_set_inputs(dev, enable_learning); +- +- /* set sampling period */ +- ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); +- +- /* ack any pending irqs - just in case */ +- ene_hw_irq_status(dev, NULL); +- +- /* enter idle mode */ +- ene_set_idle(dev, 1); +- +- /* enable firmware bits */ +- ene_hw_write_reg_mask(dev, ENE_FW1, +- ENE_FW1_ENABLE | ENE_FW1_IRQ, +- ENE_FW1_ENABLE | ENE_FW1_IRQ); +- /* clear stats */ +- dev->sample = 0; +- return 0; +-} +- +-/* this enables gpio40 signal, used if connected to wide band input*/ +-static void ene_enable_gpio40(struct ene_device *dev, int enable) +-{ +- ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ? +- 0 : ENE_CIR_CONF2_GPIO40DIS, +- ENE_CIR_CONF2_GPIO40DIS); +-} +- +-/* this enables the classic sampler */ +-static void ene_enable_normal_recieve(struct ene_device *dev, int enable) +-{ +- ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0); +-} +- +-/* this enables recieve via fan input */ +-static void ene_enable_fan_recieve(struct ene_device *dev, int enable) +-{ +- if (!enable) +- ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); +- else { +- ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); +- ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); +- } +- dev->fan_input_inuse = enable; +-} +- +-/* determine which input to use*/ +-static void ene_set_inputs(struct ene_device *dev, int learning_enable) +-{ +- ene_enable_normal_recieve(dev, 1); +- +- /* old hardware doesn't support learning mode for sure */ +- if (dev->hw_revision <= ENE_HW_B) +- return; +- +- /* reciever not learning capable, still set gpio40 correctly */ +- if (!dev->hw_learning_and_tx_capable) { +- ene_enable_gpio40(dev, !dev->hw_gpio40_learning); +- return; +- } +- +- /* enable learning mode */ +- if (learning_enable) { +- ene_enable_gpio40(dev, dev->hw_gpio40_learning); +- +- /* fan input is not used for learning */ +- if (dev->hw_fan_as_normal_input) +- ene_enable_fan_recieve(dev, 0); +- +- /* disable learning mode */ +- } else { +- if (dev->hw_fan_as_normal_input) { +- ene_enable_fan_recieve(dev, 1); +- ene_enable_normal_recieve(dev, 0); +- } else +- ene_enable_gpio40(dev, !dev->hw_gpio40_learning); +- } +- +- /* set few additional settings for this mode */ +- ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ? +- ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); +- +- ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ? +- ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); +-} +- +-/* deinitialization */ +-static void ene_hw_deinit(void *data) +-{ +- struct ene_device *dev = (struct ene_device *)data; +- +- /* disable samplers */ +- ene_enable_normal_recieve(dev, 0); +- +- if (dev->hw_fan_as_normal_input) +- ene_enable_fan_recieve(dev, 0); +- +- /* disable hardware IRQ and firmware flag */ +- ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); +- +- ene_set_idle(dev, 1); +- dev->in_use = 0; +-} +- +-/* sends current sample to userspace */ +-static void send_sample(struct ene_device *dev) +-{ +- int value = abs(dev->sample) & PULSE_MASK; +- +- if (dev->sample > 0) +- value |= PULSE_BIT; +- +- if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { +- lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value); +- wake_up(&dev->lirc_driver->rbuf->wait_poll); +- } +- dev->sample = 0; +-} +- +-/* this updates current sample */ +-static void update_sample(struct ene_device *dev, int sample) +-{ +- if (!dev->sample) +- dev->sample = sample; +- else if (same_sign(dev->sample, sample)) +- dev->sample += sample; +- else { +- send_sample(dev); +- dev->sample = sample; +- } +-} +- +-/* enable or disable idle mode */ +-static void ene_set_idle(struct ene_device *dev, int idle) +-{ +- struct timeval now; +- int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C); +- +- ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, +- disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW, +- ENE_CIR_SAMPLE_OVERFLOW); +- dev->idle = idle; +- +- /* remember when we have entered the idle mode */ +- if (idle) { +- do_gettimeofday(&dev->gap_start); +- return; +- } +- +- /* send the gap between keypresses now */ +- do_gettimeofday(&now); +- +- if (now.tv_sec - dev->gap_start.tv_sec > 16) +- dev->sample = space(PULSE_MASK); +- else +- dev->sample = dev->sample + +- space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec)) +- + space(now.tv_usec - dev->gap_start.tv_usec); +- +- if (abs(dev->sample) > PULSE_MASK) +- dev->sample = space(PULSE_MASK); +- send_sample(dev); +-} +- +-/* interrupt handler */ +-static irqreturn_t ene_hw_irq(int irq, void *data) +-{ +- u16 hw_value; +- int i, hw_sample; +- int space; +- int buffer_pointer; +- int irq_status; +- +- struct ene_device *dev = (struct ene_device *)data; +- irq_status = ene_hw_irq_status(dev, &buffer_pointer); +- +- if (!irq_status) +- return IRQ_NONE; +- +- /* TODO: only RX for now */ +- if (irq_status == ENE_IRQ_TX) +- return IRQ_HANDLED; +- +- for (i = 0; i < ENE_SAMPLES_SIZE; i++) { +- +- hw_value = ene_hw_read_reg(dev, +- ENE_SAMPLE_BUFFER + buffer_pointer + i); +- +- if (dev->fan_input_inuse) { +- /* read high part of the sample */ +- hw_value |= ene_hw_read_reg(dev, +- ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8; +- +- /* test for _space_ bit */ +- space = !(hw_value & ENE_FAN_SMPL_PULS_MSK); +- +- /* clear space bit, and other unused bits */ +- hw_value &= ENE_FAN_VALUE_MASK; +- hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; +- +- } else { +- space = hw_value & ENE_SAMPLE_SPC_MASK; +- hw_value &= ENE_SAMPLE_VALUE_MASK; +- hw_sample = hw_value * sample_period; +- } +- +- /* no more data */ +- if (!(hw_value)) +- break; +- +- if (space) +- hw_sample *= -1; +- +- /* overflow sample recieved, handle it */ +- +- if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) { +- +- if (dev->idle) +- continue; +- +- if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP) +- update_sample(dev, hw_sample); +- else +- ene_set_idle(dev, 1); +- +- continue; +- } +- +- /* normal first sample recieved */ +- if (!dev->fan_input_inuse && dev->idle) { +- ene_set_idle(dev, 0); +- +- /* discard first recieved value, its random +- since its the time signal was off before +- first pulse if idle mode is enabled, HW +- does that for us */ +- +- if (!enable_idle) +- continue; +- } +- update_sample(dev, hw_sample); +- send_sample(dev); +- } +- return IRQ_HANDLED; +-} +- +-static int ene_probe(struct pnp_dev *pnp_dev, +- const struct pnp_device_id *dev_id) +-{ +- struct ene_device *dev; +- struct lirc_driver *lirc_driver; +- int error = -ENOMEM; +- +- dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); +- +- if (!dev) +- goto err1; +- +- dev->pnp_dev = pnp_dev; +- pnp_set_drvdata(pnp_dev, dev); +- +- +- /* prepare lirc interface */ +- error = -ENOMEM; +- lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); +- +- if (!lirc_driver) +- goto err2; +- +- dev->lirc_driver = lirc_driver; +- +- strcpy(lirc_driver->name, ENE_DRIVER_NAME); +- lirc_driver->minor = -1; +- lirc_driver->code_length = sizeof(int) * 8; +- lirc_driver->features = LIRC_CAN_REC_MODE2; +- lirc_driver->data = dev; +- lirc_driver->set_use_inc = ene_hw_init; +- lirc_driver->set_use_dec = ene_hw_deinit; +- lirc_driver->dev = &pnp_dev->dev; +- lirc_driver->owner = THIS_MODULE; +- +- lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); +- +- if (!lirc_driver->rbuf) +- goto err3; +- +- if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256)) +- goto err4; +- +- error = -ENODEV; +- if (lirc_register_driver(lirc_driver)) +- goto err5; +- +- /* validate resources */ +- if (!pnp_port_valid(pnp_dev, 0) || +- pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) +- goto err6; +- +- if (!pnp_irq_valid(pnp_dev, 0)) +- goto err6; +- +- dev->hw_io = pnp_port_start(pnp_dev, 0); +- dev->irq = pnp_irq(pnp_dev, 0); +- +- /* claim the resources */ +- error = -EBUSY; +- if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) +- goto err6; +- +- if (request_irq(dev->irq, ene_hw_irq, +- IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) +- goto err7; +- +- /* detect hardware version and features */ +- error = ene_hw_detect(dev); +- if (error) +- goto err8; +- +- ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); +- return 0; +- +-err8: +- free_irq(dev->irq, dev); +-err7: +- release_region(dev->hw_io, ENE_MAX_IO); +-err6: +- lirc_unregister_driver(lirc_driver->minor); +-err5: +- lirc_buffer_free(lirc_driver->rbuf); +-err4: +- kfree(lirc_driver->rbuf); +-err3: +- kfree(lirc_driver); +-err2: +- kfree(dev); +-err1: +- return error; +-} +- +-static void ene_remove(struct pnp_dev *pnp_dev) +-{ +- struct ene_device *dev = pnp_get_drvdata(pnp_dev); +- ene_hw_deinit(dev); +- free_irq(dev->irq, dev); +- release_region(dev->hw_io, ENE_MAX_IO); +- lirc_unregister_driver(dev->lirc_driver->minor); +- lirc_buffer_free(dev->lirc_driver->rbuf); +- kfree(dev->lirc_driver); +- kfree(dev); +-} +- +-#ifdef CONFIG_PM +- +-/* TODO: make 'wake on IR' configurable and add .shutdown */ +-/* currently impossible due to lack of kernel support */ +- +-static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) +-{ +- struct ene_device *dev = pnp_get_drvdata(pnp_dev); +- ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE); +- return 0; +-} +- +-static int ene_resume(struct pnp_dev *pnp_dev) +-{ +- struct ene_device *dev = pnp_get_drvdata(pnp_dev); +- if (dev->in_use) +- ene_hw_init(dev); +- +- ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE); +- return 0; +-} +- +-#endif +- +-static const struct pnp_device_id ene_ids[] = { +- {.id = "ENE0100",}, +- {}, +-}; +- +-static struct pnp_driver ene_driver = { +- .name = ENE_DRIVER_NAME, +- .id_table = ene_ids, +- .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, +- +- .probe = ene_probe, +- .remove = __devexit_p(ene_remove), +- +-#ifdef CONFIG_PM +- .suspend = ene_suspend, +- .resume = ene_resume, +-#endif +-}; +- +-static int __init ene_init(void) +-{ +- if (sample_period < 5) { +- ene_printk(KERN_ERR, "sample period must be at\n"); +- ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n"); +- return -EINVAL; +- } +- return pnp_register_driver(&ene_driver); +-} +- +-static void ene_exit(void) +-{ +- pnp_unregister_driver(&ene_driver); +-} +- +-module_param(sample_period, int, S_IRUGO); +-MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)"); +- +-module_param(enable_idle, bool, S_IRUGO | S_IWUSR); +-MODULE_PARM_DESC(enable_idle, +- "Enables turning off signal sampling after long inactivity time; " +- "if disabled might help detecting input signal (default: enabled)"); +- +-module_param(enable_learning, bool, S_IRUGO); +-MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever"); +- +-MODULE_DEVICE_TABLE(pnp, ene_ids); +-MODULE_DESCRIPTION +- ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port"); +-MODULE_AUTHOR("Maxim Levitsky"); +-MODULE_LICENSE("GPL"); +- +-module_init(ene_init); +-module_exit(ene_exit); +diff -Naurp linux-2.6.35/drivers/staging/lirc/lirc_ene0100.h linux-2.6.35.new/drivers/staging/lirc/lirc_ene0100.h +--- linux-2.6.35/drivers/staging/lirc/lirc_ene0100.h 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/staging/lirc/lirc_ene0100.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,169 +0,0 @@ +-/* +- * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) +- * +- * Copyright (C) 2009 Maxim Levitsky +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation; either version 2 of the +- * License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +- * USA +- */ +- +-#include +-#include +- +-/* hardware address */ +-#define ENE_STATUS 0 /* hardware status - unused */ +-#define ENE_ADDR_HI 1 /* hi byte of register address */ +-#define ENE_ADDR_LO 2 /* low byte of register address */ +-#define ENE_IO 3 /* read/write window */ +-#define ENE_MAX_IO 4 +- +-/* 8 bytes of samples, divided in 2 halfs*/ +-#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ +-#define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */ +-#define ENE_SAMPLE_VALUE_MASK 0x7F +-#define ENE_SAMPLE_OVERFLOW 0x7F +-#define ENE_SAMPLES_SIZE 4 +- +-/* fan input sample buffer */ +-#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ +- /* each sample of normal buffer */ +- +-#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ +- /* if set, says that sample is pulse */ +-#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ +- +-/* first firmware register */ +-#define ENE_FW1 0xF8F8 +-#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ +-#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ +-#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ +-#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ +- +-/* second firmware register */ +-#define ENE_FW2 0xF8F9 +-#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ +-#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ +-#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ +- /* learning input */ +-#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ +-#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ +- +-/* fan as input settings - only if learning capable */ +-#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ +-#define ENE_FAN_AS_IN1_EN 0xCD +-#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ +-#define ENE_FAN_AS_IN2_EN 0x03 +-#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ +- +-/* IRQ registers block (for revision B) */ +-#define ENEB_IRQ 0xFD09 /* IRQ number */ +-#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ +-#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ +-#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ +- +-/* IRQ registers block (for revision C,D) */ +-#define ENEC_IRQ 0xFE9B /* new irq settings register */ +-#define ENEC_IRQ_MASK 0x0F /* irq number mask */ +-#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */ +-#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ +- +-/* CIR block settings */ +-#define ENE_CIR_CONF1 0xFEC0 +-#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ +-#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ +-#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ +-#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ +- +-#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ +-#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ +-#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ +- +-#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ +-#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ +- +- +-/* transmitter - not implemented yet */ +-/* KB3926C and higher */ +-/* transmission is very similiar to recieving, a byte is written to */ +-/* ENE_TX_INPUT, in same manner as it is read from sample buffer */ +-/* sample period is fixed*/ +- +- +-/* transmitter ports */ +-#define ENE_TX_PORT1 0xFC01 /* this enables one or both */ +-#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ +-#define ENE_TX_PORT2 0xFC08 +-#define ENE_TX_PORT2_EN (1 << 1) +- +-#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ +-#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ +-#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ +-#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ +- +- +-#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ +-#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ +-#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ +- +-/* Hardware versions */ +-#define ENE_HW_VERSION 0xFF00 /* hardware revision */ +-#define ENE_HW_UNK 0xFF1D +-#define ENE_HW_UNK_CLR (1 << 2) +-#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ +-#define ENE_HW_VER_MINOR 0xFF1F +-#define ENE_HW_VER_OLD 0xFD00 +- +-#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) +- +-#define ENE_DRIVER_NAME "enecir" +-#define ENE_MAXGAP 250000 /* this is amount of time we wait +- before turning the sampler, chosen +- arbitry */ +- +-#define space(len) (-(len)) /* add a space */ +- +-/* software defines */ +-#define ENE_IRQ_RX 1 +-#define ENE_IRQ_TX 2 +- +-#define ENE_HW_B 1 /* 3926B */ +-#define ENE_HW_C 2 /* 3926C */ +-#define ENE_HW_D 3 /* 3926D */ +- +-#define ene_printk(level, text, ...) \ +- printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) +- +-struct ene_device { +- struct pnp_dev *pnp_dev; +- struct lirc_driver *lirc_driver; +- +- /* hw settings */ +- unsigned long hw_io; +- int irq; +- +- int hw_revision; /* hardware revision */ +- int hw_learning_and_tx_capable; /* learning capable */ +- int hw_gpio40_learning; /* gpio40 is learning */ +- int hw_fan_as_normal_input; /* fan input is used as regular input */ +- +- /* device data */ +- int idle; +- int fan_input_inuse; +- +- int sample; +- int in_use; +- +- struct timeval gap_start; +-}; +diff -Naurp linux-2.6.35/drivers/staging/lirc/Makefile linux-2.6.35.new/drivers/staging/lirc/Makefile +--- linux-2.6.35/drivers/staging/lirc/Makefile 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/drivers/staging/lirc/Makefile 2010-09-09 23:21:42.000000000 -0400 +@@ -4,7 +4,6 @@ + # Each configuration option enables a list of files. + + obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o +-obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o + obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o + obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o + obj-$(CONFIG_LIRC_IMON) += lirc_imon.o +diff -Naurp linux-2.6.35/include/media/ir-core.h linux-2.6.35.new/include/media/ir-core.h +--- linux-2.6.35/include/media/ir-core.h 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/include/media/ir-core.h 2010-09-09 23:21:49.000000000 -0400 +@@ -41,6 +41,11 @@ enum rc_driver_type { + * anything with it. Yet, as the same keycode table can be used with other + * devices, a mask is provided to allow its usage. Drivers should generally + * leave this field in blank ++ * @timeout: optional time after which device stops sending data ++ * @min_timeout: minimum timeout supported by device ++ * @max_timeout: maximum timeout supported by device ++ * @rx_resolution : resolution (in ns) of input sampler ++ * @tx_resolution: resolution (in ns) of output sampler + * @priv: driver-specific data, to be used on the callbacks + * @change_protocol: allow changing the protocol used on hardware decoders + * @open: callback to allow drivers to enable polling/irq when IR input device +@@ -49,19 +54,36 @@ enum rc_driver_type { + * is opened. + * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) + * @s_tx_carrier: set transmit carrier frequency ++ * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%) ++ * @s_rx_carrier: inform driver about carrier it is expected to handle + * @tx_ir: transmit IR ++ * @s_idle: optional: enable/disable hardware idle mode, upon which, ++ device doesn't interrupt host until it sees IR pulses ++ * @s_learning_mode: enable wide band receiver used for learning + */ + struct ir_dev_props { + enum rc_driver_type driver_type; + unsigned long allowed_protos; + u32 scanmask; ++ ++ u32 timeout; ++ u32 min_timeout; ++ u32 max_timeout; ++ ++ u32 rx_resolution; ++ u32 tx_resolution; ++ + void *priv; + int (*change_protocol)(void *priv, u64 ir_type); + int (*open)(void *priv); + void (*close)(void *priv); + int (*s_tx_mask)(void *priv, u32 mask); + int (*s_tx_carrier)(void *priv, u32 carrier); ++ int (*s_tx_duty_cycle)(void *priv, u32 duty_cycle); ++ int (*s_rx_carrier_range)(void *priv, u32 min, u32 max); + int (*tx_ir)(void *priv, int *txbuf, u32 n); ++ void (*s_idle)(void *priv, int enable); ++ int (*s_learning_mode)(void *priv, int enable); + }; + + struct ir_input_dev { +@@ -69,9 +91,10 @@ struct ir_input_dev { + char *driver_name; /* Name of the driver module */ + struct ir_scancode_table rc_tab; /* scan/key table */ + unsigned long devno; /* device number */ +- const struct ir_dev_props *props; /* Device properties */ ++ struct ir_dev_props *props; /* Device properties */ + struct ir_raw_event_ctrl *raw; /* for raw pulse/space events */ + struct input_dev *input_dev; /* the input device associated with this device */ ++ bool idle; + + /* key info - needed by IR keycode handlers */ + spinlock_t keylock; /* protects the below members */ +@@ -95,12 +118,12 @@ enum raw_event_type { + /* From ir-keytable.c */ + int __ir_input_register(struct input_dev *dev, + const struct ir_scancode_table *ir_codes, +- const struct ir_dev_props *props, ++ struct ir_dev_props *props, + const char *driver_name); + + static inline int ir_input_register(struct input_dev *dev, + const char *map_name, +- const struct ir_dev_props *props, ++ struct ir_dev_props *props, + const char *driver_name) { + struct ir_scancode_table *ir_codes; + struct ir_input_dev *ir_dev; +@@ -110,8 +133,12 @@ static inline int ir_input_register(stru + return -EINVAL; + + ir_codes = get_rc_map(map_name); +- if (!ir_codes) +- return -EINVAL; ++ if (!ir_codes) { ++ ir_codes = get_rc_map(RC_MAP_EMPTY); ++ ++ if (!ir_codes) ++ return -EINVAL; ++ } + + rc = __ir_input_register(dev, ir_codes, props, driver_name); + if (rc < 0) +@@ -144,6 +171,10 @@ struct ir_raw_event { + void ir_raw_event_handle(struct input_dev *input_dev); + int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev); + int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type); ++int ir_raw_event_store_with_filter(struct input_dev *input_dev, ++ struct ir_raw_event *ev); ++void ir_raw_event_set_idle(struct input_dev *input_dev, int idle); ++ + static inline void ir_raw_event_reset(struct input_dev *input_dev) + { + struct ir_raw_event ev = { .pulse = false, .duration = 0 }; +diff -Naurp linux-2.6.35/include/media/lirc.h linux-2.6.35.new/include/media/lirc.h +--- linux-2.6.35/include/media/lirc.h 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/include/media/lirc.h 2010-09-09 23:21:42.000000000 -0400 +@@ -77,6 +77,7 @@ + #define LIRC_CAN_SET_REC_FILTER 0x08000000 + + #define LIRC_CAN_MEASURE_CARRIER 0x02000000 ++#define LIRC_CAN_USE_WIDEBAND_RECEIVER 0x04000000 + + #define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) + #define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) +@@ -145,7 +146,7 @@ + * if enabled from the next key press on the driver will send + * LIRC_MODE2_FREQUENCY packets + */ +-#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) ++#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) + + /* + * to set a range use +@@ -162,4 +163,6 @@ + #define LIRC_SETUP_START _IO('i', 0x00000021) + #define LIRC_SETUP_END _IO('i', 0x00000022) + ++#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) ++ + #endif +diff -Naurp linux-2.6.35/include/media/rc-map.h linux-2.6.35.new/include/media/rc-map.h +--- linux-2.6.35/include/media/rc-map.h 2010-09-09 23:19:00.000000000 -0400 ++++ linux-2.6.35.new/include/media/rc-map.h 2010-09-09 23:21:42.000000000 -0400 +@@ -70,6 +70,8 @@ void rc_map_init(void); + #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" + #define RC_MAP_CINERGY_1400 "rc-cinergy-1400" + #define RC_MAP_CINERGY "rc-cinergy" ++#define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec" ++#define RC_MAP_DIB0700_RC5_TABLE "rc-dib0700-rc5" + #define RC_MAP_DM1105_NEC "rc-dm1105-nec" + #define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" + #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" +@@ -125,6 +127,7 @@ void rc_map_init(void); + #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" + #define RC_MAP_WINFAST "rc-winfast" + #define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe" ++ + /* + * Please, do not just append newer Remote Controller names at the end. + * The names should be ordered in alphabetical order From 4badda43702a016b6b3f7cda94e5b2fd06d4fd96 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 13 Sep 2010 09:05:15 +1000 Subject: [PATCH 052/277] nouveau: fix oops in acpi edid support --- drm-nouveau-acpi-edid-fix.patch | 29 +++++++++++++++++++++++++++++ kernel.spec | 7 ++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 drm-nouveau-acpi-edid-fix.patch diff --git a/drm-nouveau-acpi-edid-fix.patch b/drm-nouveau-acpi-edid-fix.patch new file mode 100644 index 000000000..52c6662ac --- /dev/null +++ b/drm-nouveau-acpi-edid-fix.patch @@ -0,0 +1,29 @@ +From 3a25c2ea8bd898dff218ef8baa09ea1f05a60b48 Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Fri, 10 Sep 2010 15:33:11 +1000 +Subject: [PATCH] drm/nouveau: we can't free ACPI EDID, so make a copy that we can + +The rest of the connector code assumes we can kfree() the EDID pointer. +This causes things to blow up with the ACPI EDID pointer we get +passed. + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_acpi.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c +index c17a055..1191526 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c ++++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c +@@ -292,6 +292,6 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) + if (ret < 0) + return ret; + +- nv_connector->edid = edid; ++ nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL); + return 0; + } +-- +1.7.2.2 + diff --git a/kernel.spec b/kernel.spec index e4fc6789a..cf75f6113 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 25 +%global baserelease 26 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -659,6 +659,7 @@ Patch1807: drm-i2c-ch7006-fix.patch Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch Patch1812: drm-nouveau-nva3-noaccel.patch +Patch1813: drm-nouveau-acpi-edid-fix.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1278,6 +1279,7 @@ ApplyPatch drm-i2c-ch7006-fix.patch ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-nouveau-nva3-noaccel.patch +ApplyPatch drm-nouveau-acpi-edid-fix.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch @@ -1929,6 +1931,9 @@ fi # and build. %changelog +* Mon Sep 13 2010 Ben Skeggs 2.6.35.4-27 +- nouveau: fix oops in acpi edid support + * Fri Sep 10 2010 Jarod Wilson 2.6.35.4-26 - ir-core rebase to current upstream From 9bd241a830dbcad02fa01754586bde5e3e067518 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 14 Sep 2010 00:35:08 -0400 Subject: [PATCH 053/277] Add support for perl and python scripting to perf (#632942) --- kernel.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index cf75f6113..d0a488b16 100644 --- a/kernel.spec +++ b/kernel.spec @@ -495,8 +495,9 @@ BuildRequires: xmlto, asciidoc %if %{with_sparse} BuildRequires: sparse >= 0.4.1 %endif +# python-devel and perl(ExtUtils::Embed) are required for perf scripting %if %{with_perf} -BuildRequires: elfutils-devel zlib-devel binutils-devel +BuildRequires: elfutils-devel zlib-devel binutils-devel python-devel perl(ExtUtils::Embed) %endif BuildConflicts: rhbuildsys(DiskFree) < 500Mb @@ -1931,6 +1932,9 @@ fi # and build. %changelog +* Mon Sep 13 2010 Chuck Ebbert +- Add support for perl and python scripting to perf (#632942) + * Mon Sep 13 2010 Ben Skeggs 2.6.35.4-27 - nouveau: fix oops in acpi edid support From a1b0ec05b621ca8913da33170907e522ff9391dc Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 14 Sep 2010 20:51:27 -0400 Subject: [PATCH 054/277] security fixes from git head --- ...pace-incorporate-the-access_ok-check.patch | 189 ++++++++++++++++++ ...x-for-the-system-call-number-not-eax.patch | 97 +++++++++ ...rax-after-ia32-syscall-entry-tracing.patch | 49 +++++ ...tiplication-overflow-in-do_io_submit.patch | 47 +++++ kernel.spec | 18 +- 5 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch create mode 100644 02-compat-test-rax-for-the-system-call-number-not-eax.patch create mode 100644 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch create mode 100644 aio-check-for-multiplication-overflow-in-do_io_submit.patch diff --git a/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch b/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch new file mode 100644 index 000000000..f0ecb03c0 --- /dev/null +++ b/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch @@ -0,0 +1,189 @@ +From c41d68a513c71e35a14f66d71782d27a79a81ea6 Mon Sep 17 00:00:00 2001 +From: H. Peter Anvin +Date: Tue, 7 Sep 2010 16:16:18 -0700 +Subject: [PATCH] compat: Make compat_alloc_user_space() incorporate the access_ok() + +compat_alloc_user_space() expects the caller to independently call +access_ok() to verify the returned area. A missing call could +introduce problems on some architectures. + +This patch incorporates the access_ok() check into +compat_alloc_user_space() and also adds a sanity check on the length. +The existing compat_alloc_user_space() implementations are renamed +arch_compat_alloc_user_space() and are used as part of the +implementation of the new global function. + +This patch assumes NULL will cause __get_user()/__put_user() to either +fail or access userspace on all architectures. This should be +followed by checking the return value of compat_access_user_space() +for NULL in the callers, at which time the access_ok() in the callers +can also be removed. + +Reported-by: Ben Hawkes +Signed-off-by: H. Peter Anvin +Acked-by: Benjamin Herrenschmidt +Acked-by: Chris Metcalf +Acked-by: David S. Miller +Acked-by: Ingo Molnar +Acked-by: Thomas Gleixner +Acked-by: Tony Luck +Cc: Andrew Morton +Cc: Arnd Bergmann +Cc: Fenghua Yu +Cc: H. Peter Anvin +Cc: Heiko Carstens +Cc: Helge Deller +Cc: James Bottomley +Cc: Kyle McMartin +Cc: Martin Schwidefsky +Cc: Paul Mackerras +Cc: Ralf Baechle +Cc: +--- + arch/ia64/include/asm/compat.h | 2 +- + arch/mips/include/asm/compat.h | 2 +- + arch/parisc/include/asm/compat.h | 2 +- + arch/powerpc/include/asm/compat.h | 2 +- + arch/s390/include/asm/compat.h | 2 +- + arch/sparc/include/asm/compat.h | 2 +- + arch/x86/include/asm/compat.h | 2 +- + include/linux/compat.h | 3 +++ + kernel/compat.c | 21 +++++++++++++++++++++ + 10 files changed, 32 insertions(+), 8 deletions(-) + +diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h +index f90edc8..9301a28 100644 +--- a/arch/ia64/include/asm/compat.h ++++ b/arch/ia64/include/asm/compat.h +@@ -199,7 +199,7 @@ ptr_to_compat(void __user *uptr) + } + + static __inline__ void __user * +-compat_alloc_user_space (long len) ++arch_compat_alloc_user_space (long len) + { + struct pt_regs *regs = task_pt_regs(current); + return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len); +diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h +index 613f691..dbc5106 100644 +--- a/arch/mips/include/asm/compat.h ++++ b/arch/mips/include/asm/compat.h +@@ -145,7 +145,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) + return (u32)(unsigned long)uptr; + } + +-static inline void __user *compat_alloc_user_space(long len) ++static inline void __user *arch_compat_alloc_user_space(long len) + { + struct pt_regs *regs = (struct pt_regs *) + ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1; +diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h +index 02b77ba..efa0b60 100644 +--- a/arch/parisc/include/asm/compat.h ++++ b/arch/parisc/include/asm/compat.h +@@ -147,7 +147,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) + return (u32)(unsigned long)uptr; + } + +-static __inline__ void __user *compat_alloc_user_space(long len) ++static __inline__ void __user *arch_compat_alloc_user_space(long len) + { + struct pt_regs *regs = ¤t->thread.regs; + return (void __user *)regs->gr[30]; +diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h +index 396d21a..a11d4ea 100644 +--- a/arch/powerpc/include/asm/compat.h ++++ b/arch/powerpc/include/asm/compat.h +@@ -134,7 +134,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) + return (u32)(unsigned long)uptr; + } + +-static inline void __user *compat_alloc_user_space(long len) ++static inline void __user *arch_compat_alloc_user_space(long len) + { + struct pt_regs *regs = current->thread.regs; + unsigned long usp = regs->gpr[1]; +diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h +index 104f200..a875c2f 100644 +--- a/arch/s390/include/asm/compat.h ++++ b/arch/s390/include/asm/compat.h +@@ -181,7 +181,7 @@ static inline int is_compat_task(void) + + #endif + +-static inline void __user *compat_alloc_user_space(long len) ++static inline void __user *arch_compat_alloc_user_space(long len) + { + unsigned long stack; + +diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h +index 5016f76..6f57325 100644 +--- a/arch/sparc/include/asm/compat.h ++++ b/arch/sparc/include/asm/compat.h +@@ -167,7 +167,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) + return (u32)(unsigned long)uptr; + } + +-static inline void __user *compat_alloc_user_space(long len) ++static inline void __user *arch_compat_alloc_user_space(long len) + { + struct pt_regs *regs = current_thread_info()->kregs; + unsigned long usp = regs->u_regs[UREG_I6]; +diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h +index 306160e..1d9cd27 100644 +--- a/arch/x86/include/asm/compat.h ++++ b/arch/x86/include/asm/compat.h +@@ -205,7 +205,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) + return (u32)(unsigned long)uptr; + } + +-static inline void __user *compat_alloc_user_space(long len) ++static inline void __user *arch_compat_alloc_user_space(long len) + { + struct pt_regs *regs = task_pt_regs(current); + return (void __user *)regs->sp - len; +diff --git a/include/linux/compat.h b/include/linux/compat.h +index 9ddc878..5778b55 100644 +--- a/include/linux/compat.h ++++ b/include/linux/compat.h +@@ -360,5 +360,8 @@ extern ssize_t compat_rw_copy_check_uvector(int type, + const struct compat_iovec __user *uvector, unsigned long nr_segs, + unsigned long fast_segs, struct iovec *fast_pointer, + struct iovec **ret_pointer); ++ ++extern void __user *compat_alloc_user_space(unsigned long len); ++ + #endif /* CONFIG_COMPAT */ + #endif /* _LINUX_COMPAT_H */ +diff --git a/kernel/compat.c b/kernel/compat.c +index e167efc..c9e2ec0 100644 +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -1126,3 +1126,24 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info) + + return 0; + } ++ ++/* ++ * Allocate user-space memory for the duration of a single system call, ++ * in order to marshall parameters inside a compat thunk. ++ */ ++void __user *compat_alloc_user_space(unsigned long len) ++{ ++ void __user *ptr; ++ ++ /* If len would occupy more than half of the entire compat space... */ ++ if (unlikely(len > (((compat_uptr_t)~0) >> 1))) ++ return NULL; ++ ++ ptr = arch_compat_alloc_user_space(len); ++ ++ if (unlikely(!access_ok(VERIFY_WRITE, ptr, len))) ++ return NULL; ++ ++ return ptr; ++} ++EXPORT_SYMBOL_GPL(compat_alloc_user_space); +-- +1.7.2.3 + diff --git a/02-compat-test-rax-for-the-system-call-number-not-eax.patch b/02-compat-test-rax-for-the-system-call-number-not-eax.patch new file mode 100644 index 000000000..15ff0ca85 --- /dev/null +++ b/02-compat-test-rax-for-the-system-call-number-not-eax.patch @@ -0,0 +1,97 @@ +From 36d001c70d8a0144ac1d038f6876c484849a74de Mon Sep 17 00:00:00 2001 +From: H. Peter Anvin +Date: Tue, 14 Sep 2010 12:42:41 -0700 +Subject: [PATCH] x86-64, compat: Test %rax for the syscall number, not %eax + +On 64 bits, we always, by necessity, jump through the system call +table via %rax. For 32-bit system calls, in theory the system call +number is stored in %eax, and the code was testing %eax for a valid +system call number. At one point we loaded the stored value back from +the stack to enforce zero-extension, but that was removed in checkin +d4d67150165df8bf1cc05e532f6efca96f907cab. An actual 32-bit process +will not be able to introduce a non-zero-extended number, but it can +happen via ptrace. + +Instead of re-introducing the zero-extension, test what we are +actually going to use, i.e. %rax. This only adds a handful of REX +prefixes to the code. + +Reported-by: Ben Hawkes +Signed-off-by: H. Peter Anvin +Cc: +Cc: Roland McGrath +Cc: Andrew Morton +--- + arch/x86/ia32/ia32entry.S | 14 +++++++------- + 1 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index b86feab..84e3a4e 100644 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -153,7 +153,7 @@ ENTRY(ia32_sysenter_target) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) + CFI_REMEMBER_STATE + jnz sysenter_tracesys +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja ia32_badsys + sysenter_do_call: + IA32_ARG_FIXUP +@@ -195,7 +195,7 @@ sysexit_from_sys_call: + movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ + call audit_syscall_entry + movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja ia32_badsys + movl %ebx,%edi /* reload 1st syscall arg */ + movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */ +@@ -248,7 +248,7 @@ sysenter_tracesys: + call syscall_trace_enter + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ + jmp sysenter_do_call + CFI_ENDPROC +@@ -314,7 +314,7 @@ ENTRY(ia32_cstar_target) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) + CFI_REMEMBER_STATE + jnz cstar_tracesys +- cmpl $IA32_NR_syscalls-1,%eax ++ cmpq $IA32_NR_syscalls-1,%rax + ja ia32_badsys + cstar_do_call: + IA32_ARG_FIXUP 1 +@@ -367,7 +367,7 @@ cstar_tracesys: + LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */ + RESTORE_REST + xchgl %ebp,%r9d +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ + jmp cstar_do_call + END(ia32_cstar_target) +@@ -425,7 +425,7 @@ ENTRY(ia32_syscall) + orl $TS_COMPAT,TI_status(%r10) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) + jnz ia32_tracesys +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja ia32_badsys + ia32_do_call: + IA32_ARG_FIXUP +@@ -444,7 +444,7 @@ ia32_tracesys: + call syscall_trace_enter + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST +- cmpl $(IA32_NR_syscalls-1),%eax ++ cmpq $(IA32_NR_syscalls-1),%rax + ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ + jmp ia32_do_call + END(ia32_syscall) +-- +1.7.2.3 + diff --git a/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch b/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch new file mode 100644 index 000000000..b7fa7391a --- /dev/null +++ b/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch @@ -0,0 +1,49 @@ +From eefdca043e8391dcd719711716492063030b55ac Mon Sep 17 00:00:00 2001 +From: Roland McGrath +Date: Tue, 14 Sep 2010 12:22:58 -0700 +Subject: [PATCH] x86-64, compat: Retruncate rax after ia32 syscall entry tracing + +In commit d4d6715, we reopened an old hole for a 64-bit ptracer touching a +32-bit tracee in system call entry. A %rax value set via ptrace at the +entry tracing stop gets used whole as a 32-bit syscall number, while we +only check the low 32 bits for validity. + +Fix it by truncating %rax back to 32 bits after syscall_trace_enter, +in addition to testing the full 64 bits as has already been added. + +Reported-by: Ben Hawkes +Signed-off-by: Roland McGrath +Signed-off-by: H. Peter Anvin +--- + arch/x86/ia32/ia32entry.S | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index 84e3a4e..518bb99 100644 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -50,7 +50,12 @@ + /* + * Reload arg registers from stack in case ptrace changed them. + * We don't reload %eax because syscall_trace_enter() returned +- * the value it wants us to use in the table lookup. ++ * the %rax value we should see. Instead, we just truncate that ++ * value to 32 bits again as we did on entry from user mode. ++ * If it's a new value set by user_regset during entry tracing, ++ * this matches the normal truncation of the user-mode value. ++ * If it's -1 to make us punt the syscall, then (u32)-1 is still ++ * an appropriately invalid value. + */ + .macro LOAD_ARGS32 offset, _r9=0 + .if \_r9 +@@ -60,6 +65,7 @@ + movl \offset+48(%rsp),%edx + movl \offset+56(%rsp),%esi + movl \offset+64(%rsp),%edi ++ movl %eax,%eax /* zero extension */ + .endm + + .macro CFI_STARTPROC32 simple +-- +1.7.2.3 + diff --git a/aio-check-for-multiplication-overflow-in-do_io_submit.patch b/aio-check-for-multiplication-overflow-in-do_io_submit.patch new file mode 100644 index 000000000..36b949c27 --- /dev/null +++ b/aio-check-for-multiplication-overflow-in-do_io_submit.patch @@ -0,0 +1,47 @@ +From 75e1c70fc31490ef8a373ea2a4bea2524099b478 Mon Sep 17 00:00:00 2001 +From: Jeff Moyer +Date: Fri, 10 Sep 2010 14:16:00 -0700 +Subject: [PATCH] aio: check for multiplication overflow in do_io_submit +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Tavis Ormandy pointed out that do_io_submit does not do proper bounds +checking on the passed-in iocb array: + +       if (unlikely(nr < 0)) +               return -EINVAL; + +       if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(iocbpp))))) +               return -EFAULT;                      ^^^^^^^^^^^^^^^^^^ + +The attached patch checks for overflow, and if it is detected, the +number of iocbs submitted is scaled down to a number that will fit in +the long.  This is an ok thing to do, as sys_io_submit is documented as +returning the number of iocbs submitted, so callers should handle a +return value of less than the 'nr' argument passed in. + +Reported-by: Tavis Ormandy +Signed-off-by: Jeff Moyer +Signed-off-by: Linus Torvalds +--- + fs/aio.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 3006b5b..1320b2a 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -1659,6 +1659,9 @@ long do_io_submit(aio_context_t ctx_id, long nr, + if (unlikely(nr < 0)) + return -EINVAL; + ++ if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) ++ nr = LONG_MAX/sizeof(*iocbpp); ++ + if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) + return -EFAULT; + +-- +1.7.2.3 + diff --git a/kernel.spec b/kernel.spec index d0a488b16..1c0201b7d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 26 +%global baserelease 28 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -602,11 +602,17 @@ Patch30: git-utrace.patch Patch31: utrace-ptrace-fix-build.patch Patch32: utrace-remove-use-of-kref_set.patch +Patch101: 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch +Patch102: 02-compat-test-rax-for-the-system-call-number-not-eax.patch +Patch103: 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch + Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch Patch160: linux-2.6-32bit-mmap-exec-randomization.patch Patch161: linux-2.6-i386-nx-emulation.patch +Patch180: aio-check-for-multiplication-overflow-in-do_io_submit.patch + Patch200: linux-2.6-debug-sizeof-structs.patch Patch201: linux-2.6-debug-nmi-timeout.patch Patch202: linux-2.6-debug-taint-vm.patch @@ -1155,6 +1161,9 @@ ApplyPatch utrace-remove-use-of-kref_set.patch # Architecture patches # x86(-64) +ApplyPatch 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch +ApplyPatch 02-compat-test-rax-for-the-system-call-number-not-eax.patch +ApplyPatch 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch # # Intel IOMMU @@ -1179,6 +1188,8 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # bugfixes to drivers and filesystems # +ApplyPatch aio-check-for-multiplication-overflow-in-do_io_submit.patch + # ext4 # xfs @@ -1932,6 +1943,11 @@ fi # and build. %changelog +* Tue Sep 14 2010 Kyle McMartin 2.6.35.4-28 +- x86_64: plug compat syscalls holes. (CVE-2010-3081, CVE-2010-3301) + upgrading is highly recommended. +- aio: check for multiplication overflow in do_io_submit. + * Mon Sep 13 2010 Chuck Ebbert - Add support for perl and python scripting to perf (#632942) From 14525abb6daa564fd076a6a111e05dada9bc442b Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 14 Sep 2010 21:05:09 -0400 Subject: [PATCH 055/277] Fix DOS with large argument lists. --- ...e-interactivity-with-large-arguments.patch | 36 +++++++++++++ ...sive-to-sigkill-with-large-arguments.patch | 51 +++++++++++++++++++ kernel.spec | 18 ++++++- ...ges-diagnose-excessive-argument-size.patch | 42 +++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 execve-improve-interactivity-with-large-arguments.patch create mode 100644 execve-make-responsive-to-sigkill-with-large-arguments.patch create mode 100644 setup_arg_pages-diagnose-excessive-argument-size.patch diff --git a/execve-improve-interactivity-with-large-arguments.patch b/execve-improve-interactivity-with-large-arguments.patch new file mode 100644 index 000000000..7908e6ca4 --- /dev/null +++ b/execve-improve-interactivity-with-large-arguments.patch @@ -0,0 +1,36 @@ +From: Roland McGrath +Date: Wed, 8 Sep 2010 02:36:28 +0000 (-0700) +Subject: execve: improve interactivity with large arguments +X-Git-Tag: v2.6.36-rc4~13 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=7993bc1f4663c0db67bb8f0d98e6678145b387cd + +execve: improve interactivity with large arguments + +This adds a preemption point during the copying of the argument and +environment strings for execve, in copy_strings(). There is already +a preemption point in the count() loop, so this doesn't add any new +points in the abstract sense. + +When the total argument+environment strings are very large, the time +spent copying them can be much more than a normal user time slice. +So this change improves the interactivity of the rest of the system +when one process is doing an execve with very large arguments. + +Signed-off-by: Roland McGrath +Reviewed-by: KOSAKI Motohiro +Signed-off-by: Linus Torvalds +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 1b63237..6f2d777 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -419,6 +419,8 @@ static int copy_strings(int argc, const char __user *const __user *argv, + while (len > 0) { + int offset, bytes_to_copy; + ++ cond_resched(); ++ + offset = pos % PAGE_SIZE; + if (offset == 0) + offset = PAGE_SIZE; diff --git a/execve-make-responsive-to-sigkill-with-large-arguments.patch b/execve-make-responsive-to-sigkill-with-large-arguments.patch new file mode 100644 index 000000000..a9e531a76 --- /dev/null +++ b/execve-make-responsive-to-sigkill-with-large-arguments.patch @@ -0,0 +1,51 @@ +From: Roland McGrath +Date: Wed, 8 Sep 2010 02:37:06 +0000 (-0700) +Subject: execve: make responsive to SIGKILL with large arguments +X-Git-Tag: v2.6.36-rc4~12 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9aea5a65aa7a1af9a4236dfaeb0088f1624f9919 + +execve: make responsive to SIGKILL with large arguments + +An execve with a very large total of argument/environment strings +can take a really long time in the execve system call. It runs +uninterruptibly to count and copy all the strings. This change +makes it abort the exec quickly if sent a SIGKILL. + +Note that this is the conservative change, to interrupt only for +SIGKILL, by using fatal_signal_pending(). It would be perfectly +correct semantics to let any signal interrupt the string-copying in +execve, i.e. use signal_pending() instead of fatal_signal_pending(). +We'll save that change for later, since it could have user-visible +consequences, such as having a timer set too quickly make it so that +an execve can never complete, though it always happened to work before. + +Signed-off-by: Roland McGrath +Reviewed-by: KOSAKI Motohiro +Signed-off-by: Linus Torvalds +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 6f2d777..828dd24 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -376,6 +376,9 @@ static int count(const char __user * const __user * argv, int max) + argv++; + if (i++ >= max) + return -E2BIG; ++ ++ if (fatal_signal_pending(current)) ++ return -ERESTARTNOHAND; + cond_resched(); + } + } +@@ -419,6 +422,10 @@ static int copy_strings(int argc, const char __user *const __user *argv, + while (len > 0) { + int offset, bytes_to_copy; + ++ if (fatal_signal_pending(current)) { ++ ret = -ERESTARTNOHAND; ++ goto out; ++ } + cond_resched(); + + offset = pos % PAGE_SIZE; diff --git a/kernel.spec b/kernel.spec index 1c0201b7d..b93fcf1ef 100644 --- a/kernel.spec +++ b/kernel.spec @@ -734,6 +734,11 @@ Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch Patch12517: flexcop-fix-xlate_proc_name-warning.patch +# mitigate DOS attack with large argument lists +Patch12520: execve-improve-interactivity-with-large-arguments.patch +Patch12521: execve-make-responsive-to-sigkill-with-large-arguments.patch +Patch12522: setup_arg_pages-diagnose-excessive-argument-size.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1357,6 +1362,12 @@ ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch # bz #575873 ApplyPatch flexcop-fix-xlate_proc_name-warning.patch + +# mitigate DOS attack with large argument lists +ApplyPatch execve-improve-interactivity-with-large-arguments.patch +ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch +ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch + # END OF PATCH APPLICATIONS %endif @@ -1943,10 +1954,13 @@ fi # and build. %changelog -* Tue Sep 14 2010 Kyle McMartin 2.6.35.4-28 +* Tue Sep 14 2010 Chuck Ebbert 2.6.35.4-28 +- Fix DOS with large argument lists. + +* Tue Sep 14 2010 Kyle McMartin - x86_64: plug compat syscalls holes. (CVE-2010-3081, CVE-2010-3301) upgrading is highly recommended. -- aio: check for multiplication overflow in do_io_submit. +- aio: check for multiplication overflow in do_io_submit. (CVE-2010-3067) * Mon Sep 13 2010 Chuck Ebbert - Add support for perl and python scripting to perf (#632942) diff --git a/setup_arg_pages-diagnose-excessive-argument-size.patch b/setup_arg_pages-diagnose-excessive-argument-size.patch new file mode 100644 index 000000000..ead972a68 --- /dev/null +++ b/setup_arg_pages-diagnose-excessive-argument-size.patch @@ -0,0 +1,42 @@ +From: Roland McGrath +Date: Wed, 8 Sep 2010 02:35:49 +0000 (-0700) +Subject: setup_arg_pages: diagnose excessive argument size +X-Git-Tag: v2.6.36-rc4~14 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1b528181b2ffa14721fb28ad1bd539fe1732c583 + +setup_arg_pages: diagnose excessive argument size + +The CONFIG_STACK_GROWSDOWN variant of setup_arg_pages() does not +check the size of the argument/environment area on the stack. +When it is unworkably large, shift_arg_pages() hits its BUG_ON. +This is exploitable with a very large RLIMIT_STACK limit, to +create a crash pretty easily. + +Check that the initial stack is not too large to make it possible +to map in any executable. We're not checking that the actual +executable (or intepreter, for binfmt_elf) will fit. So those +mappings might clobber part of the initial stack mapping. But +that is just userland lossage that userland made happen, not a +kernel problem. + +Signed-off-by: Roland McGrath +Reviewed-by: KOSAKI Motohiro +Signed-off-by: Linus Torvalds +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 2d94552..1b63237 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -594,6 +594,11 @@ int setup_arg_pages(struct linux_binprm *bprm, + #else + stack_top = arch_align_stack(stack_top); + stack_top = PAGE_ALIGN(stack_top); ++ ++ if (unlikely(stack_top < mmap_min_addr) || ++ unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) ++ return -ENOMEM; ++ + stack_shift = vma->vm_end - stack_top; + + bprm->p -= stack_shift; From db056c27c3551859c58a820b193d46d255afe6cd Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 14 Sep 2010 21:31:20 -0400 Subject: [PATCH 056/277] Fix 3 CVEs /dev/sequencer open failure is not handled correctly (CVE-2010-3080) NULL deref and panic in irda (CVE-2010-2954) keyctl_session_to_parent NULL deref system crash (CVE-2010-2960) --- ...ee-at-error-path-of-snd_seq_oss_open.patch | 53 +++++++++++++++ ...up-self-ias_obj-on-irda_bind-failure.patch | 35 ++++++++++ kernel.spec | 22 +++++++ ...ent-if-parent-has-no-session-keyring.patch | 50 +++++++++++++++ ...-warning-in-keyctl_session_to_parent.patch | 64 +++++++++++++++++++ 5 files changed, 224 insertions(+) create mode 100644 alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch create mode 100644 irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch create mode 100644 keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch create mode 100644 keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch diff --git a/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch b/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch new file mode 100644 index 000000000..73e65ecda --- /dev/null +++ b/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch @@ -0,0 +1,53 @@ +From: Takashi Iwai +Date: Mon, 6 Sep 2010 07:13:45 +0000 (+0200) +Subject: ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=27f7ad53829f79e799a253285318bff79ece15bd + +ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() + +The error handling in snd_seq_oss_open() has several bad codes that +do dereferecing released pointers and double-free of kmalloc'ed data. +The object dp is release in free_devinfo() that is called via +private_free callback. The rest shouldn't touch this object any more. + +The patch changes delete_port() to call kfree() in any case, and gets +rid of unnecessary calls of destructors in snd_seq_oss_open(). + +Fixes CVE-2010-3080. + +Reported-and-tested-by: Tavis Ormandy +Cc: +Signed-off-by: Takashi Iwai +--- + +diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c +index 6857122..69cd7b3 100644 +--- a/sound/core/seq/oss/seq_oss_init.c ++++ b/sound/core/seq/oss/seq_oss_init.c +@@ -281,13 +281,10 @@ snd_seq_oss_open(struct file *file, int level) + return 0; + + _error: +- snd_seq_oss_writeq_delete(dp->writeq); +- snd_seq_oss_readq_delete(dp->readq); + snd_seq_oss_synth_cleanup(dp); + snd_seq_oss_midi_cleanup(dp); +- delete_port(dp); + delete_seq_queue(dp->queue); +- kfree(dp); ++ delete_port(dp); + + return rc; + } +@@ -350,8 +347,10 @@ create_port(struct seq_oss_devinfo *dp) + static int + delete_port(struct seq_oss_devinfo *dp) + { +- if (dp->port < 0) ++ if (dp->port < 0) { ++ kfree(dp); + return 0; ++ } + + debug_printk(("delete_port %i\n", dp->port)); + return snd_seq_event_port_detach(dp->cseq, dp->port); diff --git a/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch b/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch new file mode 100644 index 000000000..7afc4df7a --- /dev/null +++ b/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch @@ -0,0 +1,35 @@ +From: David S. Miller +Date: Tue, 31 Aug 2010 01:35:24 +0000 (-0700) +Subject: irda: Correctly clean up self->ias_obj on irda_bind() failure. +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=628e300cccaa628d8fb92aa28cb7530a3d5f2257 + +irda: Correctly clean up self->ias_obj on irda_bind() failure. + +If irda_open_tsap() fails, the irda_bind() code tries to destroy +the ->ias_obj object by hand, but does so wrongly. + +In particular, it fails to a) release the hashbin attached to the +object and b) reset the self->ias_obj pointer to NULL. + +Fix both problems by using irias_delete_object() and explicitly +setting self->ias_obj to NULL, just as irda_release() does. + +Reported-by: Tavis Ormandy +Signed-off-by: David S. Miller +--- + +diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c +index 79986a6..fd55b51 100644 +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -824,8 +824,8 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + + err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); + if (err < 0) { +- kfree(self->ias_obj->name); +- kfree(self->ias_obj); ++ irias_delete_object(self->ias_obj); ++ self->ias_obj = NULL; + goto out; + } + diff --git a/kernel.spec b/kernel.spec index b93fcf1ef..5b19e25e1 100644 --- a/kernel.spec +++ b/kernel.spec @@ -739,6 +739,14 @@ Patch12520: execve-improve-interactivity-with-large-arguments.patch Patch12521: execve-make-responsive-to-sigkill-with-large-arguments.patch Patch12522: setup_arg_pages-diagnose-excessive-argument-size.patch +# CVE-2010-3080 +Patch12530: alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch +# CVE-2010-2954 +Patch12540: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +# CVE-2010-2960 +Patch12550: keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +Patch12551: keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1368,6 +1376,14 @@ ApplyPatch execve-improve-interactivity-with-large-arguments.patch ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch +# CVE-2010-3080 +ApplyPatch alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch +# CVE-2010-2954 +ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +# CVE-2010-2960 +ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch + # END OF PATCH APPLICATIONS %endif @@ -1955,6 +1971,12 @@ fi %changelog * Tue Sep 14 2010 Chuck Ebbert 2.6.35.4-28 +- Fix 3 CVEs: + /dev/sequencer open failure is not handled correctly (CVE-2010-3080) + NULL deref and panic in irda (CVE-2010-2954) + keyctl_session_to_parent NULL deref system crash (CVE-2010-2960) + +* Tue Sep 14 2010 Chuck Ebbert - Fix DOS with large argument lists. * Tue Sep 14 2010 Kyle McMartin diff --git a/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch b/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch new file mode 100644 index 000000000..c9208674a --- /dev/null +++ b/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch @@ -0,0 +1,50 @@ +From: David Howells +Date: Fri, 10 Sep 2010 08:59:51 +0000 (+0100) +Subject: KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3d96406c7da1ed5811ea52a3b0905f4f0e295376 + +KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring + +Fix a bug in keyctl_session_to_parent() whereby it tries to check the ownership +of the parent process's session keyring whether or not the parent has a session +keyring [CVE-2010-2960]. + +This results in the following oops: + + BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 + IP: [] keyctl_session_to_parent+0x251/0x443 + ... + Call Trace: + [] ? keyctl_session_to_parent+0x67/0x443 + [] ? __do_fault+0x24b/0x3d0 + [] sys_keyctl+0xb4/0xb8 + [] system_call_fastpath+0x16/0x1b + +if the parent process has no session keyring. + +If the system is using pam_keyinit then it mostly protected against this as all +processes derived from a login will have inherited the session keyring created +by pam_keyinit during the log in procedure. + +To test this, pam_keyinit calls need to be commented out in /etc/pam.d/. + +Reported-by: Tavis Ormandy +Signed-off-by: David Howells +Acked-by: Tavis Ormandy +Signed-off-by: Linus Torvalds +--- + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 3868c67..60924f6 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -1305,7 +1305,8 @@ long keyctl_session_to_parent(void) + goto not_permitted; + + /* the keyrings must have the same UID */ +- if (pcred->tgcred->session_keyring->uid != mycred->euid || ++ if ((pcred->tgcred->session_keyring && ++ pcred->tgcred->session_keyring->uid != mycred->euid) || + mycred->tgcred->session_keyring->uid != mycred->euid) + goto not_permitted; + diff --git a/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch b/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch new file mode 100644 index 000000000..5318f7e2f --- /dev/null +++ b/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch @@ -0,0 +1,64 @@ +From: David Howells +Date: Fri, 10 Sep 2010 08:59:46 +0000 (+0100) +Subject: KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9d1ac65a9698513d00e5608d93fca0c53f536c14 + +KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() + +There's an protected access to the parent process's credentials in the middle +of keyctl_session_to_parent(). This results in the following RCU warning: + + =================================================== + [ INFO: suspicious rcu_dereference_check() usage. ] + --------------------------------------------------- + security/keys/keyctl.c:1291 invoked rcu_dereference_check() without protection! + + other info that might help us debug this: + + rcu_scheduler_active = 1, debug_locks = 0 + 1 lock held by keyctl-session-/2137: + #0: (tasklist_lock){.+.+..}, at: [] keyctl_session_to_parent+0x60/0x236 + + stack backtrace: + Pid: 2137, comm: keyctl-session- Not tainted 2.6.36-rc2-cachefs+ #1 + Call Trace: + [] lockdep_rcu_dereference+0xaa/0xb3 + [] keyctl_session_to_parent+0xed/0x236 + [] sys_keyctl+0xb4/0xb6 + [] system_call_fastpath+0x16/0x1b + +The code should take the RCU read lock to make sure the parents credentials +don't go away, even though it's holding a spinlock and has IRQ disabled. + +Signed-off-by: David Howells +Signed-off-by: Linus Torvalds +--- + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index b2b0998..3868c67 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -1272,6 +1272,7 @@ long keyctl_session_to_parent(void) + keyring_r = NULL; + + me = current; ++ rcu_read_lock(); + write_lock_irq(&tasklist_lock); + + parent = me->real_parent; +@@ -1319,6 +1320,7 @@ long keyctl_session_to_parent(void) + set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); + + write_unlock_irq(&tasklist_lock); ++ rcu_read_unlock(); + if (oldcred) + put_cred(oldcred); + return 0; +@@ -1327,6 +1329,7 @@ already_same: + ret = 0; + not_permitted: + write_unlock_irq(&tasklist_lock); ++ rcu_read_unlock(); + put_cred(cred); + return ret; + From cb6f3ab7359f203c453c4c02071cc8b481f2b23b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 15 Sep 2010 17:33:15 +0200 Subject: [PATCH 057/277] - virtio_console: Fix poll/select blocking even though there is data to read --- kernel.spec | 5 ++++ linux-2.6.35.4-virtio_console-fix-poll.patch | 29 ++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 linux-2.6.35.4-virtio_console-fix-poll.patch diff --git a/kernel.spec b/kernel.spec index 5b19e25e1..2431a5a9d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -654,6 +654,7 @@ Patch800: linux-2.6-crash-driver.patch # virt + ksm patches Patch1555: fix_xen_guest_on_old_EC2.patch +Patch1556: linux-2.6.35.4-virtio_console-fix-poll.patch # DRM Patch1801: drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch @@ -1293,6 +1294,7 @@ ApplyPatch linux-2.6-crash-driver.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch +ApplyPatch linux-2.6.35.4-virtio_console-fix-poll.patch #ApplyPatch drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch #ApplyPatch revert-drm-kms-toggle-poll-around-switcheroo.patch @@ -1970,6 +1972,9 @@ fi # and build. %changelog +* Wed Sep 15 2010 Hans de Goede +- virtio_console: Fix poll/select blocking even though there is data to read + * Tue Sep 14 2010 Chuck Ebbert 2.6.35.4-28 - Fix 3 CVEs: /dev/sequencer open failure is not handled correctly (CVE-2010-3080) diff --git a/linux-2.6.35.4-virtio_console-fix-poll.patch b/linux-2.6.35.4-virtio_console-fix-poll.patch new file mode 100644 index 000000000..ff46eb41e --- /dev/null +++ b/linux-2.6.35.4-virtio_console-fix-poll.patch @@ -0,0 +1,29 @@ +Subject: virtio_console: Fix poll blocking even though there is data to read (version 2) +From: Hans de Goede + +I found this while working on a Linux agent for spice, the symptom I was +seeing was select blocking on the spice vdagent virtio serial port even +though there were messages queued up there. + +virtio_console's port_fops_poll checks port->inbuf != NULL to determine if +read won't block. However if an application reads enough bytes from inbuf +through port_fops_read, to empty the current port->inbuf, port->inbuf +will be NULL even though there may be buffers left in the virtqueue. + +This causes poll() to block even though there is data ready to be read, this +patch fixes this by using port_has_data(port) instead of the +port->inbuf != NULL check. + +Signed-off-By: Hans de Goede +diff -up linux-2.6.35.x86_64/drivers/char/virtio_console.c~ linux-2.6.35.x86_64/drivers/char/virtio_console.c +--- linux-2.6.35.x86_64/drivers/char/virtio_console.c~ 2010-08-02 00:11:14.000000000 +0200 ++++ linux-2.6.35.x86_64/drivers/char/virtio_console.c 2010-09-15 13:39:29.043505000 +0200 +@@ -642,7 +642,7 @@ static unsigned int port_fops_poll(struc + poll_wait(filp, &port->waitqueue, wait); + + ret = 0; +- if (port->inbuf) ++ if (port_has_data(port)) + ret |= POLLIN | POLLRDNORM; + if (!will_write_block(port)) + ret |= POLLOUT; From 291833d307de6143e4da42d9557356207b881d48 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 15 Sep 2010 16:12:01 -0400 Subject: [PATCH 058/277] Fix another RCU lockdep warning (cgroups). --- kernel.spec | 5 ++++ linux-2.6-cgroups-rcu.patch | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 linux-2.6-cgroups-rcu.patch diff --git a/kernel.spec b/kernel.spec index 2431a5a9d..d29ba1f79 100644 --- a/kernel.spec +++ b/kernel.spec @@ -729,6 +729,7 @@ Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # rhbz #622149 Patch12085: fix-rcu_deref_check-warning.patch +Patch12086: linux-2.6-cgroups-rcu.patch # rhbz #513530 Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch @@ -1366,6 +1367,7 @@ ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # bz 622149 ApplyPatch fix-rcu_deref_check-warning.patch +ApplyPatch linux-2.6-cgroups-rcu.patch # bz 513530 ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch @@ -1972,6 +1974,9 @@ fi # and build. %changelog +* Wed Sep 15 2010 Dave Jones +- Fix another RCU lockdep warning (cgroups). + * Wed Sep 15 2010 Hans de Goede - virtio_console: Fix poll/select blocking even though there is data to read diff --git a/linux-2.6-cgroups-rcu.patch b/linux-2.6-cgroups-rcu.patch new file mode 100644 index 000000000..a9a5d99a6 --- /dev/null +++ b/linux-2.6-cgroups-rcu.patch @@ -0,0 +1,47 @@ +Message-ID: <4C805293.1020305@cn.fujitsu.com> +Date: Fri, 03 Sep 2010 09:42:43 +0800 +From: Li Zefan +To: David Miller +CC: Herbert Xu , Dave Jones , + netdev , LKML , + Peter Zijlstra , Paul Menage +Subject: [PATCH v2] cls_cgroup: Fix rcu lockdep warning + +Dave reported an rcu lockdep warning on 2.6.35.4 kernel + +task->cgroups and task->cgroups->subsys[i] are protected by RCU. +So we avoid accessing invalid pointers here. This might happen, +for example, when you are deref-ing those pointers while someone +move @task from one cgroup to another. + +Reported-by: Dave Jones +Signed-off-by: Li Zefan +--- + include/net/cls_cgroup.h | 10 ++++++++-- + 1 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h +index dd1fdb8..a4dc5b0 100644 +--- a/include/net/cls_cgroup.h ++++ b/include/net/cls_cgroup.h +@@ -27,11 +27,17 @@ struct cgroup_cls_state + #ifdef CONFIG_NET_CLS_CGROUP + static inline u32 task_cls_classid(struct task_struct *p) + { ++ int classid; ++ + if (in_interrupt()) + return 0; + +- return container_of(task_subsys_state(p, net_cls_subsys_id), +- struct cgroup_cls_state, css)->classid; ++ rcu_read_lock(); ++ classid = container_of(task_subsys_state(p, net_cls_subsys_id), ++ struct cgroup_cls_state, css)->classid; ++ rcu_read_unlock(); ++ ++ return classid; + } + #else + extern int net_cls_subsys_id; + From 7193965656df963dd0cec2cb20bbe4131b8fce90 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Sep 2010 10:53:51 +0200 Subject: [PATCH 059/277] - Small fix to virtio_console poll fix from upstream review --- kernel.spec | 3 +++ linux-2.6.35.4-virtio_console-fix-poll.patch | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel.spec b/kernel.spec index d29ba1f79..199b2d8dd 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1974,6 +1974,9 @@ fi # and build. %changelog +* Thu Sep 16 2010 Hans de Goede +- Small fix to virtio_console poll fix from upstream review + * Wed Sep 15 2010 Dave Jones - Fix another RCU lockdep warning (cgroups). diff --git a/linux-2.6.35.4-virtio_console-fix-poll.patch b/linux-2.6.35.4-virtio_console-fix-poll.patch index ff46eb41e..b87bdf077 100644 --- a/linux-2.6.35.4-virtio_console-fix-poll.patch +++ b/linux-2.6.35.4-virtio_console-fix-poll.patch @@ -1,4 +1,4 @@ -Subject: virtio_console: Fix poll blocking even though there is data to read (version 2) +Subject: virtio_console: Fix poll blocking even though there is data to read From: Hans de Goede I found this while working on a Linux agent for spice, the symptom I was @@ -10,9 +10,9 @@ read won't block. However if an application reads enough bytes from inbuf through port_fops_read, to empty the current port->inbuf, port->inbuf will be NULL even though there may be buffers left in the virtqueue. -This causes poll() to block even though there is data ready to be read, this -patch fixes this by using port_has_data(port) instead of the -port->inbuf != NULL check. +This causes poll() to block even though there is data to be read, this patch +fixes this by using the alredy defined will_read_block utility function +instead of the port->inbuf != NULL check. Signed-off-By: Hans de Goede diff -up linux-2.6.35.x86_64/drivers/char/virtio_console.c~ linux-2.6.35.x86_64/drivers/char/virtio_console.c @@ -23,7 +23,7 @@ diff -up linux-2.6.35.x86_64/drivers/char/virtio_console.c~ linux-2.6.35.x86_64/ ret = 0; - if (port->inbuf) -+ if (port_has_data(port)) ++ if (!will_read_block(port)) ret |= POLLIN | POLLRDNORM; if (!will_write_block(port)) ret |= POLLOUT; From c549b813ae80b26d4030a8b9e7fbdbcbe5616596 Mon Sep 17 00:00:00 2001 From: Dennis Gilmore Date: Thu, 16 Sep 2010 19:23:41 +0000 Subject: [PATCH 060/277] disable some modules to get the kerenl building again on sparc --- config-sparc64-generic | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config-sparc64-generic b/config-sparc64-generic index 1d21fa781..1a2cc5cdb 100644 --- a/config-sparc64-generic +++ b/config-sparc64-generic @@ -200,4 +200,9 @@ CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m CONFIG_GRETH=m CONFIG_FB_XVR1000=y -CONFIG_CRYPTO_DEV_NIAGARA2=y +CONFIG_CRYPTO_DEV_NIAGARA2=m + +# Bellow is changes made to get the kernel building on sparc again, they need to have upstream fixes +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_INFINIBAND is not set From 6daeb4142acfa7ea70d3428fb42275f3650f2c72 Mon Sep 17 00:00:00 2001 From: Dennis Gilmore Date: Thu, 16 Sep 2010 19:24:22 +0000 Subject: [PATCH 061/277] setup kernel headers to be buit on sparcv9 for 32 bit sparc --- kernel.spec | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel.spec b/kernel.spec index 199b2d8dd..b611604db 100644 --- a/kernel.spec +++ b/kernel.spec @@ -326,6 +326,10 @@ Summary: The Linux kernel %define kernel_image arch/s390/boot/image %endif +%ifarch sparcv9 +%define hdrarch sparc +%endif + %ifarch sparc64 %define asmarch sparc %define all_arch_configs kernel-%{version}-sparc64*.config @@ -387,7 +391,7 @@ Summary: The Linux kernel # Which is a BadThing(tm). # We only build kernel-headers on the following... -%define nobuildarches i386 s390 sparc %{arm} +%define nobuildarches i386 s390 sparc sparcv9 %{arm} %ifarch %nobuildarches %define with_up 0 @@ -475,7 +479,7 @@ Version: %{rpmversion} Release: %{pkg_release} # DO NOT CHANGE THE 'ExclusiveArch' LINE TO TEMPORARILY EXCLUDE AN ARCHITECTURE BUILD. # SET %%nobuildarches (ABOVE) INSTEAD -ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 ia64 sparc sparc64 s390 s390x alpha alphaev56 %{arm} +ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 ia64 sparc sparcv9 sparc64 s390 s390x alpha alphaev56 %{arm} ExclusiveOS: Linux %kernel_reqprovconf From 42589b1be29e040b7e741fc193b0673883e9b473 Mon Sep 17 00:00:00 2001 From: Dennis Gilmore Date: Thu, 16 Sep 2010 19:29:12 +0000 Subject: [PATCH 062/277] add changelog entry for sparc fixes --- kernel.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel.spec b/kernel.spec index b611604db..64b2a712e 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1978,6 +1978,10 @@ fi # and build. %changelog +* Thu Sep 16 2010 Dennis Gilmore +- build sparc headers on sparcv9 +- disable some modules to enable the kernel to build on sparc + * Thu Sep 16 2010 Hans de Goede - Small fix to virtio_console poll fix from upstream review From 7a68cb0b55f86f503077266048cfbb100a5b7f7f Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Mon, 20 Sep 2010 21:04:51 -0400 Subject: [PATCH 063/277] Linux 2.6.35.5 Drop merged patches: 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch 02-compat-test-rax-for-the-system-call-number-not-eax.patch 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch direct-io-move-aio_complete-into-end_io.patch ext4-move-aio-completion-after-unwritten-extent-conversion.patch xfs-move-aio-completion-after-unwritten-extent-conversion.patch alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch --- ...pace-incorporate-the-access_ok-check.patch | 189 ---------------- ...x-for-the-system-call-number-not-eax.patch | 97 --------- ...rax-after-ia32-syscall-entry-tracing.patch | 49 ----- ...ee-at-error-path-of-snd_seq_oss_open.patch | 53 ----- direct-io-move-aio_complete-into-end_io.patch | 204 ------------------ ...on-after-unwritten-extent-conversion.patch | 95 -------- kernel.spec | 36 ++-- sources | 2 +- ...on-after-unwritten-extent-conversion.patch | 83 ------- 9 files changed, 14 insertions(+), 794 deletions(-) delete mode 100644 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch delete mode 100644 02-compat-test-rax-for-the-system-call-number-not-eax.patch delete mode 100644 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch delete mode 100644 alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch delete mode 100644 direct-io-move-aio_complete-into-end_io.patch delete mode 100644 ext4-move-aio-completion-after-unwritten-extent-conversion.patch delete mode 100644 xfs-move-aio-completion-after-unwritten-extent-conversion.patch diff --git a/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch b/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch deleted file mode 100644 index f0ecb03c0..000000000 --- a/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch +++ /dev/null @@ -1,189 +0,0 @@ -From c41d68a513c71e35a14f66d71782d27a79a81ea6 Mon Sep 17 00:00:00 2001 -From: H. Peter Anvin -Date: Tue, 7 Sep 2010 16:16:18 -0700 -Subject: [PATCH] compat: Make compat_alloc_user_space() incorporate the access_ok() - -compat_alloc_user_space() expects the caller to independently call -access_ok() to verify the returned area. A missing call could -introduce problems on some architectures. - -This patch incorporates the access_ok() check into -compat_alloc_user_space() and also adds a sanity check on the length. -The existing compat_alloc_user_space() implementations are renamed -arch_compat_alloc_user_space() and are used as part of the -implementation of the new global function. - -This patch assumes NULL will cause __get_user()/__put_user() to either -fail or access userspace on all architectures. This should be -followed by checking the return value of compat_access_user_space() -for NULL in the callers, at which time the access_ok() in the callers -can also be removed. - -Reported-by: Ben Hawkes -Signed-off-by: H. Peter Anvin -Acked-by: Benjamin Herrenschmidt -Acked-by: Chris Metcalf -Acked-by: David S. Miller -Acked-by: Ingo Molnar -Acked-by: Thomas Gleixner -Acked-by: Tony Luck -Cc: Andrew Morton -Cc: Arnd Bergmann -Cc: Fenghua Yu -Cc: H. Peter Anvin -Cc: Heiko Carstens -Cc: Helge Deller -Cc: James Bottomley -Cc: Kyle McMartin -Cc: Martin Schwidefsky -Cc: Paul Mackerras -Cc: Ralf Baechle -Cc: ---- - arch/ia64/include/asm/compat.h | 2 +- - arch/mips/include/asm/compat.h | 2 +- - arch/parisc/include/asm/compat.h | 2 +- - arch/powerpc/include/asm/compat.h | 2 +- - arch/s390/include/asm/compat.h | 2 +- - arch/sparc/include/asm/compat.h | 2 +- - arch/x86/include/asm/compat.h | 2 +- - include/linux/compat.h | 3 +++ - kernel/compat.c | 21 +++++++++++++++++++++ - 10 files changed, 32 insertions(+), 8 deletions(-) - -diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h -index f90edc8..9301a28 100644 ---- a/arch/ia64/include/asm/compat.h -+++ b/arch/ia64/include/asm/compat.h -@@ -199,7 +199,7 @@ ptr_to_compat(void __user *uptr) - } - - static __inline__ void __user * --compat_alloc_user_space (long len) -+arch_compat_alloc_user_space (long len) - { - struct pt_regs *regs = task_pt_regs(current); - return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len); -diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h -index 613f691..dbc5106 100644 ---- a/arch/mips/include/asm/compat.h -+++ b/arch/mips/include/asm/compat.h -@@ -145,7 +145,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) - return (u32)(unsigned long)uptr; - } - --static inline void __user *compat_alloc_user_space(long len) -+static inline void __user *arch_compat_alloc_user_space(long len) - { - struct pt_regs *regs = (struct pt_regs *) - ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1; -diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h -index 02b77ba..efa0b60 100644 ---- a/arch/parisc/include/asm/compat.h -+++ b/arch/parisc/include/asm/compat.h -@@ -147,7 +147,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) - return (u32)(unsigned long)uptr; - } - --static __inline__ void __user *compat_alloc_user_space(long len) -+static __inline__ void __user *arch_compat_alloc_user_space(long len) - { - struct pt_regs *regs = ¤t->thread.regs; - return (void __user *)regs->gr[30]; -diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h -index 396d21a..a11d4ea 100644 ---- a/arch/powerpc/include/asm/compat.h -+++ b/arch/powerpc/include/asm/compat.h -@@ -134,7 +134,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) - return (u32)(unsigned long)uptr; - } - --static inline void __user *compat_alloc_user_space(long len) -+static inline void __user *arch_compat_alloc_user_space(long len) - { - struct pt_regs *regs = current->thread.regs; - unsigned long usp = regs->gpr[1]; -diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h -index 104f200..a875c2f 100644 ---- a/arch/s390/include/asm/compat.h -+++ b/arch/s390/include/asm/compat.h -@@ -181,7 +181,7 @@ static inline int is_compat_task(void) - - #endif - --static inline void __user *compat_alloc_user_space(long len) -+static inline void __user *arch_compat_alloc_user_space(long len) - { - unsigned long stack; - -diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h -index 5016f76..6f57325 100644 ---- a/arch/sparc/include/asm/compat.h -+++ b/arch/sparc/include/asm/compat.h -@@ -167,7 +167,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) - return (u32)(unsigned long)uptr; - } - --static inline void __user *compat_alloc_user_space(long len) -+static inline void __user *arch_compat_alloc_user_space(long len) - { - struct pt_regs *regs = current_thread_info()->kregs; - unsigned long usp = regs->u_regs[UREG_I6]; -diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h -index 306160e..1d9cd27 100644 ---- a/arch/x86/include/asm/compat.h -+++ b/arch/x86/include/asm/compat.h -@@ -205,7 +205,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) - return (u32)(unsigned long)uptr; - } - --static inline void __user *compat_alloc_user_space(long len) -+static inline void __user *arch_compat_alloc_user_space(long len) - { - struct pt_regs *regs = task_pt_regs(current); - return (void __user *)regs->sp - len; -diff --git a/include/linux/compat.h b/include/linux/compat.h -index 9ddc878..5778b55 100644 ---- a/include/linux/compat.h -+++ b/include/linux/compat.h -@@ -360,5 +360,8 @@ extern ssize_t compat_rw_copy_check_uvector(int type, - const struct compat_iovec __user *uvector, unsigned long nr_segs, - unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer); -+ -+extern void __user *compat_alloc_user_space(unsigned long len); -+ - #endif /* CONFIG_COMPAT */ - #endif /* _LINUX_COMPAT_H */ -diff --git a/kernel/compat.c b/kernel/compat.c -index e167efc..c9e2ec0 100644 ---- a/kernel/compat.c -+++ b/kernel/compat.c -@@ -1126,3 +1126,24 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info) - - return 0; - } -+ -+/* -+ * Allocate user-space memory for the duration of a single system call, -+ * in order to marshall parameters inside a compat thunk. -+ */ -+void __user *compat_alloc_user_space(unsigned long len) -+{ -+ void __user *ptr; -+ -+ /* If len would occupy more than half of the entire compat space... */ -+ if (unlikely(len > (((compat_uptr_t)~0) >> 1))) -+ return NULL; -+ -+ ptr = arch_compat_alloc_user_space(len); -+ -+ if (unlikely(!access_ok(VERIFY_WRITE, ptr, len))) -+ return NULL; -+ -+ return ptr; -+} -+EXPORT_SYMBOL_GPL(compat_alloc_user_space); --- -1.7.2.3 - diff --git a/02-compat-test-rax-for-the-system-call-number-not-eax.patch b/02-compat-test-rax-for-the-system-call-number-not-eax.patch deleted file mode 100644 index 15ff0ca85..000000000 --- a/02-compat-test-rax-for-the-system-call-number-not-eax.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 36d001c70d8a0144ac1d038f6876c484849a74de Mon Sep 17 00:00:00 2001 -From: H. Peter Anvin -Date: Tue, 14 Sep 2010 12:42:41 -0700 -Subject: [PATCH] x86-64, compat: Test %rax for the syscall number, not %eax - -On 64 bits, we always, by necessity, jump through the system call -table via %rax. For 32-bit system calls, in theory the system call -number is stored in %eax, and the code was testing %eax for a valid -system call number. At one point we loaded the stored value back from -the stack to enforce zero-extension, but that was removed in checkin -d4d67150165df8bf1cc05e532f6efca96f907cab. An actual 32-bit process -will not be able to introduce a non-zero-extended number, but it can -happen via ptrace. - -Instead of re-introducing the zero-extension, test what we are -actually going to use, i.e. %rax. This only adds a handful of REX -prefixes to the code. - -Reported-by: Ben Hawkes -Signed-off-by: H. Peter Anvin -Cc: -Cc: Roland McGrath -Cc: Andrew Morton ---- - arch/x86/ia32/ia32entry.S | 14 +++++++------- - 1 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S -index b86feab..84e3a4e 100644 ---- a/arch/x86/ia32/ia32entry.S -+++ b/arch/x86/ia32/ia32entry.S -@@ -153,7 +153,7 @@ ENTRY(ia32_sysenter_target) - testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) - CFI_REMEMBER_STATE - jnz sysenter_tracesys -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja ia32_badsys - sysenter_do_call: - IA32_ARG_FIXUP -@@ -195,7 +195,7 @@ sysexit_from_sys_call: - movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ - call audit_syscall_entry - movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja ia32_badsys - movl %ebx,%edi /* reload 1st syscall arg */ - movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */ -@@ -248,7 +248,7 @@ sysenter_tracesys: - call syscall_trace_enter - LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ - RESTORE_REST -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ - jmp sysenter_do_call - CFI_ENDPROC -@@ -314,7 +314,7 @@ ENTRY(ia32_cstar_target) - testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) - CFI_REMEMBER_STATE - jnz cstar_tracesys -- cmpl $IA32_NR_syscalls-1,%eax -+ cmpq $IA32_NR_syscalls-1,%rax - ja ia32_badsys - cstar_do_call: - IA32_ARG_FIXUP 1 -@@ -367,7 +367,7 @@ cstar_tracesys: - LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */ - RESTORE_REST - xchgl %ebp,%r9d -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ - jmp cstar_do_call - END(ia32_cstar_target) -@@ -425,7 +425,7 @@ ENTRY(ia32_syscall) - orl $TS_COMPAT,TI_status(%r10) - testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) - jnz ia32_tracesys -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja ia32_badsys - ia32_do_call: - IA32_ARG_FIXUP -@@ -444,7 +444,7 @@ ia32_tracesys: - call syscall_trace_enter - LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ - RESTORE_REST -- cmpl $(IA32_NR_syscalls-1),%eax -+ cmpq $(IA32_NR_syscalls-1),%rax - ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ - jmp ia32_do_call - END(ia32_syscall) --- -1.7.2.3 - diff --git a/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch b/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch deleted file mode 100644 index b7fa7391a..000000000 --- a/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch +++ /dev/null @@ -1,49 +0,0 @@ -From eefdca043e8391dcd719711716492063030b55ac Mon Sep 17 00:00:00 2001 -From: Roland McGrath -Date: Tue, 14 Sep 2010 12:22:58 -0700 -Subject: [PATCH] x86-64, compat: Retruncate rax after ia32 syscall entry tracing - -In commit d4d6715, we reopened an old hole for a 64-bit ptracer touching a -32-bit tracee in system call entry. A %rax value set via ptrace at the -entry tracing stop gets used whole as a 32-bit syscall number, while we -only check the low 32 bits for validity. - -Fix it by truncating %rax back to 32 bits after syscall_trace_enter, -in addition to testing the full 64 bits as has already been added. - -Reported-by: Ben Hawkes -Signed-off-by: Roland McGrath -Signed-off-by: H. Peter Anvin ---- - arch/x86/ia32/ia32entry.S | 8 +++++++- - 1 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S -index 84e3a4e..518bb99 100644 ---- a/arch/x86/ia32/ia32entry.S -+++ b/arch/x86/ia32/ia32entry.S -@@ -50,7 +50,12 @@ - /* - * Reload arg registers from stack in case ptrace changed them. - * We don't reload %eax because syscall_trace_enter() returned -- * the value it wants us to use in the table lookup. -+ * the %rax value we should see. Instead, we just truncate that -+ * value to 32 bits again as we did on entry from user mode. -+ * If it's a new value set by user_regset during entry tracing, -+ * this matches the normal truncation of the user-mode value. -+ * If it's -1 to make us punt the syscall, then (u32)-1 is still -+ * an appropriately invalid value. - */ - .macro LOAD_ARGS32 offset, _r9=0 - .if \_r9 -@@ -60,6 +65,7 @@ - movl \offset+48(%rsp),%edx - movl \offset+56(%rsp),%esi - movl \offset+64(%rsp),%edi -+ movl %eax,%eax /* zero extension */ - .endm - - .macro CFI_STARTPROC32 simple --- -1.7.2.3 - diff --git a/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch b/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch deleted file mode 100644 index 73e65ecda..000000000 --- a/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch +++ /dev/null @@ -1,53 +0,0 @@ -From: Takashi Iwai -Date: Mon, 6 Sep 2010 07:13:45 +0000 (+0200) -Subject: ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=27f7ad53829f79e799a253285318bff79ece15bd - -ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() - -The error handling in snd_seq_oss_open() has several bad codes that -do dereferecing released pointers and double-free of kmalloc'ed data. -The object dp is release in free_devinfo() that is called via -private_free callback. The rest shouldn't touch this object any more. - -The patch changes delete_port() to call kfree() in any case, and gets -rid of unnecessary calls of destructors in snd_seq_oss_open(). - -Fixes CVE-2010-3080. - -Reported-and-tested-by: Tavis Ormandy -Cc: -Signed-off-by: Takashi Iwai ---- - -diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c -index 6857122..69cd7b3 100644 ---- a/sound/core/seq/oss/seq_oss_init.c -+++ b/sound/core/seq/oss/seq_oss_init.c -@@ -281,13 +281,10 @@ snd_seq_oss_open(struct file *file, int level) - return 0; - - _error: -- snd_seq_oss_writeq_delete(dp->writeq); -- snd_seq_oss_readq_delete(dp->readq); - snd_seq_oss_synth_cleanup(dp); - snd_seq_oss_midi_cleanup(dp); -- delete_port(dp); - delete_seq_queue(dp->queue); -- kfree(dp); -+ delete_port(dp); - - return rc; - } -@@ -350,8 +347,10 @@ create_port(struct seq_oss_devinfo *dp) - static int - delete_port(struct seq_oss_devinfo *dp) - { -- if (dp->port < 0) -+ if (dp->port < 0) { -+ kfree(dp); - return 0; -+ } - - debug_printk(("delete_port %i\n", dp->port)); - return snd_seq_event_port_detach(dp->cseq, dp->port); diff --git a/direct-io-move-aio_complete-into-end_io.patch b/direct-io-move-aio_complete-into-end_io.patch deleted file mode 100644 index b40487155..000000000 --- a/direct-io-move-aio_complete-into-end_io.patch +++ /dev/null @@ -1,204 +0,0 @@ -From: Christoph Hellwig -Date: Sun, 18 Jul 2010 21:17:09 +0000 (+0000) -Subject: direct-io: move aio_complete into ->end_io -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=40e2e97316af6e62affab7a392e792494b8d9dde - -direct-io: move aio_complete into ->end_io - -Filesystems with unwritten extent support must not complete an AIO request -until the transaction to convert the extent has been commited. That means -the aio_complete calls needs to be moved into the ->end_io callback so -that the filesystem can control when to call it exactly. - -This makes a bit of a mess out of dio_complete and the ->end_io callback -prototype even more complicated. - -Signed-off-by: Christoph Hellwig -Reviewed-by: Jan Kara -Signed-off-by: Alex Elder ---- - -diff --git a/fs/direct-io.c b/fs/direct-io.c -index 7600aac..a10cb91 100644 ---- a/fs/direct-io.c -+++ b/fs/direct-io.c -@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio) - * filesystems can use it to hold additional state between get_block calls and - * dio_complete. - */ --static int dio_complete(struct dio *dio, loff_t offset, int ret) -+static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async) - { - ssize_t transferred = 0; - -@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) - transferred = dio->i_size - offset; - } - -- if (dio->end_io && dio->result) -- dio->end_io(dio->iocb, offset, transferred, -- dio->map_bh.b_private); -- -- if (dio->flags & DIO_LOCKING) -- /* lockdep: non-owner release */ -- up_read_non_owner(&dio->inode->i_alloc_sem); -- - if (ret == 0) - ret = dio->page_errors; - if (ret == 0) -@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) - if (ret == 0) - ret = transferred; - -+ if (dio->end_io && dio->result) { -+ dio->end_io(dio->iocb, offset, transferred, -+ dio->map_bh.b_private, ret, is_async); -+ } else if (is_async) { -+ aio_complete(dio->iocb, ret, 0); -+ } -+ -+ if (dio->flags & DIO_LOCKING) -+ /* lockdep: non-owner release */ -+ up_read_non_owner(&dio->inode->i_alloc_sem); -+ - return ret; - } - -@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error) - spin_unlock_irqrestore(&dio->bio_lock, flags); - - if (remaining == 0) { -- int ret = dio_complete(dio, dio->iocb->ki_pos, 0); -- aio_complete(dio->iocb, ret, 0); -+ dio_complete(dio, dio->iocb->ki_pos, 0, true); - kfree(dio); - } - } -@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, - spin_unlock_irqrestore(&dio->bio_lock, flags); - - if (ret2 == 0) { -- ret = dio_complete(dio, offset, ret); -+ ret = dio_complete(dio, offset, ret, false); - kfree(dio); - } else - BUG_ON(ret != -EIOCBQUEUED); -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 42272d6..0afc8c1 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -3775,7 +3775,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) - } - - static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, -- ssize_t size, void *private) -+ ssize_t size, void *private, int ret, -+ bool is_async) - { - ext4_io_end_t *io_end = iocb->private; - struct workqueue_struct *wq; -@@ -3784,7 +3785,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - - /* if not async direct IO or dio with 0 bytes write, just return */ - if (!io_end || !size) -- return; -+ goto out; - - ext_debug("ext4_end_io_dio(): io_end 0x%p" - "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", -@@ -3795,7 +3796,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - if (io_end->flag != EXT4_IO_UNWRITTEN){ - ext4_free_io_end(io_end); - iocb->private = NULL; -- return; -+ goto out; - } - - io_end->offset = offset; -@@ -3812,6 +3813,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - list_add_tail(&io_end->list, &ei->i_completed_io_list); - spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); - iocb->private = NULL; -+out: -+ if (is_async) -+ aio_complete(iocb, ret, 0); - } - - static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) -diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c -index 356e976..96337a4 100644 ---- a/fs/ocfs2/aops.c -+++ b/fs/ocfs2/aops.c -@@ -578,7 +578,9 @@ bail: - static void ocfs2_dio_end_io(struct kiocb *iocb, - loff_t offset, - ssize_t bytes, -- void *private) -+ void *private, -+ int ret, -+ bool is_async) - { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; - int level; -@@ -592,6 +594,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, - if (!level) - up_read(&inode->i_alloc_sem); - ocfs2_rw_unlock(inode, level); -+ -+ if (is_async) -+ aio_complete(iocb, ret, 0); - } - - /* -diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c -index 8abbf05..95d1e26 100644 ---- a/fs/xfs/linux-2.6/xfs_aops.c -+++ b/fs/xfs/linux-2.6/xfs_aops.c -@@ -1406,7 +1406,9 @@ xfs_end_io_direct( - struct kiocb *iocb, - loff_t offset, - ssize_t size, -- void *private) -+ void *private, -+ int ret, -+ bool is_async) - { - xfs_ioend_t *ioend = iocb->private; - -@@ -1452,6 +1454,9 @@ xfs_end_io_direct( - * against double-freeing. - */ - iocb->private = NULL; -+ -+ if (is_async) -+ aio_complete(iocb, ret, 0); - } - - STATIC ssize_t -diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h -index 319da17..c5057fb 100644 ---- a/fs/xfs/linux-2.6/xfs_aops.h -+++ b/fs/xfs/linux-2.6/xfs_aops.h -@@ -37,6 +37,8 @@ typedef struct xfs_ioend { - size_t io_size; /* size of the extent */ - xfs_off_t io_offset; /* offset in the file */ - struct work_struct io_work; /* xfsdatad work queue */ -+ struct kiocb *io_iocb; -+ int io_result; - } xfs_ioend_t; - - extern const struct address_space_operations xfs_address_space_operations; -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 68ca1b0..f91affb 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -415,7 +415,8 @@ struct buffer_head; - typedef int (get_block_t)(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); - typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, -- ssize_t bytes, void *private); -+ ssize_t bytes, void *private, int ret, -+ bool is_async); - - /* - * Attribute flags. These should be or-ed together to figure out what diff --git a/ext4-move-aio-completion-after-unwritten-extent-conversion.patch b/ext4-move-aio-completion-after-unwritten-extent-conversion.patch deleted file mode 100644 index 7e2cb1702..000000000 --- a/ext4-move-aio-completion-after-unwritten-extent-conversion.patch +++ /dev/null @@ -1,95 +0,0 @@ -From: jiayingz@google.com (Jiaying Zhang) <> -Date: Tue, 27 Jul 2010 15:56:06 +0000 (-0400) -Subject: ext4: move aio completion after unwritten extent conversion -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftytso%2Fext4.git;a=commitdiff_plain;h=5b3ff237bef43b9e7fb7d1eb858e29b73fd664f9 - -ext4: move aio completion after unwritten extent conversion - -This patch is to be applied upon Christoph's "direct-io: move aio_complete -into ->end_io" patch. It adds iocb and result fields to struct ext4_io_end_t, -so that we can call aio_complete from ext4_end_io_nolock() after the extent -conversion has finished. - -I have verified with Christoph's aio-dio test that used to fail after a few -runs on an original kernel but now succeeds on the patched kernel. - -See http://thread.gmane.org/gmane.comp.file-systems.ext4/19659 for details. - -Signed-off-by: Jiaying Zhang -Signed-off-by: "Theodore Ts'o" ---- - -diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h -index 4c7d472..fbb3947 100644 ---- a/fs/ext4/ext4.h -+++ b/fs/ext4/ext4.h -@@ -170,13 +170,15 @@ struct mpage_da_data { - }; - #define EXT4_IO_UNWRITTEN 0x1 - typedef struct ext4_io_end { -- struct list_head list; /* per-file finished AIO list */ -+ struct list_head list; /* per-file finished IO list */ - struct inode *inode; /* file being written to */ - unsigned int flag; /* unwritten or not */ - struct page *page; /* page struct for buffer write */ - loff_t offset; /* offset in the file */ - ssize_t size; /* size of the extent */ - struct work_struct work; /* data work queue */ -+ struct kiocb *iocb; /* iocb struct for AIO */ -+ int result; /* error value for AIO */ - } ext4_io_end_t; - - /* -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 609159e..46d2079 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -3668,6 +3668,8 @@ static int ext4_end_io_nolock(ext4_io_end_t *io) - return ret; - } - -+ if (io->iocb) -+ aio_complete(io->iocb, io->result, 0); - /* clear the DIO AIO unwritten flag */ - io->flag = 0; - return ret; -@@ -3767,6 +3769,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags) - io->offset = 0; - io->size = 0; - io->page = NULL; -+ io->iocb = NULL; -+ io->result = 0; - INIT_WORK(&io->work, ext4_end_io_work); - INIT_LIST_HEAD(&io->list); - } -@@ -3796,12 +3800,18 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - if (io_end->flag != EXT4_IO_UNWRITTEN){ - ext4_free_io_end(io_end); - iocb->private = NULL; -- goto out; -+out: -+ if (is_async) -+ aio_complete(iocb, ret, 0); -+ return; - } - - io_end->offset = offset; - io_end->size = size; -- io_end->flag = EXT4_IO_UNWRITTEN; -+ if (is_async) { -+ io_end->iocb = iocb; -+ io_end->result = ret; -+ } - wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; - - /* queue the work to convert unwritten extents to written */ -@@ -3813,9 +3823,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - list_add_tail(&io_end->list, &ei->i_completed_io_list); - spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); - iocb->private = NULL; --out: -- if (is_async) -- aio_complete(iocb, ret, 0); - } - - static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) diff --git a/kernel.spec b/kernel.spec index 64b2a712e..316d1c08f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 28 +%global baserelease 29 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,7 +60,7 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 4 +%define stable_update 5 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -606,10 +606,6 @@ Patch30: git-utrace.patch Patch31: utrace-ptrace-fix-build.patch Patch32: utrace-remove-use-of-kref_set.patch -Patch101: 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch -Patch102: 02-compat-test-rax-for-the-system-call-number-not-eax.patch -Patch103: 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch - Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch Patch160: linux-2.6-32bit-mmap-exec-randomization.patch @@ -724,11 +720,6 @@ Patch12020: hid-support-tivo-slide-remote.patch Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch -# rhbz #617699 -Patch12050: direct-io-move-aio_complete-into-end_io.patch -Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch -Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch - Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # rhbz #622149 @@ -745,8 +736,6 @@ Patch12520: execve-improve-interactivity-with-large-arguments.patch Patch12521: execve-make-responsive-to-sigkill-with-large-arguments.patch Patch12522: setup_arg_pages-diagnose-excessive-argument-size.patch -# CVE-2010-3080 -Patch12530: alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch # CVE-2010-2954 Patch12540: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch # CVE-2010-2960 @@ -1180,9 +1169,6 @@ ApplyPatch utrace-remove-use-of-kref_set.patch # Architecture patches # x86(-64) -ApplyPatch 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch -ApplyPatch 02-compat-test-rax-for-the-system-call-number-not-eax.patch -ApplyPatch 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch # # Intel IOMMU @@ -1361,11 +1347,6 @@ ApplyPatch neuter_intel_microcode_load.patch ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch -# rhbz #617699 -ApplyPatch direct-io-move-aio_complete-into-end_io.patch -ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch -ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch - # bz 610941 ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch @@ -1384,8 +1365,6 @@ ApplyPatch execve-improve-interactivity-with-large-arguments.patch ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch -# CVE-2010-3080 -ApplyPatch alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch # CVE-2010-2954 ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch # CVE-2010-2960 @@ -1978,6 +1957,17 @@ fi # and build. %changelog +* Mon Sep 20 2010 Chuck Ebbert 2.6.35.5-29 +- Linux 2.6.35.5 +- Drop merged patches: + 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch + 02-compat-test-rax-for-the-system-call-number-not-eax.patch + 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch + direct-io-move-aio_complete-into-end_io.patch + ext4-move-aio-completion-after-unwritten-extent-conversion.patch + xfs-move-aio-completion-after-unwritten-extent-conversion.patch + alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch + * Thu Sep 16 2010 Dennis Gilmore - build sparc headers on sparcv9 - disable some modules to enable the kernel to build on sparc diff --git a/sources b/sources index d1eb64f29..f6d872efd 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -738f762746488345b1a8707d00895eef patch-2.6.35.4.bz2 +5bf1900e4ea72b8c65f4f7aae0a28d14 patch-2.6.35.5.bz2 diff --git a/xfs-move-aio-completion-after-unwritten-extent-conversion.patch b/xfs-move-aio-completion-after-unwritten-extent-conversion.patch deleted file mode 100644 index 290be17fd..000000000 --- a/xfs-move-aio-completion-after-unwritten-extent-conversion.patch +++ /dev/null @@ -1,83 +0,0 @@ -From: Christoph Hellwig -Date: Sun, 18 Jul 2010 21:17:10 +0000 (+0000) -Subject: xfs: move aio completion after unwritten extent conversion -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fb511f2150174b18b28ad54708c1adda0df39b17 - -xfs: move aio completion after unwritten extent conversion - -If we write into an unwritten extent using AIO we need to complete the AIO -request after the extent conversion has finished. Without that a read could -race to see see the extent still unwritten and return zeros. For synchronous -I/O we already take care of that by flushing the xfsconvertd workqueue (which -might be a bit of overkill). - -To do that add iocb and result fields to struct xfs_ioend, so that we can -call aio_complete from xfs_end_io after the extent conversion has happened. -Note that we need a new result field as io_error is used for positive errno -values, while the AIO code can return negative error values and positive -transfer sizes. - -Signed-off-by: Christoph Hellwig -Reviewed-by: Dave Chinner -Signed-off-by: Alex Elder ---- - -diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c -index 95d1e26..13622d5 100644 ---- a/fs/xfs/linux-2.6/xfs_aops.c -+++ b/fs/xfs/linux-2.6/xfs_aops.c -@@ -265,8 +265,11 @@ xfs_end_io( - xfs_finish_ioend(ioend, 0); - /* ensure we don't spin on blocked ioends */ - delay(1); -- } else -+ } else { -+ if (ioend->io_iocb) -+ aio_complete(ioend->io_iocb, ioend->io_result, 0); - xfs_destroy_ioend(ioend); -+ } - } - - /* -@@ -299,6 +302,8 @@ xfs_alloc_ioend( - atomic_inc(&XFS_I(ioend->io_inode)->i_iocount); - ioend->io_offset = 0; - ioend->io_size = 0; -+ ioend->io_iocb = NULL; -+ ioend->io_result = 0; - - INIT_WORK(&ioend->io_work, xfs_end_io); - return ioend; -@@ -1411,6 +1416,7 @@ xfs_end_io_direct( - bool is_async) - { - xfs_ioend_t *ioend = iocb->private; -+ bool complete_aio = is_async; - - /* - * Non-NULL private data means we need to issue a transaction to -@@ -1436,7 +1442,14 @@ xfs_end_io_direct( - if (ioend->io_type == IO_READ) { - xfs_finish_ioend(ioend, 0); - } else if (private && size > 0) { -- xfs_finish_ioend(ioend, is_sync_kiocb(iocb)); -+ if (is_async) { -+ ioend->io_iocb = iocb; -+ ioend->io_result = ret; -+ complete_aio = false; -+ xfs_finish_ioend(ioend, 0); -+ } else { -+ xfs_finish_ioend(ioend, 1); -+ } - } else { - /* - * A direct I/O write ioend starts it's life in unwritten -@@ -1455,7 +1468,7 @@ xfs_end_io_direct( - */ - iocb->private = NULL; - -- if (is_async) -+ if (complete_aio) - aio_complete(iocb, ret, 0); - } - From b218718b2b345b73aa274b30f83f544b1e5d9817 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Tue, 21 Sep 2010 09:27:25 -0400 Subject: [PATCH 064/277] Scheduler fixes for Bugzilla #635813 and #633037 --- kernel.spec | 20 +- ...y-accounted-as-system-time-on-32-bit.patch | 55 ++ ...-of-tickless-idle-on-update_cpu_load.patch | 276 ++++++++ ...e-load-balancing-logic-to-push-model.patch | 651 ++++++++++++++++++ ...date-rq-clock-for-nohz-balanced-cpus.patch | 28 + ...synchronization-when-migrating-tasks.patch | 38 + ...-sched_avg_update-to-update_cpu_load.patch | 58 ++ 7 files changed, 1125 insertions(+), 1 deletion(-) create mode 100644 sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch create mode 100644 sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch create mode 100644 sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch create mode 100644 sched-15-update-rq-clock-for-nohz-balanced-cpus.patch create mode 100644 sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch create mode 100644 sched-25-move-sched_avg_update-to-update_cpu_load.patch diff --git a/kernel.spec b/kernel.spec index 316d1c08f..62004ac79 100644 --- a/kernel.spec +++ b/kernel.spec @@ -742,6 +742,13 @@ Patch12540: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch Patch12550: keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch Patch12551: keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +Patch12560: sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch +Patch12565: sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch +Patch12570: sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch +Patch12575: sched-15-update-rq-clock-for-nohz-balanced-cpus.patch +Patch12580: sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch +Patch12585: sched-25-move-sched_avg_update-to-update_cpu_load.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1371,6 +1378,14 @@ ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +# Scheduler fixes (#635813 and #633037) +ApplyPatch sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch +ApplyPatch sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch +ApplyPatch sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch +ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch +ApplyPatch sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch +ApplyPatch sched-25-move-sched_avg_update-to-update_cpu_load.patch + # END OF PATCH APPLICATIONS %endif @@ -1957,7 +1972,10 @@ fi # and build. %changelog -* Mon Sep 20 2010 Chuck Ebbert 2.6.35.5-29 +* Tue Sep 21 2010 Chuck Ebbert 2.6.35.5-29 +- Scheduler fixes for Bugzilla #635813 and #633037 + +* Mon Sep 20 2010 Chuck Ebbert - Linux 2.6.35.5 - Drop merged patches: 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch diff --git a/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch b/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch new file mode 100644 index 000000000..7c1512201 --- /dev/null +++ b/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch @@ -0,0 +1,55 @@ +From: Stanislaw Gruszka +Date: Tue, 14 Sep 2010 14:35:14 +0000 (+0200) +Subject: sched: Fix user time incorrectly accounted as system time on 32-bit +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fx86%2Flinux-2.6-tip.git;a=commitdiff_plain;h=e75e863dd5c7d96b91ebbd241da5328fc38a78cc + +sched: Fix user time incorrectly accounted as system time on 32-bit + +We have 32-bit variable overflow possibility when multiply in +task_times() and thread_group_times() functions. When the +overflow happens then the scaled utime value becomes erroneously +small and the scaled stime becomes i erroneously big. + +Reported here: + + https://bugzilla.redhat.com/show_bug.cgi?id=633037 + https://bugzilla.kernel.org/show_bug.cgi?id=16559 + +Reported-by: Michael Chapman +Reported-by: Ciriaco Garcia de Celis +Signed-off-by: Stanislaw Gruszka +Signed-off-by: Peter Zijlstra +Cc: Hidetoshi Seto +Cc: # 2.6.32.19+ (partially) and 2.6.33+ +LKML-Reference: <20100914143513.GB8415@redhat.com> +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched.c b/kernel/sched.c +index ed09d4f..dc85ceb 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -3513,9 +3513,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) + rtime = nsecs_to_cputime(p->se.sum_exec_runtime); + + if (total) { +- u64 temp; ++ u64 temp = rtime; + +- temp = (u64)(rtime * utime); ++ temp *= utime; + do_div(temp, total); + utime = (cputime_t)temp; + } else +@@ -3546,9 +3546,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) + rtime = nsecs_to_cputime(cputime.sum_exec_runtime); + + if (total) { +- u64 temp; ++ u64 temp = rtime; + +- temp = (u64)(rtime * cputime.utime); ++ temp *= cputime.utime; + do_div(temp, total); + utime = (cputime_t)temp; + } else diff --git a/sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch b/sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch new file mode 100644 index 000000000..ea7e48ec8 --- /dev/null +++ b/sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch @@ -0,0 +1,276 @@ +From: Venkatesh Pallipadi +Date: Tue, 18 May 2010 01:14:43 +0000 (-0700) +Subject: sched: Avoid side-effect of tickless idle on update_cpu_load +X-Git-Tag: v2.6.36-rc1~531^2~22 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fdf3e95d3916f18bf8703fb065499fdbc4dfe34c + +sched: Avoid side-effect of tickless idle on update_cpu_load + +tickless idle has a negative side effect on update_cpu_load(), which +in turn can affect load balancing behavior. + +update_cpu_load() is supposed to be called every tick, to keep track +of various load indicies. With tickless idle, there are no scheduler +ticks called on the idle CPUs. Idle CPUs may still do load balancing +(with idle_load_balance CPU) using the stale cpu_load. It will also +cause problems when all CPUs go idle for a while and become active +again. In this case loads would not degrade as expected. + +This is how rq->nr_load_updates change looks like under different +conditions: + + +All CPUS idle for 10 seconds (HZ=1000) +0 1621 +10 496 +11 139 +12 875 +13 1672 +14 12 +15 21 +1 1472 +2 2426 +3 1161 +4 2108 +5 1525 +6 701 +7 249 +8 766 +9 1967 + +One CPU busy rest idle for 10 seconds +0 10003 +10 601 +11 95 +12 966 +13 1597 +14 114 +15 98 +1 3457 +2 93 +3 6679 +4 1425 +5 1479 +6 595 +7 193 +8 633 +9 1687 + +All CPUs busy for 10 seconds +0 10026 +10 10026 +11 10026 +12 10026 +13 10025 +14 10025 +15 10025 +1 10026 +2 10026 +3 10026 +4 10026 +5 10026 +6 10026 +7 10026 +8 10026 +9 10026 + +That is update_cpu_load works properly only when all CPUs are busy. +If all are idle, all the CPUs get way lower updates. And when few +CPUs are busy and rest are idle, only busy and ilb CPU does proper +updates and rest of the idle CPUs will do lower updates. + +The patch keeps track of when a last update was done and fixes up +the load avg based on current time. + +On one of my test system SPECjbb with warehouse 1..numcpus, patch +improves throughput numbers by ~1% (average of 6 runs). On another +test system (with different domain hierarchy) there is no noticable +change in perf. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Peter Zijlstra +Cc: Thomas Gleixner +LKML-Reference: +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched.c b/kernel/sched.c +index f37a961..a757f6b 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -457,6 +457,7 @@ struct rq { + unsigned long nr_running; + #define CPU_LOAD_IDX_MAX 5 + unsigned long cpu_load[CPU_LOAD_IDX_MAX]; ++ unsigned long last_load_update_tick; + #ifdef CONFIG_NO_HZ + u64 nohz_stamp; + unsigned char in_nohz_recently; +@@ -1803,6 +1804,7 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares) + static void calc_load_account_idle(struct rq *this_rq); + static void update_sysctl(void); + static int get_update_sysctl_factor(void); ++static void update_cpu_load(struct rq *this_rq); + + static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) + { +@@ -3050,23 +3052,102 @@ static void calc_load_account_active(struct rq *this_rq) + } + + /* ++ * The exact cpuload at various idx values, calculated at every tick would be ++ * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load ++ * ++ * If a cpu misses updates for n-1 ticks (as it was idle) and update gets called ++ * on nth tick when cpu may be busy, then we have: ++ * load = ((2^idx - 1) / 2^idx)^(n-1) * load ++ * load = (2^idx - 1) / 2^idx) * load + 1 / 2^idx * cur_load ++ * ++ * decay_load_missed() below does efficient calculation of ++ * load = ((2^idx - 1) / 2^idx)^(n-1) * load ++ * avoiding 0..n-1 loop doing load = ((2^idx - 1) / 2^idx) * load ++ * ++ * The calculation is approximated on a 128 point scale. ++ * degrade_zero_ticks is the number of ticks after which load at any ++ * particular idx is approximated to be zero. ++ * degrade_factor is a precomputed table, a row for each load idx. ++ * Each column corresponds to degradation factor for a power of two ticks, ++ * based on 128 point scale. ++ * Example: ++ * row 2, col 3 (=12) says that the degradation at load idx 2 after ++ * 8 ticks is 12/128 (which is an approximation of exact factor 3^8/4^8). ++ * ++ * With this power of 2 load factors, we can degrade the load n times ++ * by looking at 1 bits in n and doing as many mult/shift instead of ++ * n mult/shifts needed by the exact degradation. ++ */ ++#define DEGRADE_SHIFT 7 ++static const unsigned char ++ degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128}; ++static const unsigned char ++ degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = { ++ {0, 0, 0, 0, 0, 0, 0, 0}, ++ {64, 32, 8, 0, 0, 0, 0, 0}, ++ {96, 72, 40, 12, 1, 0, 0}, ++ {112, 98, 75, 43, 15, 1, 0}, ++ {120, 112, 98, 76, 45, 16, 2} }; ++ ++/* ++ * Update cpu_load for any missed ticks, due to tickless idle. The backlog ++ * would be when CPU is idle and so we just decay the old load without ++ * adding any new load. ++ */ ++static unsigned long ++decay_load_missed(unsigned long load, unsigned long missed_updates, int idx) ++{ ++ int j = 0; ++ ++ if (!missed_updates) ++ return load; ++ ++ if (missed_updates >= degrade_zero_ticks[idx]) ++ return 0; ++ ++ if (idx == 1) ++ return load >> missed_updates; ++ ++ while (missed_updates) { ++ if (missed_updates % 2) ++ load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT; ++ ++ missed_updates >>= 1; ++ j++; ++ } ++ return load; ++} ++ ++/* + * Update rq->cpu_load[] statistics. This function is usually called every +- * scheduler tick (TICK_NSEC). ++ * scheduler tick (TICK_NSEC). With tickless idle this will not be called ++ * every tick. We fix it up based on jiffies. + */ + static void update_cpu_load(struct rq *this_rq) + { + unsigned long this_load = this_rq->load.weight; ++ unsigned long curr_jiffies = jiffies; ++ unsigned long pending_updates; + int i, scale; + + this_rq->nr_load_updates++; + ++ /* Avoid repeated calls on same jiffy, when moving in and out of idle */ ++ if (curr_jiffies == this_rq->last_load_update_tick) ++ return; ++ ++ pending_updates = curr_jiffies - this_rq->last_load_update_tick; ++ this_rq->last_load_update_tick = curr_jiffies; ++ + /* Update our load: */ +- for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) { ++ this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */ ++ for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) { + unsigned long old_load, new_load; + + /* scale is effectively 1 << i now, and >> i divides by scale */ + + old_load = this_rq->cpu_load[i]; ++ old_load = decay_load_missed(old_load, pending_updates - 1, i); + new_load = this_load; + /* + * Round up the averaging division if load is increasing. This +@@ -3074,9 +3155,15 @@ static void update_cpu_load(struct rq *this_rq) + * example. + */ + if (new_load > old_load) +- new_load += scale-1; +- this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i; ++ new_load += scale - 1; ++ ++ this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i; + } ++} ++ ++static void update_cpu_load_active(struct rq *this_rq) ++{ ++ update_cpu_load(this_rq); + + calc_load_account_active(this_rq); + } +@@ -3464,7 +3551,7 @@ void scheduler_tick(void) + + raw_spin_lock(&rq->lock); + update_rq_clock(rq); +- update_cpu_load(rq); ++ update_cpu_load_active(rq); + curr->sched_class->task_tick(rq, curr, 0); + raw_spin_unlock(&rq->lock); + +@@ -7688,6 +7775,9 @@ void __init sched_init(void) + + for (j = 0; j < CPU_LOAD_IDX_MAX; j++) + rq->cpu_load[j] = 0; ++ ++ rq->last_load_update_tick = jiffies; ++ + #ifdef CONFIG_SMP + rq->sd = NULL; + rq->rd = NULL; +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index eed35ed..22b8b4f 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3420,9 +3420,12 @@ static void run_rebalance_domains(struct softirq_action *h) + if (need_resched()) + break; + ++ rq = cpu_rq(balance_cpu); ++ raw_spin_lock_irq(&rq->lock); ++ update_cpu_load(rq); ++ raw_spin_unlock_irq(&rq->lock); + rebalance_domains(balance_cpu, CPU_IDLE); + +- rq = cpu_rq(balance_cpu); + if (time_after(this_rq->next_balance, rq->next_balance)) + this_rq->next_balance = rq->next_balance; + } diff --git a/sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch b/sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch new file mode 100644 index 000000000..622e9f129 --- /dev/null +++ b/sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch @@ -0,0 +1,651 @@ +From: Venkatesh Pallipadi +Date: Sat, 22 May 2010 00:09:41 +0000 (-0700) +Subject: sched: Change nohz idle load balancing logic to push model +X-Git-Tag: v2.6.36-rc1~531^2~21 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=83cd4fe27ad8446619b2e030b171b858501de87d + +sched: Change nohz idle load balancing logic to push model + +In the new push model, all idle CPUs indeed go into nohz mode. There is +still the concept of idle load balancer (performing the load balancing +on behalf of all the idle cpu's in the system). Busy CPU kicks the nohz +balancer when any of the nohz CPUs need idle load balancing. +The kickee CPU does the idle load balancing on behalf of all idle CPUs +instead of the normal idle balance. + +This addresses the below two problems with the current nohz ilb logic: +* the idle load balancer continued to have periodic ticks during idle and + wokeup frequently, even though it did not have any rebalancing to do on + behalf of any of the idle CPUs. +* On x86 and CPUs that have APIC timer stoppage on idle CPUs, this + periodic wakeup can result in a periodic additional interrupt on a CPU + doing the timer broadcast. + +Also currently we are migrating the unpinned timers from an idle to the cpu +doing idle load balancing (when all the cpus in the system are idle, +there is no idle load balancing cpu and timers get added to the same idle cpu +where the request was made. So the existing optimization works only on semi idle +system). + +And In semi idle system, we no longer have periodic ticks on the idle load +balancer CPU. Using that cpu will add more delays to the timers than intended +(as that cpu's timer base may not be uptodate wrt jiffies etc). This was +causing mysterious slowdowns during boot etc. + +For now, in the semi idle case, use the nearest busy cpu for migrating timers +from an idle cpu. This is good for power-savings anyway. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Suresh Siddha +Signed-off-by: Peter Zijlstra +Cc: Thomas Gleixner +LKML-Reference: <1274486981.2840.46.camel@sbs-t61.sc.intel.com> +Signed-off-by: Ingo Molnar +--- + +[ backported for 2.6.35 ] + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index c2d4316..a3e5b1c 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -271,13 +271,10 @@ extern int runqueue_is_locked(int cpu); + + extern cpumask_var_t nohz_cpu_mask; + #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ) +-extern int select_nohz_load_balancer(int cpu); +-extern int get_nohz_load_balancer(void); ++extern void select_nohz_load_balancer(int stop_tick); ++extern int get_nohz_timer_target(void); + #else +-static inline int select_nohz_load_balancer(int cpu) +-{ +- return 0; +-} ++static inline void select_nohz_load_balancer(int stop_tick) { } + #endif + + /* +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index 5c69e99..e934339 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -144,12 +144,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, + static int hrtimer_get_target(int this_cpu, int pinned) + { + #ifdef CONFIG_NO_HZ +- if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) { +- int preferred_cpu = get_nohz_load_balancer(); +- +- if (preferred_cpu >= 0) +- return preferred_cpu; +- } ++ if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) ++ return get_nohz_timer_target(); + #endif + return this_cpu; + } +diff --git a/kernel/sched.c b/kernel/sched.c +index a757f6b..132950b 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -460,7 +460,7 @@ struct rq { + unsigned long last_load_update_tick; + #ifdef CONFIG_NO_HZ + u64 nohz_stamp; +- unsigned char in_nohz_recently; ++ unsigned char nohz_balance_kick; + #endif + unsigned int skip_clock_update; + +@@ -1195,6 +1195,27 @@ static void resched_cpu(int cpu) + + #ifdef CONFIG_NO_HZ + /* ++ * In the semi idle case, use the nearest busy cpu for migrating timers ++ * from an idle cpu. This is good for power-savings. ++ * ++ * We don't do similar optimization for completely idle system, as ++ * selecting an idle cpu will add more delays to the timers than intended ++ * (as that cpu's timer base may not be uptodate wrt jiffies etc). ++ */ ++int get_nohz_timer_target(void) ++{ ++ int cpu = smp_processor_id(); ++ int i; ++ struct sched_domain *sd; ++ ++ for_each_domain(cpu, sd) { ++ for_each_cpu(i, sched_domain_span(sd)) ++ if (!idle_cpu(i)) ++ return i; ++ } ++ return cpu; ++} ++/* + * When add_timer_on() enqueues a timer into the timer wheel of an + * idle CPU then this timer might expire before the next timer event + * which is scheduled to wake up that CPU. In case of a completely +@@ -7791,6 +7812,10 @@ void __init sched_init(void) + rq->idle_stamp = 0; + rq->avg_idle = 2*sysctl_sched_migration_cost; + rq_attach_root(rq, &def_root_domain); ++#ifdef CONFIG_NO_HZ ++ rq->nohz_balance_kick = 0; ++ init_sched_softirq_csd(&per_cpu(remote_sched_softirq_cb, i)); ++#endif + #endif + init_rq_hrtick(rq); + atomic_set(&rq->nr_iowait, 0); +@@ -7835,8 +7860,11 @@ void __init sched_init(void) + zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT); + #ifdef CONFIG_SMP + #ifdef CONFIG_NO_HZ +- zalloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT); +- alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT); ++ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); ++ alloc_cpumask_var(&nohz.grp_idle_mask, GFP_NOWAIT); ++ atomic_set(&nohz.load_balancer, nr_cpu_ids); ++ atomic_set(&nohz.first_pick_cpu, nr_cpu_ids); ++ atomic_set(&nohz.second_pick_cpu, nr_cpu_ids); + #endif + /* May be allocated at isolcpus cmdline parse time */ + if (cpu_isolated_map == NULL) +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index 22b8b4f..6ee2e0a 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3091,13 +3091,40 @@ out_unlock: + } + + #ifdef CONFIG_NO_HZ ++ ++static DEFINE_PER_CPU(struct call_single_data, remote_sched_softirq_cb); ++ ++static void trigger_sched_softirq(void *data) ++{ ++ raise_softirq_irqoff(SCHED_SOFTIRQ); ++} ++ ++static inline void init_sched_softirq_csd(struct call_single_data *csd) ++{ ++ csd->func = trigger_sched_softirq; ++ csd->info = NULL; ++ csd->flags = 0; ++ csd->priv = 0; ++} ++ ++/* ++ * idle load balancing details ++ * - One of the idle CPUs nominates itself as idle load_balancer, while ++ * entering idle. ++ * - This idle load balancer CPU will also go into tickless mode when ++ * it is idle, just like all other idle CPUs ++ * - When one of the busy CPUs notice that there may be an idle rebalancing ++ * needed, they will kick the idle load balancer, which then does idle ++ * load balancing for all the idle CPUs. ++ */ + static struct { + atomic_t load_balancer; +- cpumask_var_t cpu_mask; +- cpumask_var_t ilb_grp_nohz_mask; +-} nohz ____cacheline_aligned = { +- .load_balancer = ATOMIC_INIT(-1), +-}; ++ atomic_t first_pick_cpu; ++ atomic_t second_pick_cpu; ++ cpumask_var_t idle_cpus_mask; ++ cpumask_var_t grp_idle_mask; ++ unsigned long next_balance; /* in jiffy units */ ++} nohz ____cacheline_aligned; + + int get_nohz_load_balancer(void) + { +@@ -3151,17 +3178,17 @@ static inline struct sched_domain *lowest_flag_domain(int cpu, int flag) + */ + static inline int is_semi_idle_group(struct sched_group *ilb_group) + { +- cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask, ++ cpumask_and(nohz.grp_idle_mask, nohz.idle_cpus_mask, + sched_group_cpus(ilb_group)); + + /* + * A sched_group is semi-idle when it has atleast one busy cpu + * and atleast one idle cpu. + */ +- if (cpumask_empty(nohz.ilb_grp_nohz_mask)) ++ if (cpumask_empty(nohz.grp_idle_mask)) + return 0; + +- if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group))) ++ if (cpumask_equal(nohz.grp_idle_mask, sched_group_cpus(ilb_group))) + return 0; + + return 1; +@@ -3194,7 +3221,7 @@ static int find_new_ilb(int cpu) + * Optimize for the case when we have no idle CPUs or only one + * idle CPU. Don't walk the sched_domain hierarchy in such cases + */ +- if (cpumask_weight(nohz.cpu_mask) < 2) ++ if (cpumask_weight(nohz.idle_cpus_mask) < 2) + goto out_done; + + for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) { +@@ -3202,7 +3229,7 @@ static int find_new_ilb(int cpu) + + do { + if (is_semi_idle_group(ilb_group)) +- return cpumask_first(nohz.ilb_grp_nohz_mask); ++ return cpumask_first(nohz.grp_idle_mask); + + ilb_group = ilb_group->next; + +@@ -3210,98 +3237,116 @@ static int find_new_ilb(int cpu) + } + + out_done: +- return cpumask_first(nohz.cpu_mask); ++ return nr_cpu_ids; + } + #else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ + static inline int find_new_ilb(int call_cpu) + { +- return cpumask_first(nohz.cpu_mask); ++ return nr_cpu_ids; + } + #endif + + /* ++ * Kick a CPU to do the nohz balancing, if it is time for it. We pick the ++ * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle ++ * CPU (if there is one). ++ */ ++static void nohz_balancer_kick(int cpu) ++{ ++ int ilb_cpu; ++ ++ nohz.next_balance++; ++ ++ ilb_cpu = get_nohz_load_balancer(); ++ ++ if (ilb_cpu >= nr_cpu_ids) { ++ ilb_cpu = cpumask_first(nohz.idle_cpus_mask); ++ if (ilb_cpu >= nr_cpu_ids) ++ return; ++ } ++ ++ if (!cpu_rq(ilb_cpu)->nohz_balance_kick) { ++ struct call_single_data *cp; ++ ++ cpu_rq(ilb_cpu)->nohz_balance_kick = 1; ++ cp = &per_cpu(remote_sched_softirq_cb, cpu); ++ __smp_call_function_single(ilb_cpu, cp, 0); ++ } ++ return; ++} ++ ++/* + * This routine will try to nominate the ilb (idle load balancing) + * owner among the cpus whose ticks are stopped. ilb owner will do the idle +- * load balancing on behalf of all those cpus. If all the cpus in the system +- * go into this tickless mode, then there will be no ilb owner (as there is +- * no need for one) and all the cpus will sleep till the next wakeup event +- * arrives... +- * +- * For the ilb owner, tick is not stopped. And this tick will be used +- * for idle load balancing. ilb owner will still be part of +- * nohz.cpu_mask.. ++ * load balancing on behalf of all those cpus. + * +- * While stopping the tick, this cpu will become the ilb owner if there +- * is no other owner. And will be the owner till that cpu becomes busy +- * or if all cpus in the system stop their ticks at which point +- * there is no need for ilb owner. ++ * When the ilb owner becomes busy, we will not have new ilb owner until some ++ * idle CPU wakes up and goes back to idle or some busy CPU tries to kick ++ * idle load balancing by kicking one of the idle CPUs. + * +- * When the ilb owner becomes busy, it nominates another owner, during the +- * next busy scheduler_tick() ++ * Ticks are stopped for the ilb owner as well, with busy CPU kicking this ++ * ilb owner CPU in future (when there is a need for idle load balancing on ++ * behalf of all idle CPUs). + */ +-int select_nohz_load_balancer(int stop_tick) ++void select_nohz_load_balancer(int stop_tick) + { + int cpu = smp_processor_id(); + + if (stop_tick) { +- cpu_rq(cpu)->in_nohz_recently = 1; +- + if (!cpu_active(cpu)) { + if (atomic_read(&nohz.load_balancer) != cpu) +- return 0; ++ return; + + /* + * If we are going offline and still the leader, + * give up! + */ +- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) ++ if (atomic_cmpxchg(&nohz.load_balancer, cpu, ++ nr_cpu_ids) != cpu) + BUG(); + +- return 0; ++ return; + } + +- cpumask_set_cpu(cpu, nohz.cpu_mask); ++ cpumask_set_cpu(cpu, nohz.idle_cpus_mask); + +- /* time for ilb owner also to sleep */ +- if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) { +- if (atomic_read(&nohz.load_balancer) == cpu) +- atomic_set(&nohz.load_balancer, -1); +- return 0; +- } ++ if (atomic_read(&nohz.first_pick_cpu) == cpu) ++ atomic_cmpxchg(&nohz.first_pick_cpu, cpu, nr_cpu_ids); ++ if (atomic_read(&nohz.second_pick_cpu) == cpu) ++ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids); + +- if (atomic_read(&nohz.load_balancer) == -1) { +- /* make me the ilb owner */ +- if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1) +- return 1; +- } else if (atomic_read(&nohz.load_balancer) == cpu) { ++ if (atomic_read(&nohz.load_balancer) >= nr_cpu_ids) { + int new_ilb; + +- if (!(sched_smt_power_savings || +- sched_mc_power_savings)) +- return 1; ++ /* make me the ilb owner */ ++ if (atomic_cmpxchg(&nohz.load_balancer, nr_cpu_ids, ++ cpu) != nr_cpu_ids) ++ return; ++ + /* + * Check to see if there is a more power-efficient + * ilb. + */ + new_ilb = find_new_ilb(cpu); + if (new_ilb < nr_cpu_ids && new_ilb != cpu) { +- atomic_set(&nohz.load_balancer, -1); ++ atomic_set(&nohz.load_balancer, nr_cpu_ids); + resched_cpu(new_ilb); +- return 0; ++ return; + } +- return 1; ++ return; + } + } else { +- if (!cpumask_test_cpu(cpu, nohz.cpu_mask)) +- return 0; ++ if (!cpumask_test_cpu(cpu, nohz.idle_cpus_mask)) ++ return; + +- cpumask_clear_cpu(cpu, nohz.cpu_mask); ++ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask); + + if (atomic_read(&nohz.load_balancer) == cpu) +- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) ++ if (atomic_cmpxchg(&nohz.load_balancer, cpu, ++ nr_cpu_ids) != cpu) + BUG(); + } +- return 0; ++ return; + } + #endif + +@@ -3383,11 +3428,101 @@ out: + rq->next_balance = next_balance; + } + ++#ifdef CONFIG_NO_HZ + /* +- * run_rebalance_domains is triggered when needed from the scheduler tick. +- * In CONFIG_NO_HZ case, the idle load balance owner will do the ++ * In CONFIG_NO_HZ case, the idle balance kickee will do the + * rebalancing for all the cpus for whom scheduler ticks are stopped. + */ ++static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) ++{ ++ struct rq *this_rq = cpu_rq(this_cpu); ++ struct rq *rq; ++ int balance_cpu; ++ ++ if (idle != CPU_IDLE || !this_rq->nohz_balance_kick) ++ return; ++ ++ for_each_cpu(balance_cpu, nohz.idle_cpus_mask) { ++ if (balance_cpu == this_cpu) ++ continue; ++ ++ /* ++ * If this cpu gets work to do, stop the load balancing ++ * work being done for other cpus. Next load ++ * balancing owner will pick it up. ++ */ ++ if (need_resched()) { ++ this_rq->nohz_balance_kick = 0; ++ break; ++ } ++ ++ raw_spin_lock_irq(&this_rq->lock); ++ update_cpu_load(this_rq); ++ raw_spin_unlock_irq(&this_rq->lock); ++ ++ rebalance_domains(balance_cpu, CPU_IDLE); ++ ++ rq = cpu_rq(balance_cpu); ++ if (time_after(this_rq->next_balance, rq->next_balance)) ++ this_rq->next_balance = rq->next_balance; ++ } ++ nohz.next_balance = this_rq->next_balance; ++ this_rq->nohz_balance_kick = 0; ++} ++ ++/* ++ * Current heuristic for kicking the idle load balancer ++ * - first_pick_cpu is the one of the busy CPUs. It will kick ++ * idle load balancer when it has more than one process active. This ++ * eliminates the need for idle load balancing altogether when we have ++ * only one running process in the system (common case). ++ * - If there are more than one busy CPU, idle load balancer may have ++ * to run for active_load_balance to happen (i.e., two busy CPUs are ++ * SMT or core siblings and can run better if they move to different ++ * physical CPUs). So, second_pick_cpu is the second of the busy CPUs ++ * which will kick idle load balancer as soon as it has any load. ++ */ ++static inline int nohz_kick_needed(struct rq *rq, int cpu) ++{ ++ unsigned long now = jiffies; ++ int ret; ++ int first_pick_cpu, second_pick_cpu; ++ ++ if (time_before(now, nohz.next_balance)) ++ return 0; ++ ++ if (!rq->nr_running) ++ return 0; ++ ++ first_pick_cpu = atomic_read(&nohz.first_pick_cpu); ++ second_pick_cpu = atomic_read(&nohz.second_pick_cpu); ++ ++ if (first_pick_cpu < nr_cpu_ids && first_pick_cpu != cpu && ++ second_pick_cpu < nr_cpu_ids && second_pick_cpu != cpu) ++ return 0; ++ ++ ret = atomic_cmpxchg(&nohz.first_pick_cpu, nr_cpu_ids, cpu); ++ if (ret == nr_cpu_ids || ret == cpu) { ++ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids); ++ if (rq->nr_running > 1) ++ return 1; ++ } else { ++ ret = atomic_cmpxchg(&nohz.second_pick_cpu, nr_cpu_ids, cpu); ++ if (ret == nr_cpu_ids || ret == cpu) { ++ if (rq->nr_running) ++ return 1; ++ } ++ } ++ return 0; ++} ++#else ++static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) { } ++#endif ++ ++/* ++ * run_rebalance_domains is triggered when needed from the scheduler tick. ++ * Also triggered for nohz idle balancing (with nohz_balancing_kick set). ++ */ + static void run_rebalance_domains(struct softirq_action *h) + { + int this_cpu = smp_processor_id(); +@@ -3397,40 +3532,12 @@ static void run_rebalance_domains(struct softirq_action *h) + + rebalance_domains(this_cpu, idle); + +-#ifdef CONFIG_NO_HZ + /* +- * If this cpu is the owner for idle load balancing, then do the ++ * If this cpu has a pending nohz_balance_kick, then do the + * balancing on behalf of the other idle cpus whose ticks are + * stopped. + */ +- if (this_rq->idle_at_tick && +- atomic_read(&nohz.load_balancer) == this_cpu) { +- struct rq *rq; +- int balance_cpu; +- +- for_each_cpu(balance_cpu, nohz.cpu_mask) { +- if (balance_cpu == this_cpu) +- continue; +- +- /* +- * If this cpu gets work to do, stop the load balancing +- * work being done for other cpus. Next load +- * balancing owner will pick it up. +- */ +- if (need_resched()) +- break; +- +- rq = cpu_rq(balance_cpu); +- raw_spin_lock_irq(&rq->lock); +- update_cpu_load(rq); +- raw_spin_unlock_irq(&rq->lock); +- rebalance_domains(balance_cpu, CPU_IDLE); +- +- if (time_after(this_rq->next_balance, rq->next_balance)) +- this_rq->next_balance = rq->next_balance; +- } +- } +-#endif ++ nohz_idle_balance(this_cpu, idle); + } + + static inline int on_null_domain(int cpu) +@@ -3440,57 +3547,17 @@ static inline int on_null_domain(int cpu) + + /* + * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing. +- * +- * In case of CONFIG_NO_HZ, this is the place where we nominate a new +- * idle load balancing owner or decide to stop the periodic load balancing, +- * if the whole system is idle. + */ + static inline void trigger_load_balance(struct rq *rq, int cpu) + { +-#ifdef CONFIG_NO_HZ +- /* +- * If we were in the nohz mode recently and busy at the current +- * scheduler tick, then check if we need to nominate new idle +- * load balancer. +- */ +- if (rq->in_nohz_recently && !rq->idle_at_tick) { +- rq->in_nohz_recently = 0; +- +- if (atomic_read(&nohz.load_balancer) == cpu) { +- cpumask_clear_cpu(cpu, nohz.cpu_mask); +- atomic_set(&nohz.load_balancer, -1); +- } +- +- if (atomic_read(&nohz.load_balancer) == -1) { +- int ilb = find_new_ilb(cpu); +- +- if (ilb < nr_cpu_ids) +- resched_cpu(ilb); +- } +- } +- +- /* +- * If this cpu is idle and doing idle load balancing for all the +- * cpus with ticks stopped, is it time for that to stop? +- */ +- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu && +- cpumask_weight(nohz.cpu_mask) == num_online_cpus()) { +- resched_cpu(cpu); +- return; +- } +- +- /* +- * If this cpu is idle and the idle load balancing is done by +- * someone else, then no need raise the SCHED_SOFTIRQ +- */ +- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu && +- cpumask_test_cpu(cpu, nohz.cpu_mask)) +- return; +-#endif + /* Don't need to rebalance while attached to NULL domain */ + if (time_after_eq(jiffies, rq->next_balance) && + likely(!on_null_domain(cpu))) + raise_softirq(SCHED_SOFTIRQ); ++#ifdef CONFIG_NO_HZ ++ else if (nohz_kick_needed(rq, cpu) && likely(!on_null_domain(cpu))) ++ nohz_balancer_kick(cpu); ++#endif + } + + static void rq_online_fair(struct rq *rq) +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index 1d7b9bc..5f171f0 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -408,13 +408,7 @@ void tick_nohz_stop_sched_tick(int inidle) + * the scheduler tick in nohz_restart_sched_tick. + */ + if (!ts->tick_stopped) { +- if (select_nohz_load_balancer(1)) { +- /* +- * sched tick not stopped! +- */ +- cpumask_clear_cpu(cpu, nohz_cpu_mask); +- goto out; +- } ++ select_nohz_load_balancer(1); + + ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); + ts->tick_stopped = 1; +diff --git a/kernel/timer.c b/kernel/timer.c +index ee305c8..48d6aec 100644 +--- a/kernel/timer.c ++++ b/kernel/timer.c +@@ -679,12 +679,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, + cpu = smp_processor_id(); + + #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) +- if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) { +- int preferred_cpu = get_nohz_load_balancer(); +- +- if (preferred_cpu >= 0) +- cpu = preferred_cpu; +- } ++ if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) ++ cpu = get_nohz_timer_target(); + #endif + new_base = per_cpu(tvec_bases, cpu); + diff --git a/sched-15-update-rq-clock-for-nohz-balanced-cpus.patch b/sched-15-update-rq-clock-for-nohz-balanced-cpus.patch new file mode 100644 index 000000000..7c5432e44 --- /dev/null +++ b/sched-15-update-rq-clock-for-nohz-balanced-cpus.patch @@ -0,0 +1,28 @@ +From: Suresh Siddha +Date: Fri, 9 Jul 2010 13:19:54 +0000 (+0200) +Subject: sched: Update rq->clock for nohz balanced cpus +X-Git-Tag: v2.6.36-rc1~531^2~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=5343bdb8fd076f16edc9d113a9e35e2a1d1f4966 + +sched: Update rq->clock for nohz balanced cpus + +Suresh spotted that we don't update the rq->clock in the nohz +load-balancer path. + +Signed-off-by: Peter Zijlstra +LKML-Reference: <1278626014.2834.74.camel@sbs-t61.sc.intel.com> +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index b4da534..e44a591 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3596,6 +3596,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) + } + + raw_spin_lock_irq(&this_rq->lock); ++ update_rq_clock(this_rq); + update_cpu_load(this_rq); + raw_spin_unlock_irq(&this_rq->lock); + diff --git a/sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch b/sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch new file mode 100644 index 000000000..466dd2d33 --- /dev/null +++ b/sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch @@ -0,0 +1,38 @@ +From: Peter Zijlstra +Date: Thu, 19 Aug 2010 11:31:43 +0000 (+0200) +Subject: sched: Fix rq->clock synchronization when migrating tasks +X-Git-Tag: v2.6.36-rc3~25^2~1 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=861d034ee814917a83bd5de4b26e3b8336ddeeb8 + +sched: Fix rq->clock synchronization when migrating tasks + +sched_fork() -- we do task placement in ->task_fork_fair() ensure we + update_rq_clock() so we work with current time. We leave the vruntime + in relative state, so the time delay until wake_up_new_task() doesn't + matter. + +wake_up_new_task() -- Since task_fork_fair() left p->vruntime in + relative state we can safely migrate, the activate_task() on the + remote rq will call update_rq_clock() and causes the clock to be + synced (enough). + +Tested-by: Jack Daniel +Tested-by: Philby John +Signed-off-by: Peter Zijlstra +LKML-Reference: <1281002322.1923.1708.camel@laptop> +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index 806d1b2..ab661eb 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3752,6 +3752,8 @@ static void task_fork_fair(struct task_struct *p) + + raw_spin_lock_irqsave(&rq->lock, flags); + ++ update_rq_clock(rq); ++ + if (unlikely(task_cpu(p) != this_cpu)) + __set_task_cpu(p, this_cpu); + diff --git a/sched-25-move-sched_avg_update-to-update_cpu_load.patch b/sched-25-move-sched_avg_update-to-update_cpu_load.patch new file mode 100644 index 000000000..556c8cee5 --- /dev/null +++ b/sched-25-move-sched_avg_update-to-update_cpu_load.patch @@ -0,0 +1,58 @@ +From: Suresh Siddha +Date: Mon, 23 Aug 2010 20:42:51 +0000 (-0700) +Subject: sched: Move sched_avg_update() to update_cpu_load() +X-Git-Tag: v2.6.36-rc4~8^2~1 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=da2b71edd8a7db44fe1746261410a981f3e03632 + +sched: Move sched_avg_update() to update_cpu_load() + +Currently sched_avg_update() (which updates rt_avg stats in the rq) +is getting called from scale_rt_power() (in the load balance context) +which doesn't take rq->lock. + +Fix it by moving the sched_avg_update() to more appropriate +update_cpu_load() where the CFS load gets updated as well. + +Signed-off-by: Suresh Siddha +Signed-off-by: Peter Zijlstra +LKML-Reference: <1282596171.2694.3.camel@sbsiddha-MOBL3> +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched.c b/kernel/sched.c +index 09b574e..ed09d4f 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -1294,6 +1294,10 @@ static void resched_task(struct task_struct *p) + static void sched_rt_avg_update(struct rq *rq, u64 rt_delta) + { + } ++ ++static void sched_avg_update(struct rq *rq) ++{ ++} + #endif /* CONFIG_SMP */ + + #if BITS_PER_LONG == 32 +@@ -3182,6 +3186,8 @@ static void update_cpu_load(struct rq *this_rq) + + this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i; + } ++ ++ sched_avg_update(this_rq); + } + + static void update_cpu_load_active(struct rq *this_rq) +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index ab661eb..f53ec75 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -2268,8 +2268,6 @@ unsigned long scale_rt_power(int cpu) + struct rq *rq = cpu_rq(cpu); + u64 total, available; + +- sched_avg_update(rq); +- + total = sched_avg_period() + (rq->clock - rq->age_stamp); + available = total - rq->rt_avg; + From 027325ab5323d32206e91dbb5c71ddbbc7bef1f4 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 21 Sep 2010 11:30:59 -0400 Subject: [PATCH 065/277] Add new btusb ids for MacBookPro from wwoods@ --- btusb-macbookpro-6-2.patch | 41 +++++++++++++++++++++++++++++++++++++ btusb-macbookpro-7-1.patch | 42 ++++++++++++++++++++++++++++++++++++++ kernel.spec | 9 ++++++++ 3 files changed, 92 insertions(+) create mode 100644 btusb-macbookpro-6-2.patch create mode 100644 btusb-macbookpro-7-1.patch diff --git a/btusb-macbookpro-6-2.patch b/btusb-macbookpro-6-2.patch new file mode 100644 index 000000000..d65a30960 --- /dev/null +++ b/btusb-macbookpro-6-2.patch @@ -0,0 +1,41 @@ +From kernel-bounces@lists.fedoraproject.org Fri Sep 17 17:09:15 2010 +From: Will Woods +To: Marcel Holtmann +Subject: [PATCH 2/2] bluetooth: add support for controller in MacBookPro6,2 +Date: Fri, 17 Sep 2010 17:09:21 -0400 + +Once again the device class is ff(vend.) instead of e0(wlcon). + +output from 'usb-devices': +T: Bus=01 Lev=03 Prnt=03 Port=02 Cnt=03 Dev#= 8 Spd=12 MxCh= 0 +D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=05ac ProdID=8218 Rev=00.22 +S: Manufacturer=Apple Inc. +S: Product=Bluetooth USB Host Controller +C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) +I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) + +Signed-off-by: Will Woods +--- + drivers/bluetooth/btusb.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index eac44e4..320e798 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,9 @@ static struct usb_device_id btusb_table[] = { + /* Apple iMac11,1 */ + { USB_DEVICE(0x05ac, 0x8215) }, + ++ /* Apple MacBookPro6,2 */ ++ { USB_DEVICE(0x05ac, 0x8218) }, ++ + /* AVM BlueFRITZ! USB v2.0 */ + { USB_DEVICE(0x057c, 0x3800) }, + +-- +1.7.2.3 diff --git a/btusb-macbookpro-7-1.patch b/btusb-macbookpro-7-1.patch new file mode 100644 index 000000000..3e07dd583 --- /dev/null +++ b/btusb-macbookpro-7-1.patch @@ -0,0 +1,42 @@ +From kernel-bounces@lists.fedoraproject.org Fri Sep 17 17:09:18 2010 +From: Will Woods +To: Marcel Holtmann +Subject: [PATCH 1/2] bluetooth: add support for controller in MacBookPro7,1 +Date: Fri, 17 Sep 2010 17:09:20 -0400 + +As with iMac11,1 the device class is ff(vend.) instead of e0(wlcon). + +output from 'usb-devices': +T: Bus=04 Lev=02 Prnt=04 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 +D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=05ac ProdID=8213 Rev=01.86 +S: Manufacturer=Apple Inc. +S: Product=Bluetooth USB Host Controller +S: SerialNumber=58B0359C28ED +C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) +I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=00 Driver=(none) + +Signed-off-by: Will Woods +--- + drivers/bluetooth/btusb.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d22ce3c..eac44e4 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -59,6 +59,9 @@ static struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ + { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, + ++ /* Apple MacBookPro7,1 */ ++ { USB_DEVICE(0x05ac, 0x8213) }, ++ + /* Apple iMac11,1 */ + { USB_DEVICE(0x05ac, 0x8215) }, + +-- +1.7.2.3 diff --git a/kernel.spec b/kernel.spec index 62004ac79..8c8d920c4 100644 --- a/kernel.spec +++ b/kernel.spec @@ -749,6 +749,9 @@ Patch12575: sched-15-update-rq-clock-for-nohz-balanced-cpus.patch Patch12580: sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch Patch12585: sched-25-move-sched_avg_update-to-update_cpu_load.patch +Patch13600: btusb-macbookpro-6-2.patch +Patch13601: btusb-macbookpro-7-1.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1386,6 +1389,9 @@ ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch ApplyPatch sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch ApplyPatch sched-25-move-sched_avg_update-to-update_cpu_load.patch +ApplyPatch btusb-macbookpro-7-1.patch +ApplyPatch btusb-macbookpro-6-2.patch + # END OF PATCH APPLICATIONS %endif @@ -1972,6 +1978,9 @@ fi # and build. %changelog +* Tue Sep 21 2010 Kyle McMartin +- Add new btusb ids for MacBookPro from wwoods@. + * Tue Sep 21 2010 Chuck Ebbert 2.6.35.5-29 - Scheduler fixes for Bugzilla #635813 and #633037 From 69a476baa962effbf7baaeef54cbc867e89a9f28 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Wed, 22 Sep 2010 08:40:20 -0400 Subject: [PATCH 066/277] Fix possible lockup with new scheduler idle balance code. --- kernel.spec | 5 +++ sched-30-sched-fix-nohz-balance-kick.patch | 39 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 sched-30-sched-fix-nohz-balance-kick.patch diff --git a/kernel.spec b/kernel.spec index 8c8d920c4..f14fb241c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -748,6 +748,7 @@ Patch12570: sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch Patch12575: sched-15-update-rq-clock-for-nohz-balanced-cpus.patch Patch12580: sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch Patch12585: sched-25-move-sched_avg_update-to-update_cpu_load.patch +Patch12590: sched-30-sched-fix-nohz-balance-kick.patch Patch13600: btusb-macbookpro-6-2.patch Patch13601: btusb-macbookpro-7-1.patch @@ -1388,6 +1389,7 @@ ApplyPatch sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch ApplyPatch sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch ApplyPatch sched-25-move-sched_avg_update-to-update_cpu_load.patch +ApplyPatch sched-30-sched-fix-nohz-balance-kick.patch ApplyPatch btusb-macbookpro-7-1.patch ApplyPatch btusb-macbookpro-6-2.patch @@ -1978,6 +1980,9 @@ fi # and build. %changelog +* Wed Sep 22 2010 Chuck Ebbert +- Fix possible lockup with new scheduler idle balance code. + * Tue Sep 21 2010 Kyle McMartin - Add new btusb ids for MacBookPro from wwoods@. diff --git a/sched-30-sched-fix-nohz-balance-kick.patch b/sched-30-sched-fix-nohz-balance-kick.patch new file mode 100644 index 000000000..debad528a --- /dev/null +++ b/sched-30-sched-fix-nohz-balance-kick.patch @@ -0,0 +1,39 @@ +From: Suresh Siddha +Date: Mon, 13 Sep 2010 18:02:21 +0000 (-0700) +Subject: sched: Fix nohz balance kick +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f6c3f1686e7ec1dd8725a9a3dcb857dfd0c7a5bf + +sched: Fix nohz balance kick + +There's a situation where the nohz balancer will try to wake itself: + +cpu-x is idle which is also ilb_cpu +got a scheduler tick during idle +and the nohz_kick_needed() in trigger_load_balance() checks for +rq_x->nr_running which might not be zero (because of someone waking a +task on this rq etc) and this leads to the situation of the cpu-x +sending a kick to itself. + +And this can cause a lockup. + +Avoid this by not marking ourself eligible for kicking. + +Signed-off-by: Suresh Siddha +Signed-off-by: Peter Zijlstra +LKML-Reference: <1284400941.2684.19.camel@sbsiddha-MOBL3.sc.intel.com> +Signed-off-by: Ingo Molnar +--- + +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index a171138..db3f674 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3630,7 +3630,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu) + if (time_before(now, nohz.next_balance)) + return 0; + +- if (!rq->nr_running) ++ if (rq->idle_at_tick) + return 0; + + first_pick_cpu = atomic_read(&nohz.first_pick_cpu); From b2398b3ef3528a5182ca6d0c17e51666e03a6430 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Wed, 22 Sep 2010 11:54:31 -0400 Subject: [PATCH 067/277] Dump stack on failed ATA commands in pata_it821x driver (#632753) --- kernel.spec | 6 ++++ libata-it821x-dump-stack-on-cache-flush.patch | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 libata-it821x-dump-stack-on-cache-flush.patch diff --git a/kernel.spec b/kernel.spec index f14fb241c..7392cb603 100644 --- a/kernel.spec +++ b/kernel.spec @@ -753,6 +753,8 @@ Patch12590: sched-30-sched-fix-nohz-balance-kick.patch Patch13600: btusb-macbookpro-6-2.patch Patch13601: btusb-macbookpro-7-1.patch +Patch13610: libata-it821x-dump-stack-on-cache-flush.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1394,6 +1396,9 @@ ApplyPatch sched-30-sched-fix-nohz-balance-kick.patch ApplyPatch btusb-macbookpro-7-1.patch ApplyPatch btusb-macbookpro-6-2.patch +# temporary patch, dump stack on failed it821x commands +ApplyPatch libata-it821x-dump-stack-on-cache-flush.patch + # END OF PATCH APPLICATIONS %endif @@ -1982,6 +1987,7 @@ fi %changelog * Wed Sep 22 2010 Chuck Ebbert - Fix possible lockup with new scheduler idle balance code. +- Dump stack on failed ATA commands in pata_it821x driver (#632753) * Tue Sep 21 2010 Kyle McMartin - Add new btusb ids for MacBookPro from wwoods@. diff --git a/libata-it821x-dump-stack-on-cache-flush.patch b/libata-it821x-dump-stack-on-cache-flush.patch new file mode 100644 index 000000000..8413066a2 --- /dev/null +++ b/libata-it821x-dump-stack-on-cache-flush.patch @@ -0,0 +1,30 @@ +Dump stack once on unsupported commands to see who is submitting them. +(#632753) + +--- linux-2.6.34.noarch.orig/drivers/ata/pata_it821x.c ++++ linux-2.6.34.noarch/drivers/ata/pata_it821x.c +@@ -399,6 +399,16 @@ static void it821x_passthru_dev_select(s + ata_sff_dev_select(ap, device); + } + ++static void it821x_dump_stack_once(void) ++{ ++ static int dumped = 0; ++ ++ if (!dumped) { ++ dump_stack(); ++ dumped = 1; ++ } ++} ++ + /** + * it821x_smart_qc_issue - wrap qc issue prot + * @qc: command +@@ -433,6 +443,7 @@ static unsigned int it821x_smart_qc_issu + return ata_sff_qc_issue(qc); + } + printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command); ++ it821x_dump_stack_once(); + return AC_ERR_DEV; + } + From 31ce2e5e16dd3e017592ea80a97aa840ac0a0d6d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 23 Sep 2010 08:54:13 +1000 Subject: [PATCH 068/277] nouveau: IGP and DP fixes --- drm-nouveau-acpi-edid-fix.patch | 29 ----- drm-nouveau-updates.patch | 183 ++++++++++++++++++++++++-------- kernel.spec | 8 +- 3 files changed, 143 insertions(+), 77 deletions(-) delete mode 100644 drm-nouveau-acpi-edid-fix.patch diff --git a/drm-nouveau-acpi-edid-fix.patch b/drm-nouveau-acpi-edid-fix.patch deleted file mode 100644 index 52c6662ac..000000000 --- a/drm-nouveau-acpi-edid-fix.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 3a25c2ea8bd898dff218ef8baa09ea1f05a60b48 Mon Sep 17 00:00:00 2001 -From: Ben Skeggs -Date: Fri, 10 Sep 2010 15:33:11 +1000 -Subject: [PATCH] drm/nouveau: we can't free ACPI EDID, so make a copy that we can - -The rest of the connector code assumes we can kfree() the EDID pointer. -This causes things to blow up with the ACPI EDID pointer we get -passed. - -Signed-off-by: Ben Skeggs ---- - drivers/gpu/drm/nouveau/nouveau_acpi.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c -index c17a055..1191526 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_acpi.c -+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c -@@ -292,6 +292,6 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) - if (ret < 0) - return ret; - -- nv_connector->edid = edid; -+ nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL); - return 0; - } --- -1.7.2.2 - diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 69567e7af..1939d9b9a 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,4 +1,4 @@ -From 65eb698a6879847281f18930145bb6e72ef62968 Mon Sep 17 00:00:00 2001 +From 1a79b8673c5f061a87b5fe1579e3de5a50aadea5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Jun 2010 15:32:24 +1000 Subject: [PATCH] drm-nouveau-updates @@ -959,13 +959,82 @@ occur. Signed-off-by: Ben Skeggs fix compile error due to upstream differences + +drm/nouveau: we can't free ACPI EDID, so make a copy that we can + +The rest of the connector code assumes we can kfree() the EDID pointer. +This causes things to blow up with the ACPI EDID pointer we get +passed. + +Signed-off-by: Ben Skeggs + +drm/nv50: mark PCIEGART pages non-present rather than using dummy page + +Signed-off-by: Ben Skeggs + +drm/nouveau: zero dummy page + +Signed-off-by: Ben Skeggs + +drm/nv50: fix 100c90 write on nva3 + +Signed-off-by: Ben Skeggs + +drm/nouveau: Fix build regression, undefined reference to `acpi_video_get_edid' + +Build breakage: + +drivers/built-in.o: In function `nouveau_acpi_edid': +(.text+0x13404e): undefined reference to `acpi_video_get_edid' +make: *** [.tmp_vmlinux1] Error 1 + +Introduced by: + +a6ed76d7ffc62ffa474b41d31b011b6853c5de32 is the first bad commit +commit a6ed76d7ffc62ffa474b41d31b011b6853c5de32 +Author: Ben Skeggs +Date: Mon Jul 12 15:33:07 2010 +1000 + + drm/nouveau: support fetching LVDS EDID from ACPI + + Based on a patch from Matthew Garrett. + + Signed-off-by: Ben Skeggs + Acked-by: Matthew Garrett + +It doesn't seem to revert cleanly, but the problem lies in these +two config entries: + +CONFIG_ACPI=y +CONFIG_ACPI_VIDEO=m + +Adding a select for ACPI_VIDEO appears to be the best solution, and +is comparable to what is done in DRM_I915. Builds, boots, and appears to +work correctly. + +Signed-off-by: Philip J. Turmel +Signed-off-by: Francisco Jerez + +drm/nv50: flush bar1 vm / dma object setup before poking 0x1708 + +Should fix issues noticed on NVAC (MacBook Pro / ION) since gpuobj +rework. + +Signed-off-by: Ben Skeggs + +drm/nouveau: correct INIT_DP_CONDITION subcondition 5 + +Fixes DP output on a GTX 465 board I have. + +Signed-off-by: Ben Skeggs --- drivers/gpu/drm/drm_crtc_helper.c | 22 +- drivers/gpu/drm/i2c/ch7006_drv.c | 22 +- drivers/gpu/drm/i2c/ch7006_priv.h | 2 +- + drivers/gpu/drm/nouveau/Kconfig | 1 + drivers/gpu/drm/nouveau/Makefile | 12 +- drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 +- - drivers/gpu/drm/nouveau/nouveau_bios.c | 910 ++++++-- + drivers/gpu/drm/nouveau/nouveau_bios.c | 912 ++++++-- drivers/gpu/drm/nouveau/nouveau_bios.h | 6 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 228 ++- drivers/gpu/drm/nouveau/nouveau_calc.c | 10 +- @@ -992,7 +1061,7 @@ fix compile error due to upstream differences drivers/gpu/drm/nouveau/nouveau_ramht.c | 289 +++ drivers/gpu/drm/nouveau/nouveau_ramht.h | 55 + drivers/gpu/drm/nouveau/nouveau_reg.h | 118 +- - drivers/gpu/drm/nouveau/nouveau_sgdma.c | 117 +- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 118 +- drivers/gpu/drm/nouveau/nouveau_state.c | 398 ++-- drivers/gpu/drm/nouveau/nv04_crtc.c | 11 +- drivers/gpu/drm/nouveau/nv04_dac.c | 60 +- @@ -1022,20 +1091,20 @@ fix compile error due to upstream differences drivers/gpu/drm/nouveau/nv50_dac.c | 47 +- drivers/gpu/drm/nouveau/nv50_display.c | 496 +++-- drivers/gpu/drm/nouveau/nv50_display.h | 6 +- - drivers/gpu/drm/nouveau/nv50_fb.c | 39 + + drivers/gpu/drm/nouveau/nv50_fb.c | 40 + drivers/gpu/drm/nouveau/nv50_fbcon.c | 4 +- drivers/gpu/drm/nouveau/nv50_fifo.c | 396 ++-- drivers/gpu/drm/nouveau/nv50_gpio.c | 35 + drivers/gpu/drm/nouveau/nv50_graph.c | 131 +- drivers/gpu/drm/nouveau/nv50_grctx.c | 3305 +++++++++++++++++---------- - drivers/gpu/drm/nouveau/nv50_instmem.c | 473 ++--- + drivers/gpu/drm/nouveau/nv50_instmem.c | 471 ++--- drivers/gpu/drm/nouveau/nv50_sor.c | 109 +- drivers/gpu/drm/nouveau/nvc0_fb.c | 38 + drivers/gpu/drm/nouveau/nvc0_fifo.c | 89 + drivers/gpu/drm/nouveau/nvc0_graph.c | 74 + drivers/gpu/drm/nouveau/nvc0_instmem.c | 229 ++ drivers/gpu/drm/nouveau/nvreg.h | 22 - - 75 files changed, 7469 insertions(+), 5278 deletions(-) + 76 files changed, 7472 insertions(+), 5278 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.h @@ -1172,6 +1241,18 @@ index 9487123..17667b7 100644 struct ch7006_mode *mode; struct ch7006_state state; +diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig +index 6b8967a..15ca435 100644 +--- a/drivers/gpu/drm/nouveau/Kconfig ++++ b/drivers/gpu/drm/nouveau/Kconfig +@@ -10,6 +10,7 @@ config DRM_NOUVEAU + select FB + select FRAMEBUFFER_CONSOLE if !EMBEDDED + select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT ++ select ACPI_VIDEO if ACPI + help + Choose this option for open-source nVidia support. + diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index acd31ed..d6cfbf2 100644 --- a/drivers/gpu/drm/nouveau/Makefile @@ -1204,7 +1285,7 @@ index acd31ed..d6cfbf2 100644 nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c -index d4bcca8..c17a055 100644 +index d4bcca8..1191526 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -3,6 +3,7 @@ @@ -1267,11 +1348,11 @@ index d4bcca8..c17a055 100644 + if (ret < 0) + return ret; + -+ nv_connector->edid = edid; ++ nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index e492919..8fa3396 100644 +index e492919..47bc0ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -28,6 +28,8 @@ @@ -1353,7 +1434,7 @@ index e492919..8fa3396 100644 } switch (cond) { -@@ -1218,12 +1220,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +@@ -1218,14 +1220,18 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) int ret; auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index); @@ -1372,8 +1453,11 @@ index e492919..8fa3396 100644 + return 3; + } - if (cond & 1) +- if (cond & 1) ++ if (!(cond & 1)) iexec->execute = false; + } + break; @@ -1392,7 +1398,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset, NV_ERROR(bios->dev, "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", @@ -8425,7 +8509,7 @@ index 6ca80a3..1b42541 100644 #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -index 1d6ee8b..5a66a7a 100644 +index 1d6ee8b..7f028fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) @@ -8500,7 +8584,7 @@ index 1d6ee8b..5a66a7a 100644 + nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3); + pte += 1; + } else { -+ nv_wo32(gpuobj, (pte * 4), dma_offset | 0x21); ++ nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); + nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000); + pte += 2; } @@ -8548,10 +8632,12 @@ index 1d6ee8b..5a66a7a 100644 NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, &gpuobj); if (ret) { -@@ -267,34 +243,48 @@ nouveau_sgdma_init(struct drm_device *dev) +@@ -266,35 +242,48 @@ nouveau_sgdma_init(struct drm_device *dev) + } dev_priv->gart_info.sg_dummy_page = - alloc_page(GFP_KERNEL|__GFP_DMA32); +- alloc_page(GFP_KERNEL|__GFP_DMA32); ++ alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO); + if (!dev_priv->gart_info.sg_dummy_page) { + nouveau_gpuobj_ref(NULL, &gpuobj); + return -ENOMEM; @@ -8601,9 +8687,8 @@ index 1d6ee8b..5a66a7a 100644 - nv_wo32(dev, gpuobj, (i+0)/4, - dev_priv->gart_info.sg_dummy_bus | 0x21); - nv_wo32(dev, gpuobj, (i+4)/4, 0); -+ nv_wo32(gpuobj, i + 0, -+ dev_priv->gart_info.sg_dummy_bus | 0x21); -+ nv_wo32(gpuobj, i + 4, 0); ++ nv_wo32(gpuobj, i + 0, 0x00000000); ++ nv_wo32(gpuobj, i + 4, 0x00000000); } } - dev_priv->engine.instmem.finish_access(dev); @@ -8611,7 +8696,7 @@ index 1d6ee8b..5a66a7a 100644 dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; dev_priv->gart_info.aper_base = 0; -@@ -317,7 +307,7 @@ nouveau_sgdma_takedown(struct drm_device *dev) +@@ -317,7 +306,7 @@ nouveau_sgdma_takedown(struct drm_device *dev) dev_priv->gart_info.sg_dummy_bus = 0; } @@ -8620,7 +8705,7 @@ index 1d6ee8b..5a66a7a 100644 } int -@@ -325,14 +315,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) +@@ -325,14 +314,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; @@ -13922,10 +14007,18 @@ index 581d405..c551f0b 100644 int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c -index 32611bd..594720b 100644 +index 32611bd..cd1988b 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c -@@ -36,3 +36,42 @@ void +@@ -20,6 +20,7 @@ nv50_fb_init(struct drm_device *dev) + case 0x50: + nv_wr32(dev, 0x100c90, 0x0707ff); + break; ++ case 0xa3: + case 0xa5: + case 0xa8: + nv_wr32(dev, 0x100c90, 0x0d0fff); +@@ -36,3 +37,42 @@ void nv50_fb_takedown(struct drm_device *dev) { } @@ -18629,7 +18722,7 @@ index 42a8fb2..336aab2 100644 size = (ctx->ctxvals_pos-offset)/8; } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c -index 5f21df3..457a8bc 100644 +index 5f21df3..ac3de05 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -32,41 +32,87 @@ @@ -18745,7 +18838,7 @@ index 5f21df3..457a8bc 100644 priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) -@@ -77,215 +123,113 @@ nv50_instmem_init(struct drm_device *dev) +@@ -77,215 +123,115 @@ nv50_instmem_init(struct drm_device *dev) for (i = 0x1700; i <= 0x1710; i += 4) priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); @@ -18943,12 +19036,12 @@ index 5f21df3..457a8bc 100644 return ret; } - dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj; -+ dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; - +- - for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size; - v += 4) - BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0); -- ++ dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; + - BAR0_WI32(chan->vm_pd, 0x10 + (i*8), - chan->vm_vram_pt[i]->instance | 0x61); - BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0); @@ -18982,7 +19075,14 @@ index 5f21df3..457a8bc 100644 - BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000); - BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000); - BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000); -- ++ nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); ++ nv_wo32(priv->fb_bar, 0x04, 0x40000000 + ++ pci_resource_len(dev->pdev, 1) - 1); ++ nv_wo32(priv->fb_bar, 0x08, 0x40000000); ++ nv_wo32(priv->fb_bar, 0x0c, 0x00000000); ++ nv_wo32(priv->fb_bar, 0x10, 0x00000000); ++ nv_wo32(priv->fb_bar, 0x14, 0x00000000); + - /* Poke the relevant regs, and pray it works :) */ - nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); - nv_wr32(dev, NV50_PUNK_UNK1710, 0); @@ -18992,15 +19092,8 @@ index 5f21df3..457a8bc 100644 - NV50_PUNK_BAR1_CTXDMA_VALID); - nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | - NV50_PUNK_BAR3_CTXDMA_VALID); -- -+ nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); -+ nv_wo32(priv->fb_bar, 0x04, 0x40000000 + -+ pci_resource_len(dev->pdev, 1) - 1); -+ nv_wo32(priv->fb_bar, 0x08, 0x40000000); -+ nv_wo32(priv->fb_bar, 0x0c, 0x00000000); -+ nv_wo32(priv->fb_bar, 0x10, 0x00000000); -+ nv_wo32(priv->fb_bar, 0x14, 0x00000000); -+ ++ dev_priv->engine.instmem.flush(dev); + + nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); for (i = 0; i < 8; i++) nv_wr32(dev, 0x1900 + (i*4), 0); @@ -19034,7 +19127,7 @@ index 5f21df3..457a8bc 100644 return 0; } -@@ -302,29 +246,24 @@ nv50_instmem_takedown(struct drm_device *dev) +@@ -302,29 +248,24 @@ nv50_instmem_takedown(struct drm_device *dev) if (!priv) return; @@ -19073,7 +19166,7 @@ index 5f21df3..457a8bc 100644 } dev_priv->engine.instmem.priv = NULL; -@@ -336,14 +275,14 @@ nv50_instmem_suspend(struct drm_device *dev) +@@ -336,14 +277,14 @@ nv50_instmem_suspend(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->fifos[0]; @@ -19091,7 +19184,7 @@ index 5f21df3..457a8bc 100644 ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); return 0; } -@@ -354,23 +293,25 @@ nv50_instmem_resume(struct drm_device *dev) +@@ -354,23 +295,25 @@ nv50_instmem_resume(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nouveau_channel *chan = dev_priv->fifos[0]; @@ -19125,7 +19218,7 @@ index 5f21df3..457a8bc 100644 NV50_PUNK_BAR3_CTXDMA_VALID); for (i = 0; i < 8; i++) -@@ -386,7 +327,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, +@@ -386,7 +329,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, if (gpuobj->im_backing) return -EINVAL; @@ -19134,7 +19227,7 @@ index 5f21df3..457a8bc 100644 if (*sz == 0) return -EINVAL; -@@ -404,9 +345,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, +@@ -404,9 +347,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, return ret; } @@ -19145,7 +19238,7 @@ index 5f21df3..457a8bc 100644 return 0; } -@@ -429,23 +368,23 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -429,23 +370,23 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; @@ -19174,7 +19267,7 @@ index 5f21df3..457a8bc 100644 vram |= 1; if (dev_priv->vram_sys_base) { -@@ -453,27 +392,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -453,27 +394,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) vram |= 0x30; } @@ -19209,7 +19302,7 @@ index 5f21df3..457a8bc 100644 gpuobj->im_bound = 1; return 0; -@@ -489,39 +417,44 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +@@ -489,39 +419,44 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) if (gpuobj->im_bound == 0) return -EINVAL; diff --git a/kernel.spec b/kernel.spec index 7392cb603..26873feb6 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 29 +%global baserelease 30 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -667,7 +667,6 @@ Patch1807: drm-i2c-ch7006-fix.patch Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch Patch1812: drm-nouveau-nva3-noaccel.patch -Patch1813: drm-nouveau-acpi-edid-fix.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1310,7 +1309,6 @@ ApplyPatch drm-i2c-ch7006-fix.patch ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-nouveau-nva3-noaccel.patch -ApplyPatch drm-nouveau-acpi-edid-fix.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch @@ -1985,6 +1983,10 @@ fi # and build. %changelog +* Thu Sep 23 2010 Ben Skeggs 2.6.35.5-30 +- nouveau: fix IGP chipsets (rhbz#636326), and some DP boards +- drm-nouveau-acpi-edid-fix.patch: drop, merged into updates + * Wed Sep 22 2010 Chuck Ebbert - Fix possible lockup with new scheduler idle balance code. - Dump stack on failed ATA commands in pata_it821x driver (#632753) From 6289a5fca941c77e54fe45f09a6e727496ff8d13 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 23 Sep 2010 20:39:02 -0400 Subject: [PATCH 069/277] Enable -debug flavours and switch default image to release builds - Bump NR_CPUS on i686 to 64. --- config-generic | 8 ++-- config-nodebug | 94 +++++++++++++++++++++---------------------- config-x86-generic | 2 +- config-x86_64-generic | 2 +- kernel.spec | 10 +++-- 5 files changed, 60 insertions(+), 56 deletions(-) diff --git a/config-generic b/config-generic index cf8619a71..13a9ab4bd 100644 --- a/config-generic +++ b/config-generic @@ -1423,11 +1423,11 @@ CONFIG_ATMEL=m CONFIG_B43=m CONFIG_B43_PCMCIA=y CONFIG_B43_SDIO=y -CONFIG_B43_DEBUG=y +# CONFIG_B43_DEBUG is not set CONFIG_B43_PHY_LP=y # CONFIG_B43_FORCE_PIO is not set CONFIG_B43LEGACY=m -CONFIG_B43LEGACY_DEBUG=y +# CONFIG_B43LEGACY_DEBUG is not set CONFIG_B43LEGACY_DMA=y CONFIG_B43LEGACY_PIO=y CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y @@ -3750,7 +3750,7 @@ CONFIG_IBMASR=m CONFIG_PM_DEBUG=y CONFIG_PM_TRACE=y # CONFIG_PM_VERBOSE is not set -CONFIG_PM_TEST_SUSPEND=y +# CONFIG_PM_TEST_SUSPEND is not set CONFIG_PM_RUNTIME=y ## BEGIN ISA Junk. @@ -4183,7 +4183,7 @@ CONFIG_USB_ATMEL=m # CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_FUNCTION_GRAPH_TRACER is not set -CONFIG_BOOT_TRACER=y +# CONFIG_BOOT_TRACER is not set CONFIG_EARLY_PRINTK_DBGP=y CONFIG_SECURITYFS=y diff --git a/config-nodebug b/config-nodebug index e1f14bb59..99a780cf0 100644 --- a/config-nodebug +++ b/config-nodebug @@ -2,90 +2,90 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_DEBUG=y CONFIG_SND_PCM_XRUN_DEBUG=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_PROVE_RCU=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_PROVE_RCU is not set # CONFIG_PROVE_RCU_REPEATEDLY is not set -CONFIG_DEBUG_PER_CPU_MAPS=y +# CONFIG_DEBUG_PER_CPU_MAPS is not set CONFIG_CPUMASK_OFFSTACK=y -CONFIG_CPU_NOTIFIER_ERROR_INJECT=m +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set -CONFIG_FAULT_INJECTION=y -CONFIG_FAILSLAB=y -CONFIG_FAIL_PAGE_ALLOC=y -CONFIG_FAIL_MAKE_REQUEST=y -CONFIG_FAULT_INJECTION_DEBUG_FS=y -CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y -CONFIG_FAIL_IO_TIMEOUT=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FAILSLAB is not set +# CONFIG_FAIL_PAGE_ALLOC is not set +# CONFIG_FAIL_MAKE_REQUEST is not set +# CONFIG_FAULT_INJECTION_DEBUG_FS is not set +# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set +# CONFIG_FAIL_IO_TIMEOUT is not set -CONFIG_SLUB_DEBUG_ON=y +# CONFIG_SLUB_DEBUG_ON is not set -CONFIG_LOCK_STAT=y +# CONFIG_LOCK_STAT is not set -CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_ACPI_DEBUG=y +# CONFIG_ACPI_DEBUG is not set # CONFIG_ACPI_DEBUG_FUNC_TRACE is not set -CONFIG_DEBUG_SG=y +# CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_PAGEALLOC is not set -CONFIG_DEBUG_WRITECOUNT=y -CONFIG_DEBUG_OBJECTS=y +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_OBJECTS is not set # CONFIG_DEBUG_OBJECTS_SELFTEST is not set -CONFIG_DEBUG_OBJECTS_FREE=y -CONFIG_DEBUG_OBJECTS_TIMERS=y +# CONFIG_DEBUG_OBJECTS_FREE is not set +# CONFIG_DEBUG_OBJECTS_TIMERS is not set CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 -CONFIG_X86_PTDUMP=y +# CONFIG_X86_PTDUMP is not set -CONFIG_CAN_DEBUG_DEVICES=y +# CONFIG_CAN_DEBUG_DEVICES is not set -CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_SYSCTL_SYSCALL_CHECK is not set -CONFIG_DEBUG_NOTIFIERS=y +# CONFIG_DEBUG_NOTIFIERS is not set -CONFIG_DMA_API_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set -CONFIG_MMIOTRACE=y +# CONFIG_MMIOTRACE is not set -CONFIG_DEBUG_CREDENTIALS=y +# CONFIG_DEBUG_CREDENTIALS is not set # off in both production debug and nodebug builds, # on in rawhide nodebug builds -CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -CONFIG_EXT4_DEBUG=y +# CONFIG_EXT4_DEBUG is not set -CONFIG_DEBUG_PERF_USE_VMALLOC=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set -CONFIG_JBD2_DEBUG=y +# CONFIG_JBD2_DEBUG is not set -CONFIG_DEBUG_CFQ_IOSCHED=y +# CONFIG_DEBUG_CFQ_IOSCHED is not set -CONFIG_DRBD_FAULT_INJECTION=y +# CONFIG_DRBD_FAULT_INJECTION is not set -CONFIG_ATH_DEBUG=y -CONFIG_IWLWIFI_DEVICE_TRACING=y +# CONFIG_ATH_DEBUG is not set +# CONFIG_IWLWIFI_DEVICE_TRACING is not set -CONFIG_DEBUG_OBJECTS_WORK=y -CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y +# CONFIG_DEBUG_OBJECTS_WORK is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set -CONFIG_DMADEVICES_DEBUG=y -CONFIG_DMADEVICES_VDEBUG=y +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMADEVICES_VDEBUG is not set CONFIG_PM_ADVANCED_DEBUG=y -CONFIG_CEPH_FS_PRETTYDEBUG=y -CONFIG_QUOTA_DEBUG=y +# CONFIG_CEPH_FS_PRETTYDEBUG is not set +# CONFIG_QUOTA_DEBUG is not set # CONFIG_PCI_DEFAULT_USE_CRS is not set diff --git a/config-x86-generic b/config-x86-generic index 4f2f6092f..64690645e 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -37,7 +37,7 @@ CONFIG_M686=y # CONFIG_MCYRIXIII is not set # CONFIG_MVIAC3_2 is not set CONFIG_SMP=y -CONFIG_NR_CPUS=32 +CONFIG_NR_CPUS=64 CONFIG_X86_GENERIC=y # CONFIG_X86_PPRO_FENCE is not set CONFIG_HPET=y diff --git a/config-x86_64-generic b/config-x86_64-generic index 204dfff62..5fb5f1b53 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -15,7 +15,7 @@ CONFIG_NUMA=y CONFIG_K8_NUMA=y CONFIG_X86_64_ACPI_NUMA=y # CONFIG_NUMA_EMU is not set -CONFIG_NR_CPUS=512 +CONFIG_NR_CPUS=256 CONFIG_X86_POWERNOW_K8=m CONFIG_X86_P4_CLOCKMOD=m CONFIG_IA32_EMULATION=y diff --git a/kernel.spec b/kernel.spec index 26873feb6..78e86dde4 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 30 +%global baserelease 31 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -125,7 +125,7 @@ Summary: The Linux kernel %define doc_build_fail true %endif -%define rawhide_skip_docs 1 +%define rawhide_skip_docs 0 %if 0%{?rawhide_skip_docs} %define with_doc 0 %define doc_build_fail true @@ -146,7 +146,7 @@ Summary: The Linux kernel # Set debugbuildsenabled to 1 for production (build separate debug kernels) # and 0 for rawhide (all kernels are debug kernels). # See also 'make debug' and 'make release'. -%define debugbuildsenabled 0 +%define debugbuildsenabled 1 # Want to build a vanilla kernel build without any non-upstream patches? # (well, almost none, we need nonintconfig for build purposes). Default to 0 (off). @@ -1983,6 +1983,10 @@ fi # and build. %changelog +* Thu Sep 23 2010 Kyle McMartin 2.6.35.5-31 +- Enable -debug flavours and switch default image to release builds. +- Bump NR_CPUS on i686 to 64. + * Thu Sep 23 2010 Ben Skeggs 2.6.35.5-30 - nouveau: fix IGP chipsets (rhbz#636326), and some DP boards - drm-nouveau-acpi-edid-fix.patch: drop, merged into updates From b13dd03f62d92090a1d147aa4b92087aa29f7d1a Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 23 Sep 2010 20:59:39 -0400 Subject: [PATCH 070/277] Slay another rcu_dereference_check warning pointed out by rmcgrath --- ...access-to-task-credentials-in-whatid.patch | 98 +++++++++++++++++++ kernel.spec | 6 ++ 2 files changed, 104 insertions(+) create mode 100644 fix-unprotected-access-to-task-credentials-in-whatid.patch diff --git a/fix-unprotected-access-to-task-credentials-in-whatid.patch b/fix-unprotected-access-to-task-credentials-in-whatid.patch new file mode 100644 index 000000000..2fd8b53dc --- /dev/null +++ b/fix-unprotected-access-to-task-credentials-in-whatid.patch @@ -0,0 +1,98 @@ +From 2779f26ab085071a8a55d3cf31f31a7d3c3bfcd1 Mon Sep 17 00:00:00 2001 +From: Daniel J Blueman +Date: Tue, 17 Aug 2010 23:56:55 +0100 +Subject: Fix unprotected access to task credentials in waitid() + +Using a program like the following: + + #include + #include + #include + #include + + int main() { + id_t id; + siginfo_t infop; + pid_t res; + + id = fork(); + if (id == 0) { sleep(1); exit(0); } + kill(id, SIGSTOP); + alarm(1); + waitid(P_PID, id, &infop, WCONTINUED); + return 0; + } + +to call waitid() on a stopped process results in access to the child task's +credentials without the RCU read lock being held - which may be replaced in the +meantime - eliciting the following warning: + + =================================================== + [ INFO: suspicious rcu_dereference_check() usage. ] + --------------------------------------------------- + kernel/exit.c:1460 invoked rcu_dereference_check() without protection! + + other info that might help us debug this: + + rcu_scheduler_active = 1, debug_locks = 1 + 2 locks held by waitid02/22252: + #0: (tasklist_lock){.?.?..}, at: [] do_wait+0xc5/0x310 + #1: (&(&sighand->siglock)->rlock){-.-...}, at: [] + wait_consider_task+0x19a/0xbe0 + + stack backtrace: + Pid: 22252, comm: waitid02 Not tainted 2.6.35-323cd+ #3 + Call Trace: + [] lockdep_rcu_dereference+0xa4/0xc0 + [] wait_consider_task+0xaf1/0xbe0 + [] do_wait+0xf5/0x310 + [] sys_waitid+0x86/0x1f0 + [] ? child_wait_callback+0x0/0x70 + [] system_call_fastpath+0x16/0x1b + +This is fixed by holding the RCU read lock in wait_task_continued() to ensure +that the task's current credentials aren't destroyed between us reading the +cred pointer and us reading the UID from those credentials. + +Furthermore, protect wait_task_stopped() in the same way. + +We don't need to keep holding the RCU read lock once we've read the UID from +the credentials as holding the RCU read lock doesn't stop the target task from +changing its creds under us - so the credentials may be outdated immediately +after we've read the pointer, lock or no lock. + +Signed-off-by: Daniel J Blueman +Signed-off-by: David Howells +Acked-by: Paul E. McKenney +Acked-by: Oleg Nesterov +Signed-off-by: Linus Torvalds +--- + kernel/exit.c | 5 ++--- + 1 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/exit.c b/kernel/exit.c +index ceffc67..ac90425 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -1383,8 +1383,7 @@ static int wait_task_stopped(struct wait_opts *wo, + if (!unlikely(wo->wo_flags & WNOWAIT)) + *p_code = 0; + +- /* don't need the RCU readlock here as we're holding a spinlock */ +- uid = __task_cred(p)->uid; ++ uid = task_uid(p); + unlock_sig: + spin_unlock_irq(&p->sighand->siglock); + if (!exit_code) +@@ -1457,7 +1456,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) + } + if (!unlikely(wo->wo_flags & WNOWAIT)) + p->signal->flags &= ~SIGNAL_STOP_CONTINUED; +- uid = __task_cred(p)->uid; ++ uid = task_uid(p); + spin_unlock_irq(&p->sighand->siglock); + + pid = task_pid_vnr(p); +-- +1.7.3 + diff --git a/kernel.spec b/kernel.spec index 78e86dde4..a272ee966 100644 --- a/kernel.spec +++ b/kernel.spec @@ -724,6 +724,7 @@ Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # rhbz #622149 Patch12085: fix-rcu_deref_check-warning.patch Patch12086: linux-2.6-cgroups-rcu.patch +Patch12087: fix-unprotected-access-to-task-credentials-in-whatid.patch # rhbz #513530 Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch @@ -1364,6 +1365,7 @@ ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # bz 622149 ApplyPatch fix-rcu_deref_check-warning.patch ApplyPatch linux-2.6-cgroups-rcu.patch +ApplyPatch fix-unprotected-access-to-task-credentials-in-whatid.patch # bz 513530 ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch @@ -1984,6 +1986,10 @@ fi %changelog * Thu Sep 23 2010 Kyle McMartin 2.6.35.5-31 +- Slay another rcu_dereference_check warning pointed out by + rmcgrath@. + +* Thu Sep 23 2010 Kyle McMartin - Enable -debug flavours and switch default image to release builds. - Bump NR_CPUS on i686 to 64. From 2348a607b787696385b7a5b6272d78506ba80928 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 23 Sep 2010 23:01:13 -0400 Subject: [PATCH 071/277] Serialize mandocs/htmldocs build --- kernel.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index a272ee966..6d21bc5ba 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1700,7 +1700,7 @@ BuildKernel %make_target %kernel_image smp %if %{with_doc} # Make the HTML and man pages. -make %{?_smp_mflags} htmldocs mandocs || %{doc_build_fail} +make htmldocs mandocs || %{doc_build_fail} # sometimes non-world-readable files sneak into the kernel source tree chmod -R a=rX Documentation @@ -1985,6 +1985,10 @@ fi # and build. %changelog +* Thu Sep 23 2010 Kyle McMartin 2.6.35.5-32 +- Serialize mandocs/htmldocs build, since otherwise it will constantly + fail on the koji builders. + * Thu Sep 23 2010 Kyle McMartin 2.6.35.5-31 - Slay another rcu_dereference_check warning pointed out by rmcgrath@. From c2aa9135d279ee98ac2bce4c42bbbecac2bbd881 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 23 Sep 2010 23:02:02 -0400 Subject: [PATCH 072/277] Bump baserelease --- kernel.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel.spec b/kernel.spec index 6d21bc5ba..a800f2bbd 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 31 +%global baserelease 32 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching From eda054e8bdc8ecca4db5a904a1ca84b90c290c62 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 25 Sep 2010 08:18:19 -0400 Subject: [PATCH 073/277] Linux 2.6.35.6-rc1 Comment out merged patches: aio-check-for-multiplication-overflow-in-do_io_submit.patch linux-2.6.35.4-virtio_console-fix-poll.patch fix-unprotected-access-to-task-credentials-in-whatid.patch dell-wmi-add-support-for-eject-key-studio-1555.patch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch Revert: "drm/nv50: initialize ramht_refs list for faked 0 channel" (our DRM update removes ramht_refs entirely.) --- kernel.spec | 36 ++++++++++++++++++++++---------- linux-2.6-upstream-reverts.patch | 34 +++++++++++++++++++++++++++++- sources | 1 + 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/kernel.spec b/kernel.spec index a800f2bbd..e8e6cc654 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 32 +%global baserelease 33 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -60,9 +60,9 @@ Summary: The Linux kernel %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 5 +%define stable_update 6 # Is it a -stable RC? -%define stable_rc 0 +%define stable_rc 1 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1206,7 +1206,7 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # bugfixes to drivers and filesystems # -ApplyPatch aio-check-for-multiplication-overflow-in-do_io_submit.patch +#ApplyPatch aio-check-for-multiplication-overflow-in-do_io_submit.patch # ext4 @@ -1298,7 +1298,7 @@ ApplyPatch linux-2.6-crash-driver.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch -ApplyPatch linux-2.6.35.4-virtio_console-fix-poll.patch +#ApplyPatch linux-2.6.35.4-virtio_console-fix-poll.patch #ApplyPatch drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch #ApplyPatch revert-drm-kms-toggle-poll-around-switcheroo.patch @@ -1365,10 +1365,10 @@ ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # bz 622149 ApplyPatch fix-rcu_deref_check-warning.patch ApplyPatch linux-2.6-cgroups-rcu.patch -ApplyPatch fix-unprotected-access-to-task-credentials-in-whatid.patch +#ApplyPatch fix-unprotected-access-to-task-credentials-in-whatid.patch # bz 513530 -ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch +#ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch # bz #575873 ApplyPatch flexcop-fix-xlate_proc_name-warning.patch @@ -1379,13 +1379,13 @@ ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch # CVE-2010-2954 -ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +#ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch # CVE-2010-2960 -ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch -ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +#ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +#ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch # Scheduler fixes (#635813 and #633037) -ApplyPatch sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch +#ApplyPatch sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch ApplyPatch sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch ApplyPatch sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch @@ -1985,6 +1985,20 @@ fi # and build. %changelog +* Sat Sep 25 2010 Chuck Ebbert 2.6.35.6-33.rc1 +- Linux 2.6.35.6-rc1 +- Comment out merged patches: + aio-check-for-multiplication-overflow-in-do_io_submit.patch + linux-2.6.35.4-virtio_console-fix-poll.patch + fix-unprotected-access-to-task-credentials-in-whatid.patch + dell-wmi-add-support-for-eject-key-studio-1555.patch + irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch + keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch + keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch + sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch +- Revert: "drm/nv50: initialize ramht_refs list for faked 0 channel" + (our DRM update removes ramht_refs entirely.) + * Thu Sep 23 2010 Kyle McMartin 2.6.35.5-32 - Serialize mandocs/htmldocs build, since otherwise it will constantly fail on the koji builders. diff --git a/linux-2.6-upstream-reverts.patch b/linux-2.6-upstream-reverts.patch index 607602cfc..fba7d245c 100644 --- a/linux-2.6-upstream-reverts.patch +++ b/linux-2.6-upstream-reverts.patch @@ -1 +1,33 @@ -nil +From 615661f3948a066fd22a36fe8ea0c528b75ee373 Mon Sep 17 00:00:00 2001 +From: Marcin Slusarz +Date: Sun, 22 Aug 2010 20:54:08 +0200 +Subject: drm/nv50: initialize ramht_refs list for faked 0 channel + +From: Marcin Slusarz + +commit 615661f3948a066fd22a36fe8ea0c528b75ee373 upstream. + +We need it for PFIFO_INTR_CACHE_ERROR interrupt handling, +because nouveau_fifo_swmthd looks for matching gpuobj in +ramht_refs list. +It fixes kernel panic in nouveau_gpuobj_ref_find. + +Signed-off-by: Marcin Slusarz +Signed-off-by: Ben Skeggs +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/nouveau/nv50_instmem.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/nouveau/nv50_instmem.c ++++ b/drivers/gpu/drm/nouveau/nv50_instmem.c +@@ -141,6 +141,8 @@ nv50_instmem_init(struct drm_device *dev + chan->file_priv = (struct drm_file *)-2; + dev_priv->fifos[0] = dev_priv->fifos[127] = chan; + ++ INIT_LIST_HEAD(&chan->ramht_refs); ++ + /* Channel's PRAMIN object + heap */ + ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, + NULL, &chan->ramin); diff --git a/sources b/sources index f6d872efd..9f2ca4879 100644 --- a/sources +++ b/sources @@ -1,2 +1,3 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 5bf1900e4ea72b8c65f4f7aae0a28d14 patch-2.6.35.5.bz2 +bee26a90f42ded49a026f67f83443206 patch-2.6.35.6-rc1.bz2 From b49b116bb07cc234c6da4d93d6f66b26a8eb1554 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 25 Sep 2010 08:29:41 -0400 Subject: [PATCH 074/277] Add sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch --- kernel.spec | 4 + ...cache_nice_tries-only-on-periodic-lb.patch | 93 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch diff --git a/kernel.spec b/kernel.spec index e8e6cc654..e61da1f22 100644 --- a/kernel.spec +++ b/kernel.spec @@ -749,6 +749,7 @@ Patch12575: sched-15-update-rq-clock-for-nohz-balanced-cpus.patch Patch12580: sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch Patch12585: sched-25-move-sched_avg_update-to-update_cpu_load.patch Patch12590: sched-30-sched-fix-nohz-balance-kick.patch +Patch12595: sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch Patch13600: btusb-macbookpro-6-2.patch Patch13601: btusb-macbookpro-7-1.patch @@ -1392,6 +1393,7 @@ ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch ApplyPatch sched-20-fix-rq-clock-synchronization-when-migrating-tasks.patch ApplyPatch sched-25-move-sched_avg_update-to-update_cpu_load.patch ApplyPatch sched-30-sched-fix-nohz-balance-kick.patch +ApplyPatch sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch ApplyPatch btusb-macbookpro-7-1.patch ApplyPatch btusb-macbookpro-6-2.patch @@ -1998,6 +2000,8 @@ fi sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch - Revert: "drm/nv50: initialize ramht_refs list for faked 0 channel" (our DRM update removes ramht_refs entirely.) +- Add sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch, another + fix for excessive scheduler load balancing. * Thu Sep 23 2010 Kyle McMartin 2.6.35.5-32 - Serialize mandocs/htmldocs build, since otherwise it will constantly diff --git a/sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch b/sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch new file mode 100644 index 000000000..5277dc75d --- /dev/null +++ b/sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch @@ -0,0 +1,93 @@ +From: Venkatesh Pallipadi +Date: Sat, 11 Sep 2010 01:19:17 +0000 (-0700) +Subject: sched: Increment cache_nice_tries only on periodic lb +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fmingo%2Flinux-2.6-x86.git;a=commitdiff_plain;h=58b26c4c025778c09c7a1438ff185080e11b7d0a + +sched: Increment cache_nice_tries only on periodic lb + +scheduler uses cache_nice_tries as an indicator to do cache_hot and +active load balance, when normal load balance fails. Currently, +this value is changed on any failed load balance attempt. That ends +up being not so nice to workloads that enter/exit idle often, as +they do more frequent new_idle balance and that pretty soon results +in cache hot tasks being pulled in. + +Making the cache_nice_tries ignore failed new_idle balance seems to +make better sense. With that only the failed load balance in +periodic load balance gets accounted and the rate of accumulation +of cache_nice_tries will not depend on idle entry/exit (short +running sleep-wakeup kind of tasks). This reduces movement of +cache_hot tasks. + +schedstat diff (after-before) excerpt from a workload that has +frequent and short wakeup-idle pattern (:2 in cpu col below refers +to NEWIDLE idx) This snapshot was across ~400 seconds. + +Without this change: +domainstats: domain0 + cpu cnt bln fld imb gain hgain nobusyq nobusyg + 0:2 306487 219575 73167 110069413 44583 19070 1172 218403 + 1:2 292139 194853 81421 120893383 50745 21902 1259 193594 + 2:2 283166 174607 91359 129699642 54931 23688 1287 173320 + 3:2 273998 161788 93991 132757146 57122 24351 1366 160422 + 4:2 289851 215692 62190 83398383 36377 13680 851 214841 + 5:2 316312 222146 77605 117582154 49948 20281 988 221158 + 6:2 297172 195596 83623 122133390 52801 21301 929 194667 + 7:2 283391 178078 86378 126622761 55122 22239 928 177150 + 8:2 297655 210359 72995 110246694 45798 19777 1125 209234 + 9:2 297357 202011 79363 119753474 50953 22088 1089 200922 +10:2 278797 178703 83180 122514385 52969 22726 1128 177575 +11:2 272661 167669 86978 127342327 55857 24342 1195 166474 +12:2 293039 204031 73211 110282059 47285 19651 948 203083 +13:2 289502 196762 76803 114712942 49339 20547 1016 195746 +14:2 264446 169609 78292 115715605 50459 21017 982 168627 +15:2 260968 163660 80142 116811793 51483 21281 1064 162596 + +With this change: +domainstats: domain0 + cpu cnt bln fld imb gain hgain nobusyq nobusyg + 0:2 272347 187380 77455 105420270 24975 1 953 186427 + 1:2 267276 172360 86234 116242264 28087 6 1028 171332 + 2:2 259769 156777 93281 123243134 30555 1 1043 155734 + 3:2 250870 143129 97627 127370868 32026 6 1188 141941 + 4:2 248422 177116 64096 78261112 22202 2 757 176359 + 5:2 275595 180683 84950 116075022 29400 6 778 179905 + 6:2 262418 162609 88944 119256898 31056 4 817 161792 + 7:2 252204 147946 92646 122388300 32879 4 824 147122 + 8:2 262335 172239 81631 110477214 26599 4 864 171375 + 9:2 261563 164775 88016 117203621 28331 3 849 163926 +10:2 243389 140949 93379 121353071 29585 2 909 140040 +11:2 242795 134651 98310 124768957 30895 2 1016 133635 +12:2 255234 166622 79843 104696912 26483 4 746 165876 +13:2 244944 151595 83855 109808099 27787 3 801 150794 +14:2 241301 140982 89935 116954383 30403 6 845 140137 +15:2 232271 128564 92821 119185207 31207 4 1416 127148 + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Peter Zijlstra +LKML-Reference: <1284167957-3675-1-git-send-email-venki@google.com> +Signed-off-by: Ingo Molnar +--- + +[ 2.6.35.x backport ] + +diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c +index a171138..aa16cf1 100644 +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -3031,7 +3031,14 @@ redo: + + if (!ld_moved) { + schedstat_inc(sd, lb_failed[idle]); +- sd->nr_balance_failed++; ++ /* ++ * Increment the failure counter only on periodic balance. ++ * We do not want newidle balance, which can be very ++ * frequent, pollute the failure counter causing ++ * excessive cache_hot migrations and active balances. ++ */ ++ if (idle != CPU_NEWLY_IDLE) ++ sd->nr_balance_failed++; + + if (need_active_balance(sd, sd_idle, idle)) { + raw_spin_lock_irqsave(&busiest->lock, flags); From b999dfdb6a810a1c4fec9e9772f646c214f81938 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Sat, 25 Sep 2010 08:38:14 -0400 Subject: [PATCH 075/277] Add xen-fix-typo-in-xen-irq-fix.patch, fixes typo in 2.6.35.5 patch. --- kernel.spec | 5 +++++ xen-fix-typo-in-xen-irq-fix.patch | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 xen-fix-typo-in-xen-irq-fix.patch diff --git a/kernel.spec b/kernel.spec index e61da1f22..9f2df691c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -755,6 +755,7 @@ Patch13600: btusb-macbookpro-6-2.patch Patch13601: btusb-macbookpro-7-1.patch Patch13610: libata-it821x-dump-stack-on-cache-flush.patch +Patch13620: xen-fix-typo-in-xen-irq-fix.patch %endif @@ -1401,6 +1402,9 @@ ApplyPatch btusb-macbookpro-6-2.patch # temporary patch, dump stack on failed it821x commands ApplyPatch libata-it821x-dump-stack-on-cache-flush.patch +# temporary fix for typo in Xen -stable patch +ApplyPatch xen-fix-typo-in-xen-irq-fix.patch + # END OF PATCH APPLICATIONS %endif @@ -2002,6 +2006,7 @@ fi (our DRM update removes ramht_refs entirely.) - Add sched-35-increment-cache_nice_tries-only-on-periodic-lb.patch, another fix for excessive scheduler load balancing. +- Add xen-fix-typo-in-xen-irq-fix.patch, fixes typo in 2.6.35.5 patch. * Thu Sep 23 2010 Kyle McMartin 2.6.35.5-32 - Serialize mandocs/htmldocs build, since otherwise it will constantly diff --git a/xen-fix-typo-in-xen-irq-fix.patch b/xen-fix-typo-in-xen-irq-fix.patch new file mode 100644 index 000000000..3a9fb62b7 --- /dev/null +++ b/xen-fix-typo-in-xen-irq-fix.patch @@ -0,0 +1,13 @@ +Fix typo in Xen patch from 2.6.35.5 + +--- linux-2.6.35.noarch.orig/drivers/xen/events.c ++++ linux-2.6.35.noarch/drivers/xen/events.c +@@ -935,7 +935,7 @@ static struct irq_chip xen_dynamic_chip + .retrigger = retrigger_dynirq, + }; + +-static struct irq_chip en_percpu_chip __read_mostly = { ++static struct irq_chip xen_percpu_chip __read_mostly = { + .name = "xen-percpu", + + .disable = disable_dynirq, From 05f615c82e8f2cd784196df9ad0fb9fe78209b25 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 26 Sep 2010 22:43:03 -0400 Subject: [PATCH 076/277] Linux 2.6.35.6 --- .gitignore | 1 + kernel.spec | 10 ++++++++-- sources | 3 +-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c2fd41347..473566eec 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ patch-*.bz2 clog *.rpm kernel-2.6.*/ +/patch-2.6.35.6.bz2 diff --git a/kernel.spec b/kernel.spec index 9f2df691c..9a8448a87 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 33 +%global baserelease 34 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -62,7 +62,7 @@ Summary: The Linux kernel # Do we have a -stable update to apply? %define stable_update 6 # Is it a -stable RC? -%define stable_rc 1 +%define stable_rc 0 # Set rpm version accordingly %if 0%{?stable_update} %define stablerev .%{stable_update} @@ -1991,6 +1991,12 @@ fi # and build. %changelog +* Mon Sep 27 2010 Kyle McMartin 2.6.35.6-34 +- Linux 2.6.35.6 +- bdi-fix-warnings-in-__mark_inode_dirty-for-dev-zero-and-friends.patch was + dropped, should fix the inode_to_bdi WARN_ON triggering for a bunch of + people. + * Sat Sep 25 2010 Chuck Ebbert 2.6.35.6-33.rc1 - Linux 2.6.35.6-rc1 - Comment out merged patches: diff --git a/sources b/sources index 9f2ca4879..53ae0ac44 100644 --- a/sources +++ b/sources @@ -1,3 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -5bf1900e4ea72b8c65f4f7aae0a28d14 patch-2.6.35.5.bz2 -bee26a90f42ded49a026f67f83443206 patch-2.6.35.6-rc1.bz2 +0dbd6ebf242a1428d4161bc32b1306fa patch-2.6.35.6.bz2 From 4141bfc9b104d8505967967f6e212c040af66371 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Mon, 27 Sep 2010 13:44:47 -0400 Subject: [PATCH 077/277] clean up patches merged in -stable --- .gitignore | 1 - ...tiplication-overflow-in-do_io_submit.patch | 47 --------- ...dd-support-for-eject-key-studio-1555.patch | 29 ------ ...access-to-task-credentials-in-whatid.patch | 98 ------------------- ...up-self-ias_obj-on-irda_bind-failure.patch | 35 ------- kernel.spec | 28 ------ ...ent-if-parent-has-no-session-keyring.patch | 50 ---------- ...-warning-in-keyctl_session_to_parent.patch | 64 ------------ linux-2.6.35.4-virtio_console-fix-poll.patch | 29 ------ ...y-accounted-as-system-time-on-32-bit.patch | 55 ----------- 10 files changed, 436 deletions(-) delete mode 100644 aio-check-for-multiplication-overflow-in-do_io_submit.patch delete mode 100644 dell-wmi-add-support-for-eject-key-studio-1555.patch delete mode 100644 fix-unprotected-access-to-task-credentials-in-whatid.patch delete mode 100644 irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch delete mode 100644 keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch delete mode 100644 keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch delete mode 100644 linux-2.6.35.4-virtio_console-fix-poll.patch delete mode 100644 sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch diff --git a/.gitignore b/.gitignore index 473566eec..c2fd41347 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ patch-*.bz2 clog *.rpm kernel-2.6.*/ -/patch-2.6.35.6.bz2 diff --git a/aio-check-for-multiplication-overflow-in-do_io_submit.patch b/aio-check-for-multiplication-overflow-in-do_io_submit.patch deleted file mode 100644 index 36b949c27..000000000 --- a/aio-check-for-multiplication-overflow-in-do_io_submit.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 75e1c70fc31490ef8a373ea2a4bea2524099b478 Mon Sep 17 00:00:00 2001 -From: Jeff Moyer -Date: Fri, 10 Sep 2010 14:16:00 -0700 -Subject: [PATCH] aio: check for multiplication overflow in do_io_submit -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Tavis Ormandy pointed out that do_io_submit does not do proper bounds -checking on the passed-in iocb array: - -       if (unlikely(nr < 0)) -               return -EINVAL; - -       if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(iocbpp))))) -               return -EFAULT;                      ^^^^^^^^^^^^^^^^^^ - -The attached patch checks for overflow, and if it is detected, the -number of iocbs submitted is scaled down to a number that will fit in -the long.  This is an ok thing to do, as sys_io_submit is documented as -returning the number of iocbs submitted, so callers should handle a -return value of less than the 'nr' argument passed in. - -Reported-by: Tavis Ormandy -Signed-off-by: Jeff Moyer -Signed-off-by: Linus Torvalds ---- - fs/aio.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/fs/aio.c b/fs/aio.c -index 3006b5b..1320b2a 100644 ---- a/fs/aio.c -+++ b/fs/aio.c -@@ -1659,6 +1659,9 @@ long do_io_submit(aio_context_t ctx_id, long nr, - if (unlikely(nr < 0)) - return -EINVAL; - -+ if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) -+ nr = LONG_MAX/sizeof(*iocbpp); -+ - if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) - return -EFAULT; - --- -1.7.2.3 - diff --git a/dell-wmi-add-support-for-eject-key-studio-1555.patch b/dell-wmi-add-support-for-eject-key-studio-1555.patch deleted file mode 100644 index f806196b1..000000000 --- a/dell-wmi-add-support-for-eject-key-studio-1555.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Islam Amer -Date: Thu, 24 Jun 2010 17:39:47 +0000 (-0400) -Subject: dell-wmi: Add support for eject key on Dell Studio 1555 -X-Git-Tag: v2.6.36-rc1~579^2~64 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d5164dbf1f651d1e955b158fb70a9c844cc91cd1 - -dell-wmi: Add support for eject key on Dell Studio 1555 - -Fixes pressing the eject key on Dell Studio 1555 does not work and produces -message : - -dell-wmi: Unknown key 0 pressed - -Signed-off-by: Islam Amer ---- - -diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c -index 66f53c3..12a8e6f 100644 ---- a/drivers/platform/x86/dell-wmi.c -+++ b/drivers/platform/x86/dell-wmi.c -@@ -221,7 +221,7 @@ static void dell_wmi_notify(u32 value, void *context) - return; - } - -- if (dell_new_hk_type) -+ if (dell_new_hk_type || buffer_entry[1] == 0x0) - reported_key = (int)buffer_entry[2]; - else - reported_key = (int)buffer_entry[1] & 0xffff; diff --git a/fix-unprotected-access-to-task-credentials-in-whatid.patch b/fix-unprotected-access-to-task-credentials-in-whatid.patch deleted file mode 100644 index 2fd8b53dc..000000000 --- a/fix-unprotected-access-to-task-credentials-in-whatid.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 2779f26ab085071a8a55d3cf31f31a7d3c3bfcd1 Mon Sep 17 00:00:00 2001 -From: Daniel J Blueman -Date: Tue, 17 Aug 2010 23:56:55 +0100 -Subject: Fix unprotected access to task credentials in waitid() - -Using a program like the following: - - #include - #include - #include - #include - - int main() { - id_t id; - siginfo_t infop; - pid_t res; - - id = fork(); - if (id == 0) { sleep(1); exit(0); } - kill(id, SIGSTOP); - alarm(1); - waitid(P_PID, id, &infop, WCONTINUED); - return 0; - } - -to call waitid() on a stopped process results in access to the child task's -credentials without the RCU read lock being held - which may be replaced in the -meantime - eliciting the following warning: - - =================================================== - [ INFO: suspicious rcu_dereference_check() usage. ] - --------------------------------------------------- - kernel/exit.c:1460 invoked rcu_dereference_check() without protection! - - other info that might help us debug this: - - rcu_scheduler_active = 1, debug_locks = 1 - 2 locks held by waitid02/22252: - #0: (tasklist_lock){.?.?..}, at: [] do_wait+0xc5/0x310 - #1: (&(&sighand->siglock)->rlock){-.-...}, at: [] - wait_consider_task+0x19a/0xbe0 - - stack backtrace: - Pid: 22252, comm: waitid02 Not tainted 2.6.35-323cd+ #3 - Call Trace: - [] lockdep_rcu_dereference+0xa4/0xc0 - [] wait_consider_task+0xaf1/0xbe0 - [] do_wait+0xf5/0x310 - [] sys_waitid+0x86/0x1f0 - [] ? child_wait_callback+0x0/0x70 - [] system_call_fastpath+0x16/0x1b - -This is fixed by holding the RCU read lock in wait_task_continued() to ensure -that the task's current credentials aren't destroyed between us reading the -cred pointer and us reading the UID from those credentials. - -Furthermore, protect wait_task_stopped() in the same way. - -We don't need to keep holding the RCU read lock once we've read the UID from -the credentials as holding the RCU read lock doesn't stop the target task from -changing its creds under us - so the credentials may be outdated immediately -after we've read the pointer, lock or no lock. - -Signed-off-by: Daniel J Blueman -Signed-off-by: David Howells -Acked-by: Paul E. McKenney -Acked-by: Oleg Nesterov -Signed-off-by: Linus Torvalds ---- - kernel/exit.c | 5 ++--- - 1 files changed, 2 insertions(+), 3 deletions(-) - -diff --git a/kernel/exit.c b/kernel/exit.c -index ceffc67..ac90425 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -1383,8 +1383,7 @@ static int wait_task_stopped(struct wait_opts *wo, - if (!unlikely(wo->wo_flags & WNOWAIT)) - *p_code = 0; - -- /* don't need the RCU readlock here as we're holding a spinlock */ -- uid = __task_cred(p)->uid; -+ uid = task_uid(p); - unlock_sig: - spin_unlock_irq(&p->sighand->siglock); - if (!exit_code) -@@ -1457,7 +1456,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) - } - if (!unlikely(wo->wo_flags & WNOWAIT)) - p->signal->flags &= ~SIGNAL_STOP_CONTINUED; -- uid = __task_cred(p)->uid; -+ uid = task_uid(p); - spin_unlock_irq(&p->sighand->siglock); - - pid = task_pid_vnr(p); --- -1.7.3 - diff --git a/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch b/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch deleted file mode 100644 index 7afc4df7a..000000000 --- a/irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: David S. Miller -Date: Tue, 31 Aug 2010 01:35:24 +0000 (-0700) -Subject: irda: Correctly clean up self->ias_obj on irda_bind() failure. -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=628e300cccaa628d8fb92aa28cb7530a3d5f2257 - -irda: Correctly clean up self->ias_obj on irda_bind() failure. - -If irda_open_tsap() fails, the irda_bind() code tries to destroy -the ->ias_obj object by hand, but does so wrongly. - -In particular, it fails to a) release the hashbin attached to the -object and b) reset the self->ias_obj pointer to NULL. - -Fix both problems by using irias_delete_object() and explicitly -setting self->ias_obj to NULL, just as irda_release() does. - -Reported-by: Tavis Ormandy -Signed-off-by: David S. Miller ---- - -diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c -index 79986a6..fd55b51 100644 ---- a/net/irda/af_irda.c -+++ b/net/irda/af_irda.c -@@ -824,8 +824,8 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) - - err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); - if (err < 0) { -- kfree(self->ias_obj->name); -- kfree(self->ias_obj); -+ irias_delete_object(self->ias_obj); -+ self->ias_obj = NULL; - goto out; - } - diff --git a/kernel.spec b/kernel.spec index 9a8448a87..baa20c759 100644 --- a/kernel.spec +++ b/kernel.spec @@ -611,8 +611,6 @@ Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch Patch160: linux-2.6-32bit-mmap-exec-randomization.patch Patch161: linux-2.6-i386-nx-emulation.patch -Patch180: aio-check-for-multiplication-overflow-in-do_io_submit.patch - Patch200: linux-2.6-debug-sizeof-structs.patch Patch201: linux-2.6-debug-nmi-timeout.patch Patch202: linux-2.6-debug-taint-vm.patch @@ -654,7 +652,6 @@ Patch800: linux-2.6-crash-driver.patch # virt + ksm patches Patch1555: fix_xen_guest_on_old_EC2.patch -Patch1556: linux-2.6.35.4-virtio_console-fix-poll.patch # DRM Patch1801: drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch @@ -724,10 +721,6 @@ Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # rhbz #622149 Patch12085: fix-rcu_deref_check-warning.patch Patch12086: linux-2.6-cgroups-rcu.patch -Patch12087: fix-unprotected-access-to-task-credentials-in-whatid.patch - -# rhbz #513530 -Patch12090: dell-wmi-add-support-for-eject-key-studio-1555.patch Patch12517: flexcop-fix-xlate_proc_name-warning.patch @@ -736,13 +729,6 @@ Patch12520: execve-improve-interactivity-with-large-arguments.patch Patch12521: execve-make-responsive-to-sigkill-with-large-arguments.patch Patch12522: setup_arg_pages-diagnose-excessive-argument-size.patch -# CVE-2010-2954 -Patch12540: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch -# CVE-2010-2960 -Patch12550: keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch -Patch12551: keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch - -Patch12560: sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch Patch12565: sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch Patch12570: sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch Patch12575: sched-15-update-rq-clock-for-nohz-balanced-cpus.patch @@ -1208,8 +1194,6 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # bugfixes to drivers and filesystems # -#ApplyPatch aio-check-for-multiplication-overflow-in-do_io_submit.patch - # ext4 # xfs @@ -1300,7 +1284,6 @@ ApplyPatch linux-2.6-crash-driver.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch -#ApplyPatch linux-2.6.35.4-virtio_console-fix-poll.patch #ApplyPatch drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch #ApplyPatch revert-drm-kms-toggle-poll-around-switcheroo.patch @@ -1367,10 +1350,6 @@ ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch # bz 622149 ApplyPatch fix-rcu_deref_check-warning.patch ApplyPatch linux-2.6-cgroups-rcu.patch -#ApplyPatch fix-unprotected-access-to-task-credentials-in-whatid.patch - -# bz 513530 -#ApplyPatch dell-wmi-add-support-for-eject-key-studio-1555.patch # bz #575873 ApplyPatch flexcop-fix-xlate_proc_name-warning.patch @@ -1380,14 +1359,7 @@ ApplyPatch execve-improve-interactivity-with-large-arguments.patch ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch -# CVE-2010-2954 -#ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch -# CVE-2010-2960 -#ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch -#ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch - # Scheduler fixes (#635813 and #633037) -#ApplyPatch sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch ApplyPatch sched-05-avoid-side-effect-of-tickless-idle-on-update_cpu_load.patch ApplyPatch sched-10-change-nohz-idle-load-balancing-logic-to-push-model.patch ApplyPatch sched-15-update-rq-clock-for-nohz-balanced-cpus.patch diff --git a/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch b/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch deleted file mode 100644 index c9208674a..000000000 --- a/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +++ /dev/null @@ -1,50 +0,0 @@ -From: David Howells -Date: Fri, 10 Sep 2010 08:59:51 +0000 (+0100) -Subject: KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3d96406c7da1ed5811ea52a3b0905f4f0e295376 - -KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring - -Fix a bug in keyctl_session_to_parent() whereby it tries to check the ownership -of the parent process's session keyring whether or not the parent has a session -keyring [CVE-2010-2960]. - -This results in the following oops: - - BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 - IP: [] keyctl_session_to_parent+0x251/0x443 - ... - Call Trace: - [] ? keyctl_session_to_parent+0x67/0x443 - [] ? __do_fault+0x24b/0x3d0 - [] sys_keyctl+0xb4/0xb8 - [] system_call_fastpath+0x16/0x1b - -if the parent process has no session keyring. - -If the system is using pam_keyinit then it mostly protected against this as all -processes derived from a login will have inherited the session keyring created -by pam_keyinit during the log in procedure. - -To test this, pam_keyinit calls need to be commented out in /etc/pam.d/. - -Reported-by: Tavis Ormandy -Signed-off-by: David Howells -Acked-by: Tavis Ormandy -Signed-off-by: Linus Torvalds ---- - -diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c -index 3868c67..60924f6 100644 ---- a/security/keys/keyctl.c -+++ b/security/keys/keyctl.c -@@ -1305,7 +1305,8 @@ long keyctl_session_to_parent(void) - goto not_permitted; - - /* the keyrings must have the same UID */ -- if (pcred->tgcred->session_keyring->uid != mycred->euid || -+ if ((pcred->tgcred->session_keyring && -+ pcred->tgcred->session_keyring->uid != mycred->euid) || - mycred->tgcred->session_keyring->uid != mycred->euid) - goto not_permitted; - diff --git a/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch b/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch deleted file mode 100644 index 5318f7e2f..000000000 --- a/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: David Howells -Date: Fri, 10 Sep 2010 08:59:46 +0000 (+0100) -Subject: KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9d1ac65a9698513d00e5608d93fca0c53f536c14 - -KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() - -There's an protected access to the parent process's credentials in the middle -of keyctl_session_to_parent(). This results in the following RCU warning: - - =================================================== - [ INFO: suspicious rcu_dereference_check() usage. ] - --------------------------------------------------- - security/keys/keyctl.c:1291 invoked rcu_dereference_check() without protection! - - other info that might help us debug this: - - rcu_scheduler_active = 1, debug_locks = 0 - 1 lock held by keyctl-session-/2137: - #0: (tasklist_lock){.+.+..}, at: [] keyctl_session_to_parent+0x60/0x236 - - stack backtrace: - Pid: 2137, comm: keyctl-session- Not tainted 2.6.36-rc2-cachefs+ #1 - Call Trace: - [] lockdep_rcu_dereference+0xaa/0xb3 - [] keyctl_session_to_parent+0xed/0x236 - [] sys_keyctl+0xb4/0xb6 - [] system_call_fastpath+0x16/0x1b - -The code should take the RCU read lock to make sure the parents credentials -don't go away, even though it's holding a spinlock and has IRQ disabled. - -Signed-off-by: David Howells -Signed-off-by: Linus Torvalds ---- - -diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c -index b2b0998..3868c67 100644 ---- a/security/keys/keyctl.c -+++ b/security/keys/keyctl.c -@@ -1272,6 +1272,7 @@ long keyctl_session_to_parent(void) - keyring_r = NULL; - - me = current; -+ rcu_read_lock(); - write_lock_irq(&tasklist_lock); - - parent = me->real_parent; -@@ -1319,6 +1320,7 @@ long keyctl_session_to_parent(void) - set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); - - write_unlock_irq(&tasklist_lock); -+ rcu_read_unlock(); - if (oldcred) - put_cred(oldcred); - return 0; -@@ -1327,6 +1329,7 @@ already_same: - ret = 0; - not_permitted: - write_unlock_irq(&tasklist_lock); -+ rcu_read_unlock(); - put_cred(cred); - return ret; - diff --git a/linux-2.6.35.4-virtio_console-fix-poll.patch b/linux-2.6.35.4-virtio_console-fix-poll.patch deleted file mode 100644 index b87bdf077..000000000 --- a/linux-2.6.35.4-virtio_console-fix-poll.patch +++ /dev/null @@ -1,29 +0,0 @@ -Subject: virtio_console: Fix poll blocking even though there is data to read -From: Hans de Goede - -I found this while working on a Linux agent for spice, the symptom I was -seeing was select blocking on the spice vdagent virtio serial port even -though there were messages queued up there. - -virtio_console's port_fops_poll checks port->inbuf != NULL to determine if -read won't block. However if an application reads enough bytes from inbuf -through port_fops_read, to empty the current port->inbuf, port->inbuf -will be NULL even though there may be buffers left in the virtqueue. - -This causes poll() to block even though there is data to be read, this patch -fixes this by using the alredy defined will_read_block utility function -instead of the port->inbuf != NULL check. - -Signed-off-By: Hans de Goede -diff -up linux-2.6.35.x86_64/drivers/char/virtio_console.c~ linux-2.6.35.x86_64/drivers/char/virtio_console.c ---- linux-2.6.35.x86_64/drivers/char/virtio_console.c~ 2010-08-02 00:11:14.000000000 +0200 -+++ linux-2.6.35.x86_64/drivers/char/virtio_console.c 2010-09-15 13:39:29.043505000 +0200 -@@ -642,7 +642,7 @@ static unsigned int port_fops_poll(struc - poll_wait(filp, &port->waitqueue, wait); - - ret = 0; -- if (port->inbuf) -+ if (!will_read_block(port)) - ret |= POLLIN | POLLRDNORM; - if (!will_write_block(port)) - ret |= POLLOUT; diff --git a/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch b/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch deleted file mode 100644 index 7c1512201..000000000 --- a/sched-00-fix-user-time-incorrectly-accounted-as-system-time-on-32-bit.patch +++ /dev/null @@ -1,55 +0,0 @@ -From: Stanislaw Gruszka -Date: Tue, 14 Sep 2010 14:35:14 +0000 (+0200) -Subject: sched: Fix user time incorrectly accounted as system time on 32-bit -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fx86%2Flinux-2.6-tip.git;a=commitdiff_plain;h=e75e863dd5c7d96b91ebbd241da5328fc38a78cc - -sched: Fix user time incorrectly accounted as system time on 32-bit - -We have 32-bit variable overflow possibility when multiply in -task_times() and thread_group_times() functions. When the -overflow happens then the scaled utime value becomes erroneously -small and the scaled stime becomes i erroneously big. - -Reported here: - - https://bugzilla.redhat.com/show_bug.cgi?id=633037 - https://bugzilla.kernel.org/show_bug.cgi?id=16559 - -Reported-by: Michael Chapman -Reported-by: Ciriaco Garcia de Celis -Signed-off-by: Stanislaw Gruszka -Signed-off-by: Peter Zijlstra -Cc: Hidetoshi Seto -Cc: # 2.6.32.19+ (partially) and 2.6.33+ -LKML-Reference: <20100914143513.GB8415@redhat.com> -Signed-off-by: Ingo Molnar ---- - -diff --git a/kernel/sched.c b/kernel/sched.c -index ed09d4f..dc85ceb 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -3513,9 +3513,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) - rtime = nsecs_to_cputime(p->se.sum_exec_runtime); - - if (total) { -- u64 temp; -+ u64 temp = rtime; - -- temp = (u64)(rtime * utime); -+ temp *= utime; - do_div(temp, total); - utime = (cputime_t)temp; - } else -@@ -3546,9 +3546,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) - rtime = nsecs_to_cputime(cputime.sum_exec_runtime); - - if (total) { -- u64 temp; -+ u64 temp = rtime; - -- temp = (u64)(rtime * cputime.utime); -+ temp *= cputime.utime; - do_div(temp, total); - utime = (cputime_t)temp; - } else From 04093b926b0dcaac32867ef8dd6cb80ece42b49c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 29 Sep 2010 12:34:17 -0400 Subject: [PATCH 078/277] Enable IB700 watchdog (used by qemu/kvm). (#637152) --- config-generic | 2 +- kernel.spec | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config-generic b/config-generic index 13a9ab4bd..c89f6a388 100644 --- a/config-generic +++ b/config-generic @@ -2193,7 +2193,7 @@ CONFIG_WDTPCI=m # CONFIG_ACQUIRE_WDT is not set # CONFIG_ADVANTECH_WDT is not set # CONFIG_EUROTECH_WDT is not set -# CONFIG_IB700_WDT is not set +CONFIG_IB700_WDT=m # CONFIG_MIXCOMWD is not set # CONFIG_SCx200_WDT is not set # CONFIG_60XX_WDT is not set diff --git a/kernel.spec b/kernel.spec index baa20c759..72e74a289 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1963,6 +1963,9 @@ fi # and build. %changelog +* Wed Sep 29 2010 Dave Jones +- Enable IB700 watchdog (used by qemu/kvm). (#637152) + * Mon Sep 27 2010 Kyle McMartin 2.6.35.6-34 - Linux 2.6.35.6 - bdi-fix-warnings-in-__mark_inode_dirty-for-dev-zero-and-friends.patch was From bbaea70ee5fb1a94c4025fb5b3b62874eb6a95f6 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 29 Sep 2010 17:58:18 -0400 Subject: [PATCH 079/277] Add back an old hack to make an SDV e1000e variant work. --- kernel.spec | 8 ++++++++ linux-2.6-e1000-ich9-montevina.patch | 30 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 linux-2.6-e1000-ich9-montevina.patch diff --git a/kernel.spec b/kernel.spec index 72e74a289..887c1288a 100644 --- a/kernel.spec +++ b/kernel.spec @@ -646,6 +646,8 @@ Patch580: linux-2.6-sparc-selinux-mprotect-checks.patch Patch610: hda_intel-prealloc-4mb-dmabuffer.patch +Patch700: linux-2.6-e1000-ich9-montevina.patch + Patch800: linux-2.6-crash-driver.patch # crypto/ @@ -1280,6 +1282,9 @@ ApplyPatch create-sys-fs-cgroup-to-mount-cgroupfs-on.patch # /dev/crash driver. ApplyPatch linux-2.6-crash-driver.patch +# Hack e1000e to work on Montevina SDV +ApplyPatch linux-2.6-e1000-ich9-montevina.patch + # crypto/ # Assorted Virt Fixes @@ -1963,6 +1968,9 @@ fi # and build. %changelog +* Wed Sep 29 2010 Dave Jones +- Add back an old hack to make an SDV e1000e variant work. + * Wed Sep 29 2010 Dave Jones - Enable IB700 watchdog (used by qemu/kvm). (#637152) diff --git a/linux-2.6-e1000-ich9-montevina.patch b/linux-2.6-e1000-ich9-montevina.patch new file mode 100644 index 000000000..888d0a766 --- /dev/null +++ b/linux-2.6-e1000-ich9-montevina.patch @@ -0,0 +1,30 @@ +This only showed up in one SDV (Montevina). +The PCIE slots don't seem to like network cards, so this is the only hope +to get networking working. It's never going upstream, but it's low impact +enough to carry just to keep those SDVs working. + +--- linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c~ 2010-09-29 17:53:13.000000000 -0400 ++++ linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c 2010-09-29 17:54:00.000000000 -0400 +@@ -424,6 +424,12 @@ static s32 e1000_init_phy_params_ich8lan + + /* Verify phy id */ + switch (phy->id) { ++ case 0: ++ if (hw->adapter->pdev->device == 0x10be) ++ hw_dbg(hw, "got 0 phy id, trying anyway"); ++ /* Fall through to IGP03E1000 case below */ ++ else ++ return -E1000_ERR_PHY; + case IGP03E1000_E_PHY_ID: + phy->type = e1000_phy_igp_3; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; +--- linux-2.6.35.noarch/drivers/net/e1000e/netdev.c~ 2010-09-29 17:54:07.000000000 -0400 ++++ linux-2.6.35.noarch/drivers/net/e1000e/netdev.c 2010-09-29 17:54:29.000000000 -0400 +@@ -5994,6 +5994,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, 0x10be), board_ich9lan }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, From fbce23b0ff1ab57d5cf278c3025111b224e38103 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 29 Sep 2010 18:11:07 -0400 Subject: [PATCH 080/277] bump for build --- kernel.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel.spec b/kernel.spec index 887c1288a..d68ba8df5 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 34 +%global baserelease 35 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -1968,7 +1968,7 @@ fi # and build. %changelog -* Wed Sep 29 2010 Dave Jones +* Wed Sep 29 2010 Dave Jones 2.6.35.6-35 - Add back an old hack to make an SDV e1000e variant work. * Wed Sep 29 2010 Dave Jones From 8f3d6a8c3f4218ebac86a0d542e3d2ca70da456b Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 29 Sep 2010 18:31:36 -0400 Subject: [PATCH 081/277] build fix --- linux-2.6-e1000-ich9-montevina.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-e1000-ich9-montevina.patch b/linux-2.6-e1000-ich9-montevina.patch index 888d0a766..8f494c0ff 100644 --- a/linux-2.6-e1000-ich9-montevina.patch +++ b/linux-2.6-e1000-ich9-montevina.patch @@ -11,7 +11,7 @@ enough to carry just to keep those SDVs working. switch (phy->id) { + case 0: + if (hw->adapter->pdev->device == 0x10be) -+ hw_dbg(hw, "got 0 phy id, trying anyway"); ++ e_dbg(hw, "got 0 phy id, trying anyway"); + /* Fall through to IGP03E1000 case below */ + else + return -E1000_ERR_PHY; From 452369b9369943ba92237487bfe7af762fffb5c5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 29 Sep 2010 18:50:05 -0400 Subject: [PATCH 082/277] build fix, again. I suck. --- linux-2.6-e1000-ich9-montevina.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-e1000-ich9-montevina.patch b/linux-2.6-e1000-ich9-montevina.patch index 8f494c0ff..d45fd5673 100644 --- a/linux-2.6-e1000-ich9-montevina.patch +++ b/linux-2.6-e1000-ich9-montevina.patch @@ -11,7 +11,7 @@ enough to carry just to keep those SDVs working. switch (phy->id) { + case 0: + if (hw->adapter->pdev->device == 0x10be) -+ e_dbg(hw, "got 0 phy id, trying anyway"); ++ e_dbg("got 0 phy id, trying anyway"); + /* Fall through to IGP03E1000 case below */ + else + return -E1000_ERR_PHY; From 7043d42b5aa70ca638d63b479968ad550822e070 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Sep 2010 13:19:07 +1000 Subject: [PATCH 083/277] nouveau: fix potential dma race --- drm-nouveau-ibdma-race.patch | 29 +++++++++++++++++++++++++++++ kernel.spec | 8 +++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 drm-nouveau-ibdma-race.patch diff --git a/drm-nouveau-ibdma-race.patch b/drm-nouveau-ibdma-race.patch new file mode 100644 index 000000000..23a60046a --- /dev/null +++ b/drm-nouveau-ibdma-race.patch @@ -0,0 +1,29 @@ +From 55647c139cf7d6caeaa08a99b2165763a02ab71a Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Thu, 30 Sep 2010 09:09:42 +1000 +Subject: [PATCH] drm/nv50: prevent (IB_PUT == IB_GET) for occurring unless idle + +Should fix a DMA race condition I've never seen myself, but could be +the culprit in some random hangs that have been reported. + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_dma.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c +index 9d27acd..eb24e2b 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dma.c +@@ -214,7 +214,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) + + chan->dma.ib_free = get - chan->dma.ib_put; + if (chan->dma.ib_free <= 0) +- chan->dma.ib_free += chan->dma.ib_max + 1; ++ chan->dma.ib_free += chan->dma.ib_max; + } + + return 0; +-- +1.7.2.2 + diff --git a/kernel.spec b/kernel.spec index d68ba8df5..186da00c2 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 35 +%global baserelease 36 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -666,6 +666,7 @@ Patch1807: drm-i2c-ch7006-fix.patch Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch Patch1812: drm-nouveau-nva3-noaccel.patch +Patch1813: drm-nouveau-ibdma-race.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1300,6 +1301,7 @@ ApplyPatch drm-i2c-ch7006-fix.patch ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-nouveau-nva3-noaccel.patch +ApplyPatch drm-nouveau-ibdma-race.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch @@ -1968,6 +1970,10 @@ fi # and build. %changelog +* Thu Sep 30 2010 Ben Skeggs 2.6.35.6-36 +- nouveau: fix theoretical race condition which may be the cause of some + random hangs people reported. + * Wed Sep 29 2010 Dave Jones 2.6.35.6-35 - Add back an old hack to make an SDV e1000e variant work. From db140fac23a1c9034887f83d5ffb2c6519879a4e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 30 Sep 2010 16:01:42 -0400 Subject: [PATCH 084/277] silence another rcu_reference warning --- kernel.spec | 8 ++ linux-2.6-rcu-sched-warning.patch | 215 ++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 linux-2.6-rcu-sched-warning.patch diff --git a/kernel.spec b/kernel.spec index 186da00c2..c95299da4 100644 --- a/kernel.spec +++ b/kernel.spec @@ -703,6 +703,8 @@ Patch2918: linux-2.6-v4l-dvb-ir-core-update-2.patch Patch3000: linux-2.6-via-velocity-dma-fix.patch +Patch3010: linux-2.6-rcu-sched-warning.patch + # NFSv4 # patches headed upstream @@ -1340,6 +1342,9 @@ ApplyPatch linux-2.6-v4l-dvb-ir-core-update-2.patch # Fix DMA bug on via-velocity ApplyPatch linux-2.6-via-velocity-dma-fix.patch +# silence another rcu_reference warning +ApplyPatch linux-2.6-rcu-sched-warning.patch + # Patches headed upstream ApplyPatch disable-i8042-check-on-apple-mac.patch @@ -1970,6 +1975,9 @@ fi # and build. %changelog +* Thu Sep 30 2010 Dave Jones +- silence another rcu_reference warning + * Thu Sep 30 2010 Ben Skeggs 2.6.35.6-36 - nouveau: fix theoretical race condition which may be the cause of some random hangs people reported. diff --git a/linux-2.6-rcu-sched-warning.patch b/linux-2.6-rcu-sched-warning.patch new file mode 100644 index 000000000..ab3ff006b --- /dev/null +++ b/linux-2.6-rcu-sched-warning.patch @@ -0,0 +1,215 @@ +From davej Thu Sep 16 11:55:58 2010 +Return-Path: linux-kernel-owner@vger.kernel.org +X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on gelk +X-Spam-Level: +X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED, + T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 +Received: from mail.corp.redhat.com [10.5.5.52] + by gelk with IMAP (fetchmail-6.3.17) + for (single-drop); Thu, 16 Sep 2010 11:55:58 -0400 (EDT) +Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO + zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by + mail04.corp.redhat.com with LMTP; Thu, 16 Sep 2010 11:51:27 -0400 (EDT) +Received: from localhost (localhost.localdomain [127.0.0.1]) + by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4889C9FC56; + Thu, 16 Sep 2010 11:51:27 -0400 (EDT) +Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) + by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id 94mQrmwfCpY4; Thu, 16 Sep 2010 11:51:27 -0400 (EDT) +Received: from int-mx03.intmail.prod.int.phx2.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.16]) + by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 0DBDB9FC4B; + Thu, 16 Sep 2010 11:51:27 -0400 (EDT) +Received: from mx1.redhat.com (ext-mx05.extmail.prod.ext.phx2.redhat.com [10.5.110.9]) + by int-mx03.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o8GFpQnO003857; + Thu, 16 Sep 2010 11:51:26 -0400 +Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) + by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o8GFFCFE031066; + Thu, 16 Sep 2010 11:51:17 -0400 +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S1755493Ab0IPPvH (ORCPT + 41 others); + Thu, 16 Sep 2010 11:51:07 -0400 +Received: from casper.infradead.org ([85.118.1.10]:41834 "EHLO + casper.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S1754921Ab0IPPvC convert rfc822-to-8bit (ORCPT + ); + Thu, 16 Sep 2010 11:51:02 -0400 +Received: from f199130.upc-f.chello.nl ([80.56.199.130] helo=laptop) + by casper.infradead.org with esmtpsa (Exim 4.72 #1 (Red Hat Linux)) + id 1OwGjI-0003VE-Ux; Thu, 16 Sep 2010 15:50:33 +0000 +Received: by laptop (Postfix, from userid 1000) + id 6DCDB100AEB1D; Thu, 16 Sep 2010 17:50:32 +0200 (CEST) +Subject: Re: 2.6.35-stable/ppc64/p7: suspicious rcu_dereference_check() + usage detected during 2.6.35-stable boot +From: Peter Zijlstra +To: paulmck@linux.vnet.ibm.com +Cc: Subrata Modak , + linux-kernel , + Li Zefan , Linuxppc-dev , + sachinp , + DIVYA PRAKASH , + "Valdis.Kletnieks" +In-Reply-To: <20100809161200.GC3026@linux.vnet.ibm.com> +References: <1280739132.15317.9.camel@subratamodak.linux.ibm.com> + <20100809161200.GC3026@linux.vnet.ibm.com> +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: 8BIT +Date: Thu, 16 Sep 2010 17:50:31 +0200 +Message-ID: <1284652231.2275.569.camel@laptop> +Mime-Version: 1.0 +Sender: linux-kernel-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-kernel@vger.kernel.org +X-RedHat-Spam-Score: -2.31 (RCVD_IN_DNSWL_MED,T_RP_MATCHES_RCVD) +X-Scanned-By: MIMEDefang 2.67 on 10.5.11.16 +X-Scanned-By: MIMEDefang 2.67 on 10.5.110.9 +Status: RO +Content-Length: 6752 +Lines: 145 + +On Mon, 2010-08-09 at 09:12 -0700, Paul E. McKenney wrote: + +> > [ 0.051203] CPU0: AMD QEMU Virtual CPU version 0.12.4 stepping 03 +> > [ 0.052999] lockdep: fixing up alternatives. +> > [ 0.054105] +> > [ 0.054106] =================================================== +> > [ 0.054999] [ INFO: suspicious rcu_dereference_check() usage. ] +> > [ 0.054999] --------------------------------------------------- +> > [ 0.054999] kernel/sched.c:616 invoked rcu_dereference_check() without protection! +> > [ 0.054999] +> > [ 0.054999] other info that might help us debug this: +> > [ 0.054999] +> > [ 0.054999] +> > [ 0.054999] rcu_scheduler_active = 1, debug_locks = 1 +> > [ 0.054999] 3 locks held by swapper/1: +> > [ 0.054999] #0: (cpu_add_remove_lock){+.+.+.}, at: [] cpu_up+0x42/0x6a +> > [ 0.054999] #1: (cpu_hotplug.lock){+.+.+.}, at: [] cpu_hotplug_begin+0x2a/0x51 +> > [ 0.054999] #2: (&rq->lock){-.-...}, at: [] init_idle+0x2f/0x113 +> > [ 0.054999] +> > [ 0.054999] stack backtrace: +> > [ 0.054999] Pid: 1, comm: swapper Not tainted 2.6.35 #1 +> > [ 0.054999] Call Trace: +> > [ 0.054999] [] lockdep_rcu_dereference+0x9b/0xa3 +> > [ 0.054999] [] task_group+0x7b/0x8a +> > [ 0.054999] [] set_task_rq+0x13/0x40 +> > [ 0.054999] [] init_idle+0xd2/0x113 +> > [ 0.054999] [] fork_idle+0xb8/0xc7 +> > [ 0.054999] [] ? mark_held_locks+0x4d/0x6b +> > [ 0.054999] [] do_fork_idle+0x17/0x2b +> > [ 0.054999] [] native_cpu_up+0x1c1/0x724 +> > [ 0.054999] [] ? do_fork_idle+0x0/0x2b +> > [ 0.054999] [] _cpu_up+0xac/0x127 +> > [ 0.054999] [] cpu_up+0x55/0x6a +> > [ 0.054999] [] kernel_init+0xe1/0x1ff +> > [ 0.054999] [] kernel_thread_helper+0x4/0x10 +> > [ 0.054999] [] ? restore_args+0x0/0x30 +> > [ 0.054999] [] ? kernel_init+0x0/0x1ff +> > [ 0.054999] [] ? kernel_thread_helper+0x0/0x10 +> > [ 0.056074] Booting Node 0, Processors #1lockdep: fixing up alternatives. +> > [ 0.130045] #2lockdep: fixing up alternatives. +> > [ 0.203089] #3 Ok. +> > [ 0.275286] Brought up 4 CPUs +> > [ 0.276005] Total of 4 processors activated (16017.17 BogoMIPS). +> +> This does look like a new one, thank you for reporting it! +> +> Here is my analysis, which should at least provide some humor value to +> those who understand the code better than I do. ;-) +> +> So the corresponding rcu_dereference_check() is in +> task_subsys_state_check(), and is fetching the cpu_cgroup_subsys_id +> element of the newly created task's task->cgroups->subsys[] array. +> The "git grep" command finds only three uses of cpu_cgroup_subsys_id, +> but no definition. +> +> Now, fork_idle() invokes copy_process(), which invokes cgroup_fork(), +> which sets the child process's ->cgroups pointer to that of the parent, +> also invoking get_css_set(), which increments the corresponding reference +> count, doing both operations under task_lock() protection (->alloc_lock). +> Because fork_idle() does not specify any of CLONE_NEWNS, CLONE_NEWUTS, +> CLONE_NEWIPC, CLONE_NEWPID, or CLONE_NEWNET, copy_namespaces() should +> not create a new namespace, and so there should be no ns_cgroup_clone(). +> We should thus retain the parent's ->cgroups pointer. And copy_process() +> installs the new task in the various lists, so that the task is externally +> accessible upon return. +> +> After a non-error return from copy_process(), fork_init() invokes +> init_idle_pid(), which does not appear to affect the task's cgroup +> state. Next fork_init() invokes init_idle(), which in turn invokes +> __set_task_cpu(), which invokes set_task_rq(), which calls task_group() +> several times, which calls task_subsys_state_check(), which calls the +> rcu_dereference_check() that complained above. +> +> However, the result returns by rcu_dereference_check() is stored into +> the task structure: +> +> p->se.cfs_rq = task_group(p)->cfs_rq[cpu]; +> p->se.parent = task_group(p)->se[cpu]; +> +> This means that the corresponding structure must have been tied down with +> a reference count or some such. If such a reference has been taken, then +> this complaint is a false positive, and could be suppressed by putting +> rcu_read_lock() and rcu_read_unlock() around the call to init_idle() +> from fork_idle(). However, although, reference to the enclosing ->cgroups +> struct css_set is held, it is not clear to me that this reference applies +> to the structures pointed to by the ->subsys[] array, especially given +> that the cgroup_subsys_state structures referenced by this array have +> their own reference count, which does not appear to me to be acquired +> by this code path. +> +> Or are the cgroup_subsys_state structures referenced by idle tasks +> never freed or some such? + +I would hope so!, the idle tasks should be part of the root cgroup, +which is not removable. + +The problem is that while we do in-fact hold rq->lock, the newly spawned +idle thread's cpu is not yet set to the correct cpu so the lockdep check +in task_group(): + + lockdep_is_held(&task_rq(p)->lock) + +will fail. + +But of a chicken and egg problem. Setting the cpu needs to have the cpu +set ;-) + +Ingo, why do we have rq->lock there at all? The CPU isn't up and running +yet, nothing should be touching it. + +Signed-off-by: Peter Zijlstra +--- + kernel/sched.c | 12 ++++++++++++ + 1 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/kernel/sched.c b/kernel/sched.c +index bd8b487..6241049 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -5332,7 +5332,19 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) + idle->se.exec_start = sched_clock(); + + cpumask_copy(&idle->cpus_allowed, cpumask_of(cpu)); ++ /* ++ * We're having a chicken and egg problem, even though we are ++ * holding rq->lock, the cpu isn't yet set to this cpu so the ++ * lockdep check in task_group() will fail. ++ * ++ * Similar case to sched_fork(). / Alternatively we could ++ * use task_rq_lock() here and obtain the other rq->lock. ++ * ++ * Silence PROVE_RCU ++ */ ++ rcu_read_lock(); + __set_task_cpu(idle, cpu); ++ rcu_read_unlock(); + + rq->curr = rq->idle = idle; + #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) + +-- +To unsubscribe from this list: send the line "unsubscribe linux-kernel" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html +Please read the FAQ at http://www.tux.org/lkml/ + From 2e4b75da82511e4f124bdb5af1641d77c3d49b82 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 1 Oct 2010 15:52:28 +1000 Subject: [PATCH 085/277] nouveau: more fixes --- drm-nouveau-ibdma-race.patch | 29 -- drm-nouveau-updates.patch | 609 +++++++++++++++++++++++++++-------- kernel.spec | 8 +- 3 files changed, 481 insertions(+), 165 deletions(-) delete mode 100644 drm-nouveau-ibdma-race.patch diff --git a/drm-nouveau-ibdma-race.patch b/drm-nouveau-ibdma-race.patch deleted file mode 100644 index 23a60046a..000000000 --- a/drm-nouveau-ibdma-race.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 55647c139cf7d6caeaa08a99b2165763a02ab71a Mon Sep 17 00:00:00 2001 -From: Ben Skeggs -Date: Thu, 30 Sep 2010 09:09:42 +1000 -Subject: [PATCH] drm/nv50: prevent (IB_PUT == IB_GET) for occurring unless idle - -Should fix a DMA race condition I've never seen myself, but could be -the culprit in some random hangs that have been reported. - -Signed-off-by: Ben Skeggs ---- - drivers/gpu/drm/nouveau/nouveau_dma.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c -index 9d27acd..eb24e2b 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_dma.c -+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c -@@ -214,7 +214,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) - - chan->dma.ib_free = get - chan->dma.ib_put; - if (chan->dma.ib_free <= 0) -- chan->dma.ib_free += chan->dma.ib_max + 1; -+ chan->dma.ib_free += chan->dma.ib_max; - } - - return 0; --- -1.7.2.2 - diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 1939d9b9a..ec86a44d9 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1,4 +1,4 @@ -From 1a79b8673c5f061a87b5fe1579e3de5a50aadea5 Mon Sep 17 00:00:00 2001 +From b1bfbda896a9d9d8e8bd86dd08aac2b2f9928ce1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Jun 2010 15:32:24 +1000 Subject: [PATCH] drm-nouveau-updates @@ -1026,6 +1026,85 @@ drm/nouveau: correct INIT_DP_CONDITION subcondition 5 Fixes DP output on a GTX 465 board I have. +Signed-off-by: Ben Skeggs + +drm/nouveau: add debugfs file to forcibly evict everything from vram + +Very useful for debugging buffer migration issues. + +Signed-off-by: Ben Skeggs + +drm/nv50: assume smaller tiles for bo moves + +Somehow fixes some corruption seen in KDE.. + +Signed-off-by: Ben Skeggs + +drm/nouveau: fix panels using straps-based mode detection + +nouveau_bios_fp_mode() zeroes the mode struct before filling in relevant +entries. This nukes the mode id initialised by drm_mode_create(), and +causes warnings from idr when we try to remove the mode. + +Signed-off-by: Ben Skeggs + +drm/nv10: Don't oops if the card wants to switch to a channel with no grctx. + +Signed-off-by: Francisco Jerez + +drm/nouveau: enable enhanced framing only if DP display supports it + +Reported-by: Adam Jackson +Signed-off-by: Ben Skeggs + +drm/nouveau: fix typo in c2aa91afea5f7e7ae4530fabd37414a79c03328c + +Signed-off-by: Ben Skeggs + +drm/nouveau: fix required mode bandwidth calculation for DP + +This should fix eDP on certain laptops with 18-bit panels, we were rejecting +the panel's native mode due to thinking there was insufficient bandwidth +for it. + +Signed-off-by: Ben Skeggs + +drm/nv30-nv40: Fix postdivider mask when writing engine/memory PLLs. + +Signed-off-by: Francisco Jerez + +drm/nv0x-nv4x: Leave the 0x40 bit untouched when changing CRE_LCD. + +It's an unrelated PLL filtering control bit, leave it alone when +changing the CRTC-encoder binding. + +Signed-off-by: Francisco Jerez + +drm/nv50: prevent (IB_PUT == IB_GET) for occurring unless idle + +Should fix a DMA race condition I've never seen myself, but could be +the culprit in some random hangs that have been reported. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Add a module option to force card POST. + +Signed-off-by: Ben Skeggs + +drm/nouveau: Try to fetch an EDID from OF if DDC fails. + +More Apple brain damage, it fixes the modesetting failure on an eMac +G4 (fdo bug 29810). + +Reported-by: Zoltan Varnagy +Signed-off-by: Francisco Jerez + +drm/nouveau: better handling of unmappable vram + +Signed-off-by: Ben Skeggs + +drm/nouveau: fix chipset vs card_type thinko + Signed-off-by: Ben Skeggs --- drivers/gpu/drm/drm_crtc_helper.c | 22 +- @@ -1034,24 +1113,25 @@ Signed-off-by: Ben Skeggs drivers/gpu/drm/nouveau/Kconfig | 1 + drivers/gpu/drm/nouveau/Makefile | 12 +- drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 +- - drivers/gpu/drm/nouveau/nouveau_bios.c | 912 ++++++-- + drivers/gpu/drm/nouveau/nouveau_bios.c | 914 ++++++-- drivers/gpu/drm/nouveau/nouveau_bios.h | 6 +- - drivers/gpu/drm/nouveau/nouveau_bo.c | 228 ++- + drivers/gpu/drm/nouveau/nouveau_bo.c | 251 ++- drivers/gpu/drm/nouveau/nouveau_calc.c | 10 +- drivers/gpu/drm/nouveau/nouveau_channel.c | 18 +- - drivers/gpu/drm/nouveau/nouveau_connector.c | 417 ++-- - drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +- - drivers/gpu/drm/nouveau/nouveau_dma.c | 21 +- - drivers/gpu/drm/nouveau/nouveau_dp.c | 131 +- - drivers/gpu/drm/nouveau/nouveau_drv.c | 45 +- - drivers/gpu/drm/nouveau/nouveau_drv.h | 309 ++-- - drivers/gpu/drm/nouveau/nouveau_encoder.h | 16 +- + drivers/gpu/drm/nouveau/nouveau_connector.c | 473 ++-- + drivers/gpu/drm/nouveau/nouveau_connector.h | 10 +- + drivers/gpu/drm/nouveau/nouveau_debugfs.c | 16 + + drivers/gpu/drm/nouveau/nouveau_dma.c | 23 +- + drivers/gpu/drm/nouveau/nouveau_dp.c | 138 +- + drivers/gpu/drm/nouveau/nouveau_drv.c | 49 +- + drivers/gpu/drm/nouveau/nouveau_drv.h | 310 ++-- + drivers/gpu/drm/nouveau/nouveau_encoder.h | 17 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- drivers/gpu/drm/nouveau/nouveau_fence.c | 35 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 15 +- drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 -- drivers/gpu/drm/nouveau/nouveau_grctx.h | 2 +- - drivers/gpu/drm/nouveau/nouveau_hw.c | 13 +- + drivers/gpu/drm/nouveau/nouveau_hw.c | 15 +- drivers/gpu/drm/nouveau/nouveau_i2c.c | 83 +- drivers/gpu/drm/nouveau/nouveau_i2c.h | 11 +- drivers/gpu/drm/nouveau/nouveau_irq.c | 129 +- @@ -1064,20 +1144,20 @@ Signed-off-by: Ben Skeggs drivers/gpu/drm/nouveau/nouveau_sgdma.c | 118 +- drivers/gpu/drm/nouveau/nouveau_state.c | 398 ++-- drivers/gpu/drm/nouveau/nv04_crtc.c | 11 +- - drivers/gpu/drm/nouveau/nv04_dac.c | 60 +- - drivers/gpu/drm/nouveau/nv04_dfp.c | 145 +- + drivers/gpu/drm/nouveau/nv04_dac.c | 61 +- + drivers/gpu/drm/nouveau/nv04_dfp.c | 147 +- drivers/gpu/drm/nouveau/nv04_display.c | 90 +- drivers/gpu/drm/nouveau/nv04_fbcon.c | 9 +- drivers/gpu/drm/nouveau/nv04_fifo.c | 88 +- drivers/gpu/drm/nouveau/nv04_graph.c | 5 +- drivers/gpu/drm/nouveau/nv04_instmem.c | 167 +- drivers/gpu/drm/nouveau/nv04_mc.c | 4 + - drivers/gpu/drm/nouveau/nv04_tv.c | 133 +- + drivers/gpu/drm/nouveau/nv04_tv.c | 139 +- drivers/gpu/drm/nouveau/nv10_fifo.c | 29 +- drivers/gpu/drm/nouveau/nv10_gpio.c | 92 + - drivers/gpu/drm/nouveau/nv10_graph.c | 175 +- + drivers/gpu/drm/nouveau/nv10_graph.c | 177 +- drivers/gpu/drm/nouveau/nv17_gpio.c | 92 - - drivers/gpu/drm/nouveau/nv17_tv.c | 181 +- + drivers/gpu/drm/nouveau/nv17_tv.c | 179 +- drivers/gpu/drm/nouveau/nv17_tv.h | 15 +- drivers/gpu/drm/nouveau/nv17_tv_modes.c | 48 +- drivers/gpu/drm/nouveau/nv20_graph.c | 576 +++--- @@ -1103,8 +1183,8 @@ Signed-off-by: Ben Skeggs drivers/gpu/drm/nouveau/nvc0_fifo.c | 89 + drivers/gpu/drm/nouveau/nvc0_graph.c | 74 + drivers/gpu/drm/nouveau/nvc0_instmem.c | 229 ++ - drivers/gpu/drm/nouveau/nvreg.h | 22 - - 76 files changed, 7472 insertions(+), 5278 deletions(-) + drivers/gpu/drm/nouveau/nvreg.h | 23 +- + 77 files changed, 7584 insertions(+), 5293 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.h @@ -1352,7 +1432,7 @@ index d4bcca8..1191526 100644 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index e492919..47bc0ba 100644 +index e492919..72905c9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -28,6 +28,8 @@ @@ -2829,7 +2909,7 @@ index e492919..47bc0ba 100644 int ret; if (!NVInitVBIOS(dev)) -@@ -6284,40 +6797,27 @@ nouveau_bios_init(struct drm_device *dev) +@@ -6284,40 +6797,29 @@ nouveau_bios_init(struct drm_device *dev) if (!bios->major_version) /* we don't run version 0 bios */ return 0; @@ -2853,9 +2933,11 @@ index e492919..47bc0ba 100644 + "running VBIOS init tables.\n"); bios->execute = true; } - -- bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); - +- bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); ++ if (nouveau_force_post) ++ bios->execute = true; + ret = nouveau_run_vbios_init(dev); if (ret) return ret; @@ -2918,10 +3000,10 @@ index adf4ec2..c1de2f3 100644 struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index 6f3c195..22a2038 100644 +index 51746d9..a4011f5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c -@@ -43,17 +43,12 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) +@@ -58,17 +58,12 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); @@ -2939,7 +3021,16 @@ index 6f3c195..22a2038 100644 kfree(nvbo); } -@@ -166,9 +161,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, +@@ -167,8 +162,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, + nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); + align >>= PAGE_SHIFT; + +- nvbo->placement.fpfn = 0; +- nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0; + nouveau_bo_placement_set(nvbo, flags, 0); + + nvbo->channel = chan; +@@ -181,9 +174,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } nvbo->channel = NULL; @@ -2949,7 +3040,7 @@ index 6f3c195..22a2038 100644 *pnvbo = nvbo; return 0; } -@@ -296,7 +288,8 @@ nouveau_bo_map(struct nouveau_bo *nvbo) +@@ -311,7 +301,8 @@ nouveau_bo_map(struct nouveau_bo *nvbo) void nouveau_bo_unmap(struct nouveau_bo *nvbo) { @@ -2959,7 +3050,7 @@ index 6f3c195..22a2038 100644 } u16 -@@ -395,7 +388,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, +@@ -410,7 +401,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; @@ -2971,7 +3062,7 @@ index 6f3c195..22a2038 100644 break; case TTM_PL_TT: switch (dev_priv->gart_info.type) { -@@ -461,18 +457,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, +@@ -476,18 +470,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, @@ -2998,7 +3089,7 @@ index 6f3c195..22a2038 100644 if (mem->mem_type == TTM_PL_TT) return NvDmaGART; return NvDmaVRAM; -@@ -484,86 +482,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, +@@ -499,86 +495,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, } static int @@ -3060,8 +3151,8 @@ index 6f3c195..22a2038 100644 + while (length) { + u32 amount, stride, height; + -+ amount = min(length, (u64)(16 * 1024 * 1024)); -+ stride = 64 * 4; ++ amount = min(length, (u64)(4 * 1024 * 1024)); ++ stride = 16 * 4; + height = amount / stride; + + if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { @@ -3071,7 +3162,7 @@ index 6f3c195..22a2038 100644 + + BEGIN_RING(chan, NvSubM2MF, 0x0200, 7); + OUT_RING (chan, 0); -+ OUT_RING (chan, 0x20); ++ OUT_RING (chan, 0); + OUT_RING (chan, stride); + OUT_RING (chan, height); + OUT_RING (chan, 1); @@ -3092,7 +3183,7 @@ index 6f3c195..22a2038 100644 + + BEGIN_RING(chan, NvSubM2MF, 0x021c, 7); + OUT_RING (chan, 0); -+ OUT_RING (chan, 0x20); ++ OUT_RING (chan, 0); + OUT_RING (chan, stride); + OUT_RING (chan, height); + OUT_RING (chan, 1); @@ -3225,7 +3316,7 @@ index 6f3c195..22a2038 100644 return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); } -@@ -710,13 +803,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, +@@ -725,13 +816,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) return ret; @@ -3239,7 +3330,7 @@ index 6f3c195..22a2038 100644 /* Fake bo copy. */ if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { BUG_ON(bo->mem.mm_node != NULL); -@@ -725,6 +811,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, +@@ -740,6 +824,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, goto out; } @@ -3252,6 +3343,34 @@ index 6f3c195..22a2038 100644 /* Hardware assisted copy. */ if (new_mem->mem_type == TTM_PL_SYSTEM) ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); +@@ -815,7 +905,26 @@ nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) + static int + nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) + { +- return 0; ++ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ ++ /* as long as the bo isn't in vram, and isn't tiled, we've got ++ * nothing to do here. ++ */ ++ if (bo->mem.mem_type != TTM_PL_VRAM) { ++ if (dev_priv->card_type < NV_50 || !nvbo->tile_flags) ++ return 0; ++ } ++ ++ /* make sure bo is in mappable vram */ ++ if (bo->mem.mm_node->start + bo->mem.num_pages < dev_priv->fb_mappable_pages) ++ return 0; ++ ++ ++ nvbo->placement.fpfn = 0; ++ nvbo->placement.lpfn = dev_priv->fb_mappable_pages; ++ nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0); ++ return ttm_bo_validate(bo, &nvbo->placement, false, true, false); + } + + struct ttm_bo_driver nouveau_bo_driver = { diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c index 88f9bc0..23d9896 100644 --- a/drivers/gpu/drm/nouveau/nouveau_calc.c @@ -3360,7 +3479,7 @@ index 1fc57ef..53c2a6f 100644 nouveau_channel_free(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c -index 149ed22..a1473ff 100644 +index 149ed22..46584c3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -37,12 +37,6 @@ @@ -3376,7 +3495,30 @@ index 149ed22..a1473ff 100644 static struct nouveau_encoder * find_encoder_by_type(struct drm_connector *connector, int type) { -@@ -102,60 +96,12 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) +@@ -82,6 +76,22 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder) + return NULL; + } + ++/*TODO: This could use improvement, and learn to handle the fixed ++ * BIOS tables etc. It's fine currently, for its only user. ++ */ ++int ++nouveau_connector_bpp(struct drm_connector *connector) ++{ ++ struct nouveau_connector *nv_connector = nouveau_connector(connector); ++ ++ if (nv_connector->edid && nv_connector->edid->revision >= 4) { ++ u8 bpc = ((nv_connector->edid->input & 0x70) >> 3) + 4; ++ if (bpc > 4) ++ return bpc; ++ } ++ ++ return 18; ++} + + static void + nouveau_connector_destroy(struct drm_connector *drm_connector) +@@ -102,60 +112,12 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) kfree(drm_connector); } @@ -3438,7 +3580,7 @@ index 149ed22..a1473ff 100644 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { struct nouveau_i2c_chan *i2c = NULL; -@@ -174,14 +120,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, +@@ -174,14 +136,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, if (nv_encoder->dcb->i2c_index < 0xf) i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); @@ -3454,7 +3596,44 @@ index 149ed22..a1473ff 100644 *pnv_encoder = nv_encoder; return i2c; } -@@ -234,21 +174,7 @@ nouveau_connector_detect(struct drm_connector *connector) +@@ -190,6 +146,36 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, + return NULL; + } + ++static struct nouveau_encoder * ++nouveau_connector_of_detect(struct drm_connector *connector) ++{ ++#ifdef __powerpc__ ++ struct drm_device *dev = connector->dev; ++ struct nouveau_connector *nv_connector = nouveau_connector(connector); ++ struct nouveau_encoder *nv_encoder; ++ struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev); ++ ++ if (!dn || ++ !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) || ++ (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG)))) ++ return NULL; ++ ++ for_each_child_of_node(dn, cn) { ++ const char *name = of_get_property(cn, "name", NULL); ++ const void *edid = of_get_property(cn, "EDID", NULL); ++ int idx = name ? name[strlen(name) - 1] - 'A' : 0; ++ ++ if (nv_encoder->dcb->i2c_index == idx && edid) { ++ nv_connector->edid = ++ kmemdup(edid, EDID_LENGTH, GFP_KERNEL); ++ of_node_put(cn); ++ return nv_encoder; ++ } ++ } ++#endif ++ return NULL; ++} ++ + static void + nouveau_connector_set_encoder(struct drm_connector *connector, + struct nouveau_encoder *nv_encoder) +@@ -234,21 +220,7 @@ nouveau_connector_detect(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_i2c_chan *i2c; @@ -3477,7 +3656,7 @@ index 149ed22..a1473ff 100644 /* Cleanup the previous EDID block. */ if (nv_connector->edid) { -@@ -259,9 +185,7 @@ nouveau_connector_detect(struct drm_connector *connector) +@@ -259,9 +231,7 @@ nouveau_connector_detect(struct drm_connector *connector) i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { @@ -3487,7 +3666,20 @@ index 149ed22..a1473ff 100644 drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { -@@ -321,6 +245,85 @@ detect_analog: +@@ -301,6 +271,12 @@ nouveau_connector_detect(struct drm_connector *connector) + return connector_status_connected; + } + ++ nv_encoder = nouveau_connector_of_detect(connector); ++ if (nv_encoder) { ++ nouveau_connector_set_encoder(connector, nv_encoder); ++ return connector_status_connected; ++ } ++ + detect_analog: + nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); + if (!nv_encoder && !nouveau_tv_disable) +@@ -321,6 +297,85 @@ detect_analog: return connector_status_disconnected; } @@ -3573,7 +3765,7 @@ index 149ed22..a1473ff 100644 static void nouveau_connector_force(struct drm_connector *connector) { -@@ -353,6 +356,7 @@ nouveau_connector_set_property(struct drm_connector *connector, +@@ -353,6 +408,7 @@ nouveau_connector_set_property(struct drm_connector *connector, { struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; @@ -3581,7 +3773,7 @@ index 149ed22..a1473ff 100644 struct drm_device *dev = connector->dev; int ret; -@@ -425,8 +429,8 @@ nouveau_connector_set_property(struct drm_connector *connector, +@@ -425,8 +481,8 @@ nouveau_connector_set_property(struct drm_connector *connector, } if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) @@ -3592,7 +3784,7 @@ index 149ed22..a1473ff 100644 return -EINVAL; } -@@ -441,7 +445,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) +@@ -441,7 +497,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) int high_w = 0, high_h = 0, high_v = 0; list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { @@ -3602,7 +3794,7 @@ index 149ed22..a1473ff 100644 continue; /* Use preferred mode if there is one.. */ -@@ -534,21 +539,28 @@ static int +@@ -534,21 +591,30 @@ static int nouveau_connector_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -3629,13 +3821,15 @@ index 149ed22..a1473ff 100644 + if (nv_encoder->dcb->type == OUTPUT_LVDS && + (nv_encoder->dcb->lvdsconf.use_straps_for_mode || + dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) { -+ nv_connector->native_mode = drm_mode_create(dev); -+ nouveau_bios_fp_mode(dev, nv_connector->native_mode); ++ struct drm_display_mode mode; ++ ++ nouveau_bios_fp_mode(dev, &mode); ++ nv_connector->native_mode = drm_mode_duplicate(dev, &mode); + } /* Find the native mode if this is a digital panel, if we didn't * find any modes through DDC previously add the native mode to -@@ -566,10 +578,10 @@ nouveau_connector_get_modes(struct drm_connector *connector) +@@ -566,10 +632,10 @@ nouveau_connector_get_modes(struct drm_connector *connector) } if (nv_encoder->dcb->type == OUTPUT_TV) @@ -3649,7 +3843,7 @@ index 149ed22..a1473ff 100644 ret += nouveau_connector_scaler_modes_add(connector); return ret; -@@ -582,6 +594,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, +@@ -582,6 +648,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; @@ -3657,7 +3851,7 @@ index 149ed22..a1473ff 100644 unsigned min_clock = 25000, max_clock = min_clock; unsigned clock = mode->clock; -@@ -608,8 +621,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, +@@ -608,15 +675,14 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 350000; break; case OUTPUT_TV: @@ -3667,7 +3861,15 @@ index 149ed22..a1473ff 100644 case OUTPUT_DP: if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) max_clock = nv_encoder->dp.link_nr * 270000; -@@ -643,6 +655,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) + else + max_clock = nv_encoder->dp.link_nr * 162000; + +- clock *= 3; ++ clock = clock * nouveau_connector_bpp(connector) / 8; + break; + default: + BUG_ON(1); +@@ -643,6 +709,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } @@ -3712,7 +3914,7 @@ index 149ed22..a1473ff 100644 static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, -@@ -662,148 +712,74 @@ nouveau_connector_funcs = { +@@ -662,148 +766,74 @@ nouveau_connector_funcs = { .force = nouveau_connector_force }; @@ -3887,7 +4089,7 @@ index 149ed22..a1473ff 100644 nv_connector->dcb = dcb; connector = &nv_connector->base; -@@ -811,27 +787,21 @@ nouveau_connector_create(struct drm_device *dev, +@@ -811,27 +841,21 @@ nouveau_connector_create(struct drm_device *dev, connector->interlace_allowed = false; connector->doublescan_allowed = false; @@ -3926,7 +4128,7 @@ index 149ed22..a1473ff 100644 } /* Init DVI-I specific properties */ -@@ -841,12 +811,8 @@ nouveau_connector_create(struct drm_device *dev, +@@ -841,12 +865,8 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0); } @@ -3939,7 +4141,7 @@ index 149ed22..a1473ff 100644 if (dev_priv->card_type >= NV_50) { drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, -@@ -858,17 +824,6 @@ nouveau_connector_create(struct drm_device *dev, +@@ -858,17 +878,6 @@ nouveau_connector_create(struct drm_device *dev, case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; break; @@ -3957,7 +4159,7 @@ index 149ed22..a1473ff 100644 default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; -@@ -882,15 +837,15 @@ nouveau_connector_create(struct drm_device *dev, +@@ -882,15 +891,15 @@ nouveau_connector_create(struct drm_device *dev, break; } @@ -3982,10 +4184,10 @@ index 149ed22..a1473ff 100644 - return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h -index 4ef38ab..0d2e668 100644 +index 4ef38ab..c21ed6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h -@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector( +@@ -49,7 +49,13 @@ static inline struct nouveau_connector *nouveau_connector( return container_of(con, struct nouveau_connector, base); } @@ -3996,10 +4198,41 @@ index 4ef38ab..0d2e668 100644 + +void +nouveau_connector_set_polling(struct drm_connector *); ++ ++int ++nouveau_connector_bpp(struct drm_connector *); #endif /* __NOUVEAU_CONNECTOR_H__ */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c +index 7933de4..8e15923 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c ++++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c +@@ -157,7 +157,23 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data) + return 0; + } + ++static int ++nouveau_debugfs_evict_vram(struct seq_file *m, void *data) ++{ ++ struct drm_info_node *node = (struct drm_info_node *) m->private; ++ struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private; ++ int ret; ++ ++ ret = ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ++ if (ret) ++ seq_printf(m, "failed: %d", ret); ++ else ++ seq_printf(m, "succeeded\n"); ++ return 0; ++} ++ + static struct drm_info_list nouveau_debugfs_list[] = { ++ { "evict_vram", nouveau_debugfs_evict_vram, 0, NULL }, + { "chipset", nouveau_debugfs_chipset_info, 0, NULL }, + { "memory", nouveau_debugfs_memory_info, 0, NULL }, + { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL }, diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c -index 65c441a..9d27acd 100644 +index 65c441a..eb24e2b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -28,6 +28,7 @@ @@ -4058,8 +4291,17 @@ index 65c441a..9d27acd 100644 /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); if (ret) +@@ -219,7 +214,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) + + chan->dma.ib_free = get - chan->dma.ib_put; + if (chan->dma.ib_free <= 0) +- chan->dma.ib_free += chan->dma.ib_max + 1; ++ chan->dma.ib_free += chan->dma.ib_max; + } + + return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c -index deeb21c..89ca1f6 100644 +index deeb21c..4562f30 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -23,8 +23,10 @@ @@ -4115,7 +4357,17 @@ index deeb21c..89ca1f6 100644 train: cr_done = eq_done = false; -@@ -403,6 +431,15 @@ stop: +@@ -289,7 +317,8 @@ train: + return false; + + config[0] = nv_encoder->dp.link_nr; +- if (nv_encoder->dp.dpcd_version >= 0x11) ++ if (nv_encoder->dp.dpcd_version >= 0x11 && ++ nv_encoder->dp.enhanced_frame) + config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + ret = nouveau_dp_lane_count_set(encoder, config[0]); +@@ -403,6 +432,15 @@ stop: } } @@ -4131,7 +4383,21 @@ index deeb21c..89ca1f6 100644 return eq_done; } -@@ -487,7 +524,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, +@@ -431,10 +469,12 @@ nouveau_dp_detect(struct drm_encoder *encoder) + !nv_encoder->dcb->dpconf.link_bw) + nv_encoder->dp.link_bw = DP_LINK_BW_1_62; + +- nv_encoder->dp.link_nr = dpcd[2] & 0xf; ++ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; + if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr) + nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; + ++ nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP); ++ + return true; + } + +@@ -487,7 +527,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); @@ -4141,7 +4407,7 @@ index deeb21c..89ca1f6 100644 NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", nv_rd32(dev, NV50_AUXCH_CTRL(index))); ret = -EBUSY; -@@ -535,47 +573,64 @@ out: +@@ -535,47 +576,64 @@ out: return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); } @@ -4242,7 +4508,7 @@ index deeb21c..89ca1f6 100644 + .functionality = nouveau_dp_i2c_func +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c -index 2737704..946748a 100644 +index 2737704..ee2442f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -35,13 +35,9 @@ @@ -4271,7 +4537,18 @@ index 2737704..946748a 100644 module_param_named(vram_notify, nouveau_vram_notify, int, 0400); MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)"); -@@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) +@@ -83,6 +79,10 @@ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); + int nouveau_nofbaccel = 0; + module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); + ++MODULE_PARM_DESC(force_post, "Force POST"); ++int nouveau_force_post = 0; ++module_param_named(force_post, nouveau_force_post, int, 0400); ++ + MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type"); + int nouveau_override_conntype = 0; + module_param_named(override_conntype, nouveau_override_conntype, int, 0400); +@@ -155,9 +155,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) struct drm_crtc *crtc; int ret, i; @@ -4281,7 +4558,7 @@ index 2737704..946748a 100644 if (pm_state.event == PM_EVENT_PRETHAW) return 0; -@@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -257,9 +254,6 @@ nouveau_pci_resume(struct pci_dev *pdev) struct drm_crtc *crtc; int ret, i; @@ -4291,7 +4568,7 @@ index 2737704..946748a 100644 nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "We're back, enabling device...\n"); -@@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -269,6 +263,13 @@ nouveau_pci_resume(struct pci_dev *pdev) return -1; pci_set_master(dev->pdev); @@ -4305,7 +4582,7 @@ index 2737704..946748a 100644 NV_INFO(dev, "POSTing device...\n"); ret = nouveau_run_vbios_init(dev); if (ret) -@@ -323,7 +320,6 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -323,7 +324,6 @@ nouveau_pci_resume(struct pci_dev *pdev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); @@ -4313,7 +4590,7 @@ index 2737704..946748a 100644 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) -@@ -332,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -332,11 +332,7 @@ nouveau_pci_resume(struct pci_dev *pdev) NV_ERROR(dev, "Could not pin/map cursor.\n"); } @@ -4326,7 +4603,7 @@ index 2737704..946748a 100644 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -@@ -371,7 +363,8 @@ nouveau_pci_resume(struct pci_dev *pdev) +@@ -371,7 +367,8 @@ nouveau_pci_resume(struct pci_dev *pdev) static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | @@ -4336,7 +4613,7 @@ index 2737704..946748a 100644 .load = nouveau_load, .firstopen = nouveau_firstopen, .lastclose = nouveau_lastclose, -@@ -438,16 +431,18 @@ static int __init nouveau_init(void) +@@ -438,16 +435,18 @@ static int __init nouveau_init(void) nouveau_modeset = 1; } @@ -4360,7 +4637,7 @@ index 2737704..946748a 100644 nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index c697191..228c8cd 100644 +index 8be2f59..be53e92 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) @@ -4701,7 +4978,7 @@ index c697191..228c8cd 100644 extern int nouveau_duallink; extern int nouveau_uscript_lvds; extern int nouveau_uscript_tmds; -@@ -682,7 +666,6 @@ extern int nouveau_tv_disable; +@@ -682,10 +666,10 @@ extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; @@ -4709,7 +4986,11 @@ index c697191..228c8cd 100644 extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; -@@ -707,17 +690,12 @@ extern bool nouveau_wait_for_idle(struct drm_device *); ++extern int nouveau_force_post; + extern int nouveau_override_conntype; + + extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); +@@ -707,17 +691,12 @@ extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ @@ -4732,7 +5013,7 @@ index c697191..228c8cd 100644 extern void nouveau_mem_close(struct drm_device *); extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, -@@ -759,7 +737,6 @@ extern void nouveau_channel_free(struct nouveau_channel *); +@@ -759,7 +738,6 @@ extern void nouveau_channel_free(struct nouveau_channel *); extern int nouveau_gpuobj_early_init(struct drm_device *); extern int nouveau_gpuobj_init(struct drm_device *); extern void nouveau_gpuobj_takedown(struct drm_device *); @@ -4740,7 +5021,7 @@ index c697191..228c8cd 100644 extern int nouveau_gpuobj_suspend(struct drm_device *dev); extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev); extern void nouveau_gpuobj_resume(struct drm_device *dev); -@@ -769,24 +746,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); +@@ -769,24 +747,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *, uint32_t size, int align, uint32_t flags, struct nouveau_gpuobj **); @@ -4770,7 +5051,7 @@ index c697191..228c8cd 100644 extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, uint64_t offset, uint64_t size, int access, int target, struct nouveau_gpuobj **); -@@ -857,11 +821,13 @@ void nouveau_register_dsm_handler(void); +@@ -857,11 +822,13 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); @@ -4784,7 +5065,7 @@ index c697191..228c8cd 100644 #endif /* nouveau_backlight.c */ -@@ -924,22 +890,29 @@ extern void nv10_fb_takedown(struct drm_device *); +@@ -924,22 +891,29 @@ extern void nv10_fb_takedown(struct drm_device *); extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); @@ -4816,7 +5097,7 @@ index c697191..228c8cd 100644 extern bool nv04_fifo_cache_pull(struct drm_device *, bool); extern int nv04_fifo_channel_id(struct drm_device *); extern int nv04_fifo_create_context(struct nouveau_channel *); -@@ -971,6 +944,19 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); +@@ -971,6 +945,19 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); @@ -4836,7 +5117,7 @@ index c697191..228c8cd 100644 /* nv04_graph.c */ extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern int nv04_graph_init(struct drm_device *); -@@ -1035,11 +1021,15 @@ extern int nv50_graph_unload_context(struct drm_device *); +@@ -1035,11 +1022,15 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); @@ -4857,7 +5138,7 @@ index c697191..228c8cd 100644 /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); -@@ -1051,8 +1041,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1051,8 +1042,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -4867,7 +5148,7 @@ index c697191..228c8cd 100644 /* nv50_instmem.c */ extern int nv50_instmem_init(struct drm_device *); -@@ -1064,8 +1053,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, +@@ -1064,8 +1054,21 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -4891,7 +5172,7 @@ index c697191..228c8cd 100644 /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); -@@ -1088,13 +1090,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, +@@ -1088,13 +1091,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nv04_dac.c */ @@ -4908,7 +5189,7 @@ index c697191..228c8cd 100644 extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, int head, bool dl); -@@ -1103,15 +1106,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); +@@ -1103,15 +1107,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); /* nv04_tv.c */ extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); @@ -4929,7 +5210,7 @@ index c697191..228c8cd 100644 /* nv04_crtc.c */ extern int nv04_crtc_create(struct drm_device *, int index); -@@ -1147,7 +1152,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); +@@ -1148,7 +1154,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); extern int nouveau_fence_flush(void *obj, void *arg); extern void nouveau_fence_unref(void **obj); extern void *nouveau_fence_ref(void *obj); @@ -4937,7 +5218,7 @@ index c697191..228c8cd 100644 /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, -@@ -1167,13 +1171,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, +@@ -1168,13 +1173,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); @@ -4956,7 +5237,7 @@ index c697191..228c8cd 100644 /* nv50_calc. */ int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, -@@ -1220,6 +1226,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) +@@ -1221,6 +1228,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) iowrite32_native(val, dev_priv->mmio + reg); } @@ -4970,7 +5251,7 @@ index c697191..228c8cd 100644 static inline u8 nv_rd08(struct drm_device *dev, unsigned reg) { struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -1232,7 +1245,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) +@@ -1233,7 +1247,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) iowrite8(val, dev_priv->mmio + reg); } @@ -4979,7 +5260,7 @@ index c697191..228c8cd 100644 nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val)) /* PRAMIN access */ -@@ -1249,17 +1262,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val) +@@ -1250,17 +1264,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val) } /* object access */ @@ -4999,7 +5280,7 @@ index c697191..228c8cd 100644 /* * Logging -@@ -1346,6 +1350,15 @@ nv_two_reg_pll(struct drm_device *dev) +@@ -1347,6 +1352,15 @@ nv_two_reg_pll(struct drm_device *dev) return false; } @@ -5016,7 +5297,7 @@ index c697191..228c8cd 100644 #define NV_SW_DMA_SEMAPHORE 0x00000060 #define NV_SW_SEMAPHORE_OFFSET 0x00000064 diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h -index e1df820..7c82d68 100644 +index e1df820..ae69b61 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -38,13 +38,15 @@ struct nouveau_encoder { @@ -5037,7 +5318,15 @@ index e1df820..7c82d68 100644 union { struct { int mc_unknown; -@@ -69,10 +71,16 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) +@@ -53,6 +55,7 @@ struct nouveau_encoder { + int dpcd_version; + int link_nr; + int link_bw; ++ bool enhanced_frame; + } dp; + }; + }; +@@ -69,10 +72,16 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) return &enc->base.base; } @@ -5198,7 +5487,7 @@ index faddf53..6b208ff 100644 } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c -index 69c76cf..62ac673 100644 +index 6937d53..613f878 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, @@ -5210,7 +5499,7 @@ index 69c76cf..62ac673 100644 if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; -@@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, +@@ -578,10 +576,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct drm_nouveau_gem_pushbuf_bo *bo; struct nouveau_channel *chan; struct validate_op op; @@ -5222,7 +5511,7 @@ index 69c76cf..62ac673 100644 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); req->vram_available = dev_priv->fb_aper_free; -@@ -650,7 +647,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, +@@ -666,7 +663,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, push[i].length); } } else @@ -5231,7 +5520,7 @@ index 69c76cf..62ac673 100644 ret = RING_SPACE(chan, req->nr_push * 2); if (ret) { NV_ERROR(dev, "cal_space: %d\n", ret); -@@ -725,7 +722,7 @@ out_next: +@@ -741,7 +738,7 @@ out_next: req->suffix0 = 0x00000000; req->suffix1 = 0x00000000; } else @@ -5240,7 +5529,7 @@ index 69c76cf..62ac673 100644 req->suffix0 = 0x00020000; req->suffix1 = 0x00000000; } else { -@@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, +@@ -776,8 +773,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); int ret = -EINVAL; @@ -5249,7 +5538,7 @@ index 69c76cf..62ac673 100644 gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return ret; -@@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, +@@ -816,8 +811,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, struct nouveau_bo *nvbo; int ret = -EINVAL; @@ -5258,7 +5547,7 @@ index 69c76cf..62ac673 100644 gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return ret; -@@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data, +@@ -843,8 +836,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data, struct drm_gem_object *gem; int ret; @@ -5447,9 +5736,18 @@ index 5d39c4c..4a8ad13 100644 #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c -index 7855b35..f8ec49b 100644 +index 7855b35..cb13134 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c +@@ -305,7 +305,7 @@ setPLL_double_lowregs(struct drm_device *dev, uint32_t NMNMreg, + bool mpll = Preg == 0x4020; + uint32_t oldPval = nvReadMC(dev, Preg); + uint32_t NMNM = pv->NM2 << 16 | pv->NM1; +- uint32_t Pval = (oldPval & (mpll ? ~(0x11 << 16) : ~(1 << 16))) | ++ uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | + 0xc << 28 | pv->log2P << 16; + uint32_t saved4600 = 0; + /* some cards have different maskc040s */ @@ -865,8 +865,13 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); @@ -9522,7 +9820,7 @@ index eba687f..291a4cb 100644 crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47); } diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c -index 1cb19e3..9cc560c 100644 +index 1cb19e3..ba6423f 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) @@ -9609,7 +9907,14 @@ index 1cb19e3..9cc560c 100644 return true; } -@@ -344,15 +352,9 @@ static void nv04_dac_prepare(struct drm_encoder *encoder) +@@ -337,22 +345,13 @@ static void nv04_dac_prepare(struct drm_encoder *encoder) + { + struct drm_encoder_helper_funcs *helper = encoder->helper_private; + struct drm_device *dev = encoder->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; + int head = nouveau_crtc(encoder->crtc)->index; +- struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg; + helper->dpms(encoder, DRM_MODE_DPMS_OFF); nv04_dfp_disable(dev, head); @@ -9619,14 +9924,13 @@ index 1cb19e3..9cc560c 100644 - */ - if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44)) - crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0; -+ crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0; } - static void nv04_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) -@@ -428,6 +430,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) +@@ -428,6 +427,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) } } @@ -9644,7 +9948,7 @@ index 1cb19e3..9cc560c 100644 static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; -@@ -501,11 +514,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { +@@ -501,11 +511,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { .destroy = nv04_dac_destroy, }; @@ -9660,7 +9964,7 @@ index 1cb19e3..9cc560c 100644 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); if (!nv_encoder) -@@ -527,5 +542,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -527,5 +539,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -9668,7 +9972,7 @@ index 1cb19e3..9cc560c 100644 return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c -index 41634d4..e331b4f 100644 +index 41634d4..762d9f2 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -34,6 +34,8 @@ @@ -9680,7 +9984,16 @@ index 41634d4..e331b4f 100644 #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) -@@ -144,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) +@@ -102,6 +104,8 @@ void nv04_dfp_disable(struct drm_device *dev, int head) + } + /* don't inadvertently turn it on when state written later */ + crtcstate[head].fp_control = FP_TG_CONTROL_OFF; ++ crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] &= ++ ~NV_CIO_CRE_LCD_ROUTE_MASK; + } + + void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) +@@ -144,6 +148,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) } } @@ -9717,7 +10030,7 @@ index 41634d4..e331b4f 100644 static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) -@@ -221,26 +253,21 @@ static void nv04_dfp_prepare(struct drm_encoder *encoder) +@@ -221,26 +255,21 @@ static void nv04_dfp_prepare(struct drm_encoder *encoder) nv04_dfp_prepare_sel_clk(dev, nv_encoder, head); @@ -9741,7 +10054,7 @@ index 41634d4..e331b4f 100644 - NV_CIO_CRE_LCD__INDEX, - *cr_lcd_oth); - } -+ *cr_lcd = 0x3; ++ *cr_lcd = (*cr_lcd & ~NV_CIO_CRE_LCD_ROUTE_MASK) | 0x3; + + if (nv_two_heads(dev)) { + if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP) @@ -9759,7 +10072,7 @@ index 41634d4..e331b4f 100644 } } } -@@ -412,10 +439,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -412,10 +441,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct dcb_entry *dcbe = nv_encoder->dcb; int head = nouveau_crtc(encoder->crtc)->index; @@ -9771,7 +10084,7 @@ index 41634d4..e331b4f 100644 if (dcbe->type == OUTPUT_TMDS) run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); -@@ -433,6 +457,12 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -433,6 +459,12 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) else NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); @@ -9784,7 +10097,7 @@ index 41634d4..e331b4f 100644 helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", -@@ -440,6 +470,27 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) +@@ -440,6 +472,27 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } @@ -9812,7 +10125,7 @@ index 41634d4..e331b4f 100644 static inline bool is_powersaving_dpms(int mode) { return (mode != DRM_MODE_DPMS_ON); -@@ -487,6 +538,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) +@@ -487,6 +540,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) LVDS_PANEL_OFF, 0); } @@ -9820,7 +10133,7 @@ index 41634d4..e331b4f 100644 nv04_dfp_update_fp_control(encoder, mode); if (mode == DRM_MODE_DPMS_ON) -@@ -510,6 +562,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) +@@ -510,6 +564,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n", mode, nv_encoder->dcb->index); @@ -9828,7 +10141,7 @@ index 41634d4..e331b4f 100644 nv04_dfp_update_fp_control(encoder, mode); } -@@ -554,10 +607,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) +@@ -554,10 +609,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) NV_DEBUG_KMS(encoder->dev, "\n"); @@ -9871,7 +10184,7 @@ index 41634d4..e331b4f 100644 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { .dpms = nv04_lvds_dpms, .save = nv04_dfp_save, -@@ -584,11 +669,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { +@@ -584,11 +671,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { .destroy = nv04_dfp_destroy, }; @@ -9886,7 +10199,7 @@ index 41634d4..e331b4f 100644 int type; switch (entry->type) { -@@ -613,11 +699,16 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -613,11 +701,16 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; @@ -10592,7 +10905,7 @@ index 617ed1e..2af43a1 100644 } diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c -index c4e3404..0b5d012 100644 +index c4e3404..9915a3b 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -34,69 +34,26 @@ @@ -10682,7 +10995,22 @@ index c4e3404..0b5d012 100644 } static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) -@@ -195,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder, +@@ -142,12 +99,10 @@ static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) + + state->tv_setup = 0; + +- if (bind) { +- state->CRTC[NV_CIO_CRE_LCD__INDEX] = 0; ++ if (bind) + state->CRTC[NV_CIO_CRE_49] |= 0x10; +- } else { ++ else + state->CRTC[NV_CIO_CRE_49] &= ~0x10; +- } + + NVWriteVgaCrtc(dev, head, NV_CIO_CRE_LCD__INDEX, + state->CRTC[NV_CIO_CRE_LCD__INDEX]); +@@ -195,7 +150,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder, regp->tv_vskew = 1; regp->tv_vsync_delay = 1; @@ -10691,7 +11019,7 @@ index c4e3404..0b5d012 100644 } static void nv04_tv_commit(struct drm_encoder *encoder) -@@ -214,30 +171,31 @@ static void nv04_tv_commit(struct drm_encoder *encoder) +@@ -214,30 +169,31 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { @@ -10737,7 +11065,7 @@ index c4e3404..0b5d012 100644 if (type < 0) return type; -@@ -246,40 +204,31 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -246,40 +202,31 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) if (!nv_encoder) return -ENOMEM; @@ -10789,7 +11117,7 @@ index c4e3404..0b5d012 100644 *hfuncs = (struct drm_encoder_helper_funcs) { .dpms = nv04_tv_dpms, -@@ -292,14 +241,16 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -292,14 +239,16 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) .detect = sfuncs->detect, }; @@ -11017,7 +11345,7 @@ index 0000000..007fc29 + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c -index fcf2cdd..b2f6a57 100644 +index fcf2cdd..8e68c97 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -43,51 +43,51 @@ struct pipe_state { @@ -11205,6 +11533,15 @@ index fcf2cdd..b2f6a57 100644 nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER); +@@ -729,7 +803,7 @@ nv10_graph_context_switch(struct drm_device *dev) + /* Load context for next channel */ + chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + chan = dev_priv->fifos[chid]; +- if (chan) ++ if (chan && chan->pgraph_ctx) + nv10_graph_load_context(chan); + + pgraph->fifo_access(dev, true); @@ -856,11 +930,12 @@ int nv10_graph_init(struct drm_device *dev) for (i = 0; i < NV10_PFB_TILE__SIZE; i++) nv10_graph_set_region_tiling(dev, i, 0, 0, 0); @@ -11322,7 +11659,7 @@ index 2e58c33..0000000 - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c -index 74c8803..a3b8861 100644 +index 74c8803..28119fd 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) @@ -11598,7 +11935,7 @@ index 74c8803..a3b8861 100644 nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } -@@ -373,15 +423,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) +@@ -373,15 +423,8 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) } @@ -11612,13 +11949,11 @@ index 74c8803..a3b8861 100644 - *cr_lcd = 0; - } + if (tv_norm->kind == CTV_ENC_MODE) -+ *cr_lcd = 0x1 | (head ? 0x0 : 0x8); -+ else -+ *cr_lcd = 0; ++ *cr_lcd |= 0x1 | (head ? 0x0 : 0x8); /* Set the DACCLK register */ dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1; -@@ -744,8 +789,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { +@@ -744,8 +787,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { .destroy = nv17_tv_destroy, }; @@ -11630,7 +11965,7 @@ index 74c8803..a3b8861 100644 struct drm_encoder *encoder; struct nv17_tv_encoder *tv_enc = NULL; -@@ -774,5 +821,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) +@@ -774,5 +819,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -20040,7 +20375,7 @@ index 0000000..152d8e8 +{ +} diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h -index 5998c35..ad64673 100644 +index 5998c35..881f8a5 100644 --- a/drivers/gpu/drm/nouveau/nvreg.h +++ b/drivers/gpu/drm/nouveau/nvreg.h @@ -147,28 +147,6 @@ @@ -20072,6 +20407,14 @@ index 5998c35..ad64673 100644 #define NV_PCRTC_INTR_0 0x00600100 # define NV_PCRTC_INTR_0_VBLANK (1 << 0) #define NV_PCRTC_INTR_EN_0 0x00600140 +@@ -285,6 +263,7 @@ + # define NV_CIO_CRE_HCUR_ADDR1_ADR 7:2 + # define NV_CIO_CRE_LCD__INDEX 0x33 + # define NV_CIO_CRE_LCD_LCD_SELECT 0:0 ++# define NV_CIO_CRE_LCD_ROUTE_MASK 0x3b + # define NV_CIO_CRE_DDC0_STATUS__INDEX 0x36 + # define NV_CIO_CRE_DDC0_WR__INDEX 0x37 + # define NV_CIO_CRE_ILACE__INDEX 0x39 /* interlace */ -- -1.7.2.2 +1.7.3 diff --git a/kernel.spec b/kernel.spec index c95299da4..643bc22f8 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 36 +%global baserelease 37 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -666,7 +666,6 @@ Patch1807: drm-i2c-ch7006-fix.patch Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch Patch1812: drm-nouveau-nva3-noaccel.patch -Patch1813: drm-nouveau-ibdma-race.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch @@ -1303,7 +1302,6 @@ ApplyPatch drm-i2c-ch7006-fix.patch ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-nouveau-nva3-noaccel.patch -ApplyPatch drm-nouveau-ibdma-race.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch @@ -1975,6 +1973,10 @@ fi # and build. %changelog +* Fri Oct 01 2010 Ben Skeggs 2.6.35.6-37 +- nouveau: DP fixes, nv50+ corruption fix, display fixes +- drm-nouveau-ibdma-race.patch: removed, in updates now + * Thu Sep 30 2010 Dave Jones - silence another rcu_reference warning From bc9e072d9b1b7f51a750037460df24486408f777 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 3 Oct 2010 17:32:27 -0400 Subject: [PATCH 086/277] efifb updates from upstream --- efifb-add-more-models.patch | 83 +++++++++-- ...ase-addr-is-plausible-on-pci-systems.patch | 135 ++++++++++++++++++ kernel.spec | 8 +- 3 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 efifb-check-that-the-base-addr-is-plausible-on-pci-systems.patch diff --git a/efifb-add-more-models.patch b/efifb-add-more-models.patch index 3351970d7..81c4ecf6a 100644 --- a/efifb-add-more-models.patch +++ b/efifb-add-more-models.patch @@ -1,18 +1,46 @@ ---- vanilla-2.6.35.3.orig/drivers/video/efifb.c -+++ vanilla-2.6.35.3/drivers/video/efifb.c -@@ -39,7 +39,11 @@ enum { +commit a5757c2a474a15f87e5baa9a4caacc31cde2bae6 +Author: Luke Macken +Date: Wed Sep 22 13:05:04 2010 -0700 + + efifb: support the EFI framebuffer on more Apple hardware + + Enable the EFI framebuffer on 14 more Macs, including the iMac11,1 + iMac10,1 iMac8,1 Macmini3,1 Macmini4,1 MacBook5,1 MacBook6,1 MacBook7,1 + MacBookPro2,2 MacBookPro5,2 MacBookPro5,3 MacBookPro6,1 MacBookPro6,2 and + MacBookPro7,1 + + Information gathered from various user submissions. + + https://bugzilla.redhat.com/show_bug.cgi?id=528232 + http://ubuntuforums.org/showthread.php?t=1557326 + + [akpm@linux-foundation.org: coding-style fixes] + Signed-off-by: Luke Macken + Signed-off-by: Peter Jones + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c +index c082b61..70477c2 100644 +--- a/drivers/video/efifb.c ++++ b/drivers/video/efifb.c +@@ -39,17 +39,31 @@ enum { M_I20, /* 20-Inch iMac */ M_I20_SR, /* 20-Inch iMac (Santa Rosa) */ M_I24, /* 24-Inch iMac */ + M_I24_8_1, /* 24-Inch iMac, 8,1th gen */ + M_I24_10_1, /* 24-Inch iMac, 10,1th gen */ ++ M_I27_11_1, /* 27-Inch iMac, 11,1th gen */ M_MINI, /* Mac Mini */ + M_MINI_3_1, /* Mac Mini, 3,1th gen */ + M_MINI_4_1, /* Mac Mini, 4,1th gen */ M_MB, /* MacBook */ M_MB_2, /* MacBook, 2nd rev. */ M_MB_3, /* MacBook, 3rd rev. */ -@@ -47,6 +51,7 @@ enum { ++ M_MB_5_1, /* MacBook, 5th rev. */ ++ M_MB_6_1, /* MacBook, 6th rev. */ ++ M_MB_7_1, /* MacBook, 7th rev. */ + M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */ M_MBA, /* MacBook Air */ M_MBP, /* MacBook Pro */ M_MBP_2, /* MacBook Pro 2nd gen */ @@ -20,16 +48,28 @@ M_MBP_SR, /* MacBook Pro (Santa Rosa) */ M_MBP_4, /* MacBook Pro, 4th gen */ M_MBP_5_1, /* MacBook Pro, 5,1th gen */ -@@ -64,11 +69,16 @@ static struct efifb_dmi_info { ++ M_MBP_5_2, /* MacBook Pro, 5,2th gen */ ++ M_MBP_5_3, /* MacBook Pro, 5,3rd gen */ ++ M_MBP_6_1, /* MacBook Pro, 6,1th gen */ ++ M_MBP_6_2, /* MacBook Pro, 6,2th gen */ ++ M_MBP_7_1, /* MacBook Pro, 7,1th gen */ + M_UNKNOWN /* placeholder */ + }; + +@@ -64,14 +78,28 @@ static struct efifb_dmi_info { [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ + [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 }, + [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 }, ++ [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 }, [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, -+ [M_MINI_3_1]= { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, -+ [M_MINI_4_1]= { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, ++ [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, ++ [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, ++ [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 }, ++ [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 }, ++ [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 }, [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ @@ -37,19 +77,34 @@ [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, -@@ -92,7 +102,11 @@ static struct dmi_system_id __initdata d ++ [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 }, ++ [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 }, ++ [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 }, ++ [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 }, ++ [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 }, + [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } + }; + +@@ -92,7 +120,12 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB), /* At least one of these two will be right; maybe both? */ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB), -@@ -104,6 +118,7 @@ static struct dmi_system_id __initdata d +@@ -101,14 +134,23 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), @@ -57,3 +112,13 @@ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2), ++ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1), + {}, + }; + diff --git a/efifb-check-that-the-base-addr-is-plausible-on-pci-systems.patch b/efifb-check-that-the-base-addr-is-plausible-on-pci-systems.patch new file mode 100644 index 000000000..a96fd9805 --- /dev/null +++ b/efifb-check-that-the-base-addr-is-plausible-on-pci-systems.patch @@ -0,0 +1,135 @@ +commit 85a00d9bbfb4704fbf368944b1cb9fed8f1598c5 +Author: Peter Jones +Date: Wed Sep 22 13:05:04 2010 -0700 + + efifb: check that the base address is plausible on pci systems + + Some Apple machines have identical DMI data but different memory + configurations for the video. Given that, check that the address in our + table is actually within the range of a PCI BAR on a VGA device in the + machine. + + This also fixes up the return value from set_system(), which has always + been wrong, but never resulted in bad behavior since there's only ever + been one matching entry in the dmi table. + + The patch + + 1) stops people's machines from crashing when we get their display wrong, + which seems to be unfortunately inevitable, + + 2) allows us to support identical dmi data with differing video memory + configurations + + This also adds me as the efifb maintainer, since I've effectively been + acting as such for quite some time. + + Signed-off-by: Peter Jones + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +diff --git a/MAINTAINERS b/MAINTAINERS +index 726433a..4d4881d 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2199,6 +2199,12 @@ W: http://acpi4asus.sf.net + S: Maintained + F: drivers/platform/x86/eeepc-laptop.c + ++EFIFB FRAMEBUFFER DRIVER ++L: linux-fbdev@vger.kernel.org ++M: Peter Jones ++S: Maintained ++F: drivers/video/efifb.c ++ + EFS FILESYSTEM + W: http://aeschi.ch.eu.org/efs/ + S: Orphan +diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c +index 815f84b..c082b61 100644 +--- a/drivers/video/efifb.c ++++ b/drivers/video/efifb.c +@@ -13,7 +13,7 @@ + #include + #include + #include +- ++#include + #include