diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
similarity index 88%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
rename to drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
index e6b228844a32c0e742806d95b06656bd9dc72536..da18885c559c5453b263a277b52d190e3b646fcf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
@@ -23,42 +23,7 @@
  * Authors: Ben Skeggs
  */
 
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
-	mov $r8 0x83c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
-	mov $r8 0x85c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
+#ifdef INCLUDE_CODE
 // queue_put - add request to queue
 //
 // In : $r13 queue pointer
@@ -178,27 +143,41 @@ watchdog_clear:
 	iowr I[$r8 + 0x000] $r0
 	ret
 
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
+// wait_donez - wait on FUC_DONE bit to become clear
+//
+// In : $r10 bit to wait on
+//
+wait_donez:
+	trace_set(T_WAIT);
+	mov $r8 0x818
+	shl b32 $r8 6
+	iowr I[$r8 + 0x000] $r10
+	wait_donez_ne:
+		mov $r8 0x400
+		shl b32 $r8 6
+		iord $r8 I[$r8 + 0x000]
+		xbit $r8 $r8 $r10
+		bra ne #wait_donez_ne
+	trace_clr(T_WAIT)
+	ret
+
+// wait_doneo - wait on FUC_DONE bit to become set
 //
 // In : $r10 bit to wait on
 //
-define(`wait_done', `
-$1:
+wait_doneo:
 	trace_set(T_WAIT);
 	mov $r8 0x818
 	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r10	// CC_SCRATCH[6] = wait bit
-	wait_done_$1:
+	iowr I[$r8 + 0x000] $r10
+	wait_doneo_e:
 		mov $r8 0x400
 		shl b32 $r8 6
-		iord $r8 I[$r8 + 0x000]	// DONE
+		iord $r8 I[$r8 + 0x000]
 		xbit $r8 $r8 $r10
-		bra $2 #wait_done_$1
+		bra e #wait_doneo_e
 	trace_clr(T_WAIT)
 	ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
 
 // mmctx_size - determine size of a mmio list transfer
 //
@@ -397,4 +376,4 @@ strand_ctx_init:
 	sub b32 $r15 $r14 $r15
 	trace_clr(T_STRINIT)
 	ret
-')
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
new file mode 100644
index 0000000000000000000000000000000000000000..4770e8c994320abaa0f3d523c24454b5d9c85aaa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
@@ -0,0 +1,369 @@
+/* fuc microcode for nvc0 PGRAPH/GPC
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* TODO
+ * - bracket certain functions with scratch writes, useful for debugging
+ * - watchdog timer around ctx operations
+ */
+
+#ifdef INCLUDE_DATA
+gpc_id:			.b32 0
+gpc_mmio_list_head:	.b32 0
+gpc_mmio_list_tail:	.b32 0
+
+tpc_count:		.b32 0
+tpc_mask:		.b32 0
+tpc_mmio_list_head:	.b32 0
+tpc_mmio_list_tail:	.b32 0
+
+cmd_queue:		queue_init
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+	push $r14
+	mov $r14 -0x67ec 	// 0x9814
+	sethi $r14 0x400000
+	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
+	add b32 $r14 0x41c
+	mov $r15 1
+	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
+	pop $r14
+	ret
+
+// GPC fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
+//   CC_SCRATCH[1]: context base
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: GPC context size
+//
+init:
+	clear b32 $r0
+	mov $sp $r0
+
+	// enable fifo access
+	mov $r1 0x1200
+	mov $r2 2
+	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+	mov $r1 0x400
+	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
+
+	// enable fifo interrupt
+	mov $r2 4
+	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
+
+	// enable interrupts
+	bset $flags ie0
+
+	// figure out which GPC we are, and how many TPCs we have
+	mov $r1 0x608
+	shl b32 $r1 6
+	iord $r2 I[$r1 + 0x000]		// UNITS
+	mov $r3 1
+	and $r2 0x1f
+	shl b32 $r3 $r2
+	sub b32 $r3 1
+	st b32 D[$r0 + #tpc_count] $r2
+	st b32 D[$r0 + #tpc_mask] $r3
+	add b32 $r1 0x400
+	iord $r2 I[$r1 + 0x000]		// MYINDEX
+	st b32 D[$r0 + #gpc_id] $r2
+
+	// find context data for this chipset
+	mov $r2 0x800
+	shl b32 $r2 6
+	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
+	mov $r1 #chipsets - 12
+	init_find_chipset:
+		add b32 $r1 12
+		ld b32 $r3 D[$r1 + 0x00]
+		cmpu b32 $r3 $r2
+		bra e #init_context
+		cmpu b32 $r3 0
+		bra ne #init_find_chipset
+		// unknown chipset
+		ret
+
+	// initialise context base, and size tracking
+	init_context:
+	mov $r2 0x800
+	shl b32 $r2 6
+	iord $r2 I[$r2 + 0x100]	// CC_SCRATCH[1], initial base
+	clear b32 $r3		// track GPC context size here
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't currently ever change
+	mov $r4 0x700
+	shl b32 $r4 6
+	shr b32 $r5 $r2 8
+	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
+	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
+
+	// calculate GPC mmio context size, store the chipset-specific
+	// mmio list pointers somewhere we can get at them later without
+	// re-parsing the chipset list
+	clear b32 $r14
+	clear b32 $r15
+	ld b16 $r14 D[$r1 + 4]
+	ld b16 $r15 D[$r1 + 6]
+	st b16 D[$r0 + #gpc_mmio_list_head] $r14
+	st b16 D[$r0 + #gpc_mmio_list_tail] $r15
+	call #mmctx_size
+	add b32 $r2 $r15
+	add b32 $r3 $r15
+
+	// calculate per-TPC mmio context size, store the list pointers
+	ld b16 $r14 D[$r1 + 8]
+	ld b16 $r15 D[$r1 + 10]
+	st b16 D[$r0 + #tpc_mmio_list_head] $r14
+	st b16 D[$r0 + #tpc_mmio_list_tail] $r15
+	call #mmctx_size
+	ld b32 $r14 D[$r0 + #tpc_count]
+	mulu $r14 $r15
+	add b32 $r2 $r14
+	add b32 $r3 $r14
+
+	// round up base/size to 256 byte boundary (for strand SWBASE)
+	add b32 $r4 0x1300
+	shr b32 $r3 2
+	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
+	shr b32 $r2 8
+	shr b32 $r3 6
+	add b32 $r2 1
+	add b32 $r3 1
+	shl b32 $r2 8
+	shl b32 $r3 8
+
+	// calculate size of strand context data
+	mov b32 $r15 $r2
+	call #strand_ctx_init
+	add b32 $r3 $r15
+
+	// save context size, and tell HUB we're done
+	mov $r1 0x800
+	shl b32 $r1 6
+	iowr I[$r1 + 0x100] $r3		// CC_SCRATCH[1]  = context size
+	add b32 $r1 0x800
+	clear b32 $r2
+	bset $r2 31
+	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call #queue_get
+	bra $p1 #main
+
+	// 0x0000-0x0003 are all context transfers
+	cmpu b32 $r14 0x04
+	bra nc #main_not_ctx_xfer
+		// fetch $flags and mask off $p1/$p2
+		mov $r1 $flags
+		mov $r2 0x0006
+		not b32 $r2
+		and $r1 $r2
+		// set $p1/$p2 according to transfer type
+		shl b32 $r14 1
+		or $r1 $r14
+		mov $flags $r1
+		// transfer context data
+		call #ctx_xfer
+		bra #main
+
+	main_not_ctx_xfer:
+	shl b32 $r15 $r14 16
+	or $r15 E_BAD_COMMAND
+	call #error
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+
+	// incoming fifo command?
+	iord $r10 I[$r0 + 0x200]	// INTR
+	and $r11 $r10 0x00000004
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r11 0x1900
+		mov $r13 #cmd_queue
+		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
+		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
+		call #queue_put
+		add b32 $r11 0x400
+		mov $r14 1
+		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
+
+	// ack, and wake up main()
+	ih_no_fifo:
+	iowr I[$r0 + 0x100] $r10	// INTR_ACK
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+// Set this GPC's bit in HUB_BAR, used to signal completion of various
+// activities to the HUB fuc
+//
+hub_barrier_done:
+	mov $r15 1
+	ld b32 $r14 D[$r0 + #gpc_id]
+	shl b32 $r15 $r14
+	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
+	sethi $r14 0x400000
+	call #nv_wr32
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r14 0x614
+	shl b32 $r14 6
+	mov $r15 0x020
+	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
+	mov $r15 8
+	ctx_redswitch_delay:
+		sub b32 $r15 1
+		bra ne #ctx_redswitch_delay
+	mov $r15 0xa20
+	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
+	ret
+
+// Transfer GPC context data between GPU and storage area
+//
+// In: $r15 context base address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// set context base address
+	mov $r1 0xa04
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r15// MEM_BASE
+	bra not $p1 #ctx_xfer_not_load
+		call #ctx_redswitch
+	ctx_xfer_not_load:
+
+	// strands
+	mov $r1 0x4afc
+	sethi $r1 0x20000
+	mov $r2 0xc
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
+	call #strand_wait
+	mov $r2 0x47fc
+	sethi $r2 0x20000
+	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
+	xbit $r2 $flags $p1
+	add b32 $r2 3
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 2		// first
+	mov $r11 0x0000
+	sethi $r11 0x500000
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
+	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
+	mov $r14 0		// not multi
+	call #mmctx_xfer
+
+	// per-TPC mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 4		// last
+	mov $r11 0x4000
+	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
+	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
+	ld b32 $r15 D[$r0 + #tpc_mask]
+	mov $r14 0x800		// stride = 0x800
+	call #mmctx_xfer
+
+	// wait for strands to finish
+	call #strand_wait
+
+	// if load, or a save without a load following, do some
+	// unknown stuff that's done after finishing a block of
+	// strand commands
+	bra $p1 #ctx_xfer_post
+	bra not $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		mov $r1 0x4afc
+		sethi $r1 0x20000
+		mov $r2 0xd
+		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
+		call #strand_wait
+
+	// mark completion in HUB's barrier
+	ctx_xfer_done:
+	call #hub_barrier_done
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
index 61a6b43ece19e705dc132b0ed71fae37ed20e3f2..c2d9e59bb58f30053b612be05b8c8aa4692726b8 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 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"),
@@ -20,32 +19,17 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h
- */
-
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define NVGF
+#include "macros.fuc"
 
 .section #nvc0_grgpc_data
-include(`nvc0.fuc')
-gpc_id:			.b32 0
-gpc_mmio_list_head:	.b32 0
-gpc_mmio_list_tail:	.b32 0
-
-tpc_count:		.b32 0
-tpc_mask:		.b32 0
-tpc_mmio_list_head:	.b32 0
-tpc_mmio_list_tail:	.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
 
-cmd_queue:		queue_init
-
-// chipset descriptions
 chipsets:
 .b8  0xc0 0 0 0
 .b16 #nvc0_gpc_mmio_head
@@ -159,335 +143,12 @@ nvc1_tpc_mmio_tail:
 mmctx_data(0x000424, 2);
 mmctx_data(0x0006e0, 1);
 nvd9_tpc_mmio_tail:
+#undef INCLUDE_DATA
 
 .section #nvc0_grgpc_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
-	push $r14
-	mov $r14 -0x67ec 	// 0x9814
-	sethi $r14 0x400000
-	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
-	add b32 $r14 0x41c
-	mov $r15 1
-	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
-	pop $r14
-	ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//   CC_SCRATCH[1]: context base
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: GPC context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
-
-	// enable fifo interrupt
-	mov $r2 4
-	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
-
-	// enable interrupts
-	bset $flags ie0
-
-	// figure out which GPC we are, and how many TPCs we have
-	mov $r1 0x608
-	shl b32 $r1 6
-	iord $r2 I[$r1 + 0x000]		// UNITS
-	mov $r3 1
-	and $r2 0x1f
-	shl b32 $r3 $r2
-	sub b32 $r3 1
-	st b32 D[$r0 + #tpc_count] $r2
-	st b32 D[$r0 + #tpc_mask] $r3
-	add b32 $r1 0x400
-	iord $r2 I[$r1 + 0x000]		// MYINDEX
-	st b32 D[$r0 + #gpc_id] $r2
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r1 #chipsets - 12
-	init_find_chipset:
-		add b32 $r1 12
-		ld b32 $r3 D[$r1 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// initialise context base, and size tracking
-	init_context:
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x100]	// CC_SCRATCH[1], initial base
-	clear b32 $r3		// track GPC context size here
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't currently ever change
-	mov $r4 0x700
-	shl b32 $r4 6
-	shr b32 $r5 $r2 8
-	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
-	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
-
-	// calculate GPC mmio context size, store the chipset-specific
-	// mmio list pointers somewhere we can get at them later without
-	// re-parsing the chipset list
-	clear b32 $r14
-	clear b32 $r15
-	ld b16 $r14 D[$r1 + 4]
-	ld b16 $r15 D[$r1 + 6]
-	st b16 D[$r0 + #gpc_mmio_list_head] $r14
-	st b16 D[$r0 + #gpc_mmio_list_tail] $r15
-	call #mmctx_size
-	add b32 $r2 $r15
-	add b32 $r3 $r15
-
-	// calculate per-TPC mmio context size, store the list pointers
-	ld b16 $r14 D[$r1 + 8]
-	ld b16 $r15 D[$r1 + 10]
-	st b16 D[$r0 + #tpc_mmio_list_head] $r14
-	st b16 D[$r0 + #tpc_mmio_list_tail] $r15
-	call #mmctx_size
-	ld b32 $r14 D[$r0 + #tpc_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-
-	// round up base/size to 256 byte boundary (for strand SWBASE)
-	add b32 $r4 0x1300
-	shr b32 $r3 2
-	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
-	shr b32 $r2 8
-	shr b32 $r3 6
-	add b32 $r2 1
-	add b32 $r3 1
-	shl b32 $r2 8
-	shl b32 $r3 8
-
-	// calculate size of strand context data
-	mov b32 $r15 $r2
-	call #strand_ctx_init
-	add b32 $r3 $r15
-
-	// save context size, and tell HUB we're done
-	mov $r1 0x800
-	shl b32 $r1 6
-	iowr I[$r1 + 0x100] $r3		// CC_SCRATCH[1]  = context size
-	add b32 $r1 0x800
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// 0x0000-0x0003 are all context transfers
-	cmpu b32 $r14 0x04
-	bra nc #main_not_ctx_xfer
-		// fetch $flags and mask off $p1/$p2
-		mov $r1 $flags
-		mov $r2 0x0006
-		not b32 $r2
-		and $r1 $r2
-		// set $p1/$p2 according to transfer type
-		shl b32 $r14 1
-		or $r1 $r14
-		mov $flags $r1
-		// transfer context data
-		call #ctx_xfer
-		bra #main
-
-	main_not_ctx_xfer:
-	shl b32 $r15 $r14 16
-	or $r15 E_BAD_COMMAND
-	call #error
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// ack, and wake up main()
-	ih_no_fifo:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
-	mov $r15 1
-	ld b32 $r14 D[$r0 + #gpc_id]
-	shl b32 $r15 $r14
-	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
-	sethi $r14 0x400000
-	call #nv_wr32
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x020
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0xa20
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
-	ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// set context base address
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r15// MEM_BASE
-	bra not $p1 #ctx_xfer_not_load
-		call #ctx_redswitch
-	ctx_xfer_not_load:
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 2		// first
-	mov $r11 0x0000
-	sethi $r11 0x500000
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
-	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// per-TPC mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 4		// last
-	mov $r11 0x4000
-	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
-	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #tpc_mask]
-	mov $r14 0x800		// stride = 0x800
-	call #mmctx_xfer
-
-	// wait for strands to finish
-	call #strand_wait
-
-	// if load, or a save without a load following, do some
-	// unknown stuff that's done after finishing a block of
-	// strand commands
-	bra $p1 #ctx_xfer_post
-	bra not $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r1 0x4afc
-		sethi $r1 0x20000
-		mov $r2 0xd
-		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
-		call #strand_wait
-
-	// mark completion in HUB's barrier
-	ctx_xfer_done:
-	call #hub_barrier_done
-	ret
-
+#include "com.fuc"
+#include "gpc.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
index cafcc638042adbb5f2c957838e6c03d5294b1851..66ec1acaadee59d5d74a65791b7658b46fd9143f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
@@ -192,7 +192,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x0089d000,
 	0x081887f1,
 	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
+/* 0x00e2: wait_donez_ne */
 	0x87f1008a,
 	0x84b60400,
 	0x0088cf06,
@@ -209,7 +209,7 @@ uint32_t nvc0_grgpc_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x011c: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
index ccaeb50aa76b19ecf80b083f2deb0cae68315318..2fc585eeff950c24f01d9a79295701d1aa497a96 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 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"),
@@ -20,32 +19,17 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 nve0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grgpc.fuc.h
- */
-
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define NVGK
+#include "macros.fuc"
 
 .section #nve0_grgpc_data
-include(`nve0.fuc')
-gpc_id:			.b32 0
-gpc_mmio_list_head:	.b32 0
-gpc_mmio_list_tail:	.b32 0
-
-tpc_count:		.b32 0
-tpc_mask:		.b32 0
-tpc_mmio_list_head:	.b32 0
-tpc_mmio_list_tail:	.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
 
-cmd_queue:		queue_init
-
-// chipset descriptions
 chipsets:
 .b8  0xe4 0 0 0
 .b16 #nve4_gpc_mmio_head
@@ -182,335 +166,12 @@ mmctx_data(0x000758, 1)
 mmctx_data(0x000770, 1)
 mmctx_data(0x000778, 2)
 nvf0_tpc_mmio_tail:
+#undef INCLUDE_DATA
 
 .section #nve0_grgpc_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
-	push $r14
-	mov $r14 -0x67ec 	// 0x9814
-	sethi $r14 0x400000
-	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
-	add b32 $r14 0x41c
-	mov $r15 1
-	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
-	pop $r14
-	ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//   CC_SCRATCH[1]: context base
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: GPC context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
-
-	// enable fifo interrupt
-	mov $r2 4
-	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
-
-	// enable interrupts
-	bset $flags ie0
-
-	// figure out which GPC we are, and how many TPCs we have
-	mov $r1 0x608
-	shl b32 $r1 6
-	iord $r2 I[$r1 + 0x000]		// UNITS
-	mov $r3 1
-	and $r2 0x1f
-	shl b32 $r3 $r2
-	sub b32 $r3 1
-	st b32 D[$r0 + #tpc_count] $r2
-	st b32 D[$r0 + #tpc_mask] $r3
-	add b32 $r1 0x400
-	iord $r2 I[$r1 + 0x000]		// MYINDEX
-	st b32 D[$r0 + #gpc_id] $r2
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r1 #chipsets - 12
-	init_find_chipset:
-		add b32 $r1 12
-		ld b32 $r3 D[$r1 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// initialise context base, and size tracking
-	init_context:
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x100]	// CC_SCRATCH[1], initial base
-	clear b32 $r3		// track GPC context size here
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't currently ever change
-	mov $r4 0x700
-	shl b32 $r4 6
-	shr b32 $r5 $r2 8
-	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
-	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
-
-	// calculate GPC mmio context size, store the chipset-specific
-	// mmio list pointers somewhere we can get at them later without
-	// re-parsing the chipset list
-	clear b32 $r14
-	clear b32 $r15
-	ld b16 $r14 D[$r1 + 4]
-	ld b16 $r15 D[$r1 + 6]
-	st b16 D[$r0 + #gpc_mmio_list_head] $r14
-	st b16 D[$r0 + #gpc_mmio_list_tail] $r15
-	call #mmctx_size
-	add b32 $r2 $r15
-	add b32 $r3 $r15
-
-	// calculate per-TPC mmio context size, store the list pointers
-	ld b16 $r14 D[$r1 + 8]
-	ld b16 $r15 D[$r1 + 10]
-	st b16 D[$r0 + #tpc_mmio_list_head] $r14
-	st b16 D[$r0 + #tpc_mmio_list_tail] $r15
-	call #mmctx_size
-	ld b32 $r14 D[$r0 + #tpc_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-
-	// round up base/size to 256 byte boundary (for strand SWBASE)
-	add b32 $r4 0x1300
-	shr b32 $r3 2
-	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
-	shr b32 $r2 8
-	shr b32 $r3 6
-	add b32 $r2 1
-	add b32 $r3 1
-	shl b32 $r2 8
-	shl b32 $r3 8
-
-	// calculate size of strand context data
-	mov b32 $r15 $r2
-	call #strand_ctx_init
-	add b32 $r3 $r15
-
-	// save context size, and tell HUB we're done
-	mov $r1 0x800
-	shl b32 $r1 6
-	iowr I[$r1 + 0x100] $r3		// CC_SCRATCH[1]  = context size
-	add b32 $r1 0x800
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// 0x0000-0x0003 are all context transfers
-	cmpu b32 $r14 0x04
-	bra nc #main_not_ctx_xfer
-		// fetch $flags and mask off $p1/$p2
-		mov $r1 $flags
-		mov $r2 0x0006
-		not b32 $r2
-		and $r1 $r2
-		// set $p1/$p2 according to transfer type
-		shl b32 $r14 1
-		or $r1 $r14
-		mov $flags $r1
-		// transfer context data
-		call #ctx_xfer
-		bra #main
-
-	main_not_ctx_xfer:
-	shl b32 $r15 $r14 16
-	or $r15 E_BAD_COMMAND
-	call #error
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// ack, and wake up main()
-	ih_no_fifo:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
-	mov $r15 1
-	ld b32 $r14 D[$r0 + #gpc_id]
-	shl b32 $r15 $r14
-	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
-	sethi $r14 0x400000
-	call #nv_wr32
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x020
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0xa20
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
-	ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// set context base address
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r15// MEM_BASE
-	bra not $p1 #ctx_xfer_not_load
-		call #ctx_redswitch
-	ctx_xfer_not_load:
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 2		// first
-	mov $r11 0x0000
-	sethi $r11 0x500000
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
-	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// per-TPC mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 4		// last
-	mov $r11 0x4000
-	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
-	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #tpc_mask]
-	mov $r14 0x800		// stride = 0x800
-	call #mmctx_xfer
-
-	// wait for strands to finish
-	call #strand_wait
-
-	// if load, or a save without a load following, do some
-	// unknown stuff that's done after finishing a block of
-	// strand commands
-	bra $p1 #ctx_xfer_post
-	bra not $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r1 0x4afc
-		sethi $r1 0x20000
-		mov $r2 0xd
-		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
-		call #strand_wait
-
-	// mark completion in HUB's barrier
-	ctx_xfer_done:
-	call #hub_barrier_done
-	ret
-
+#include "com.fuc"
+#include "gpc.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
index 419bd5da1e00cd837ad6d83e043e59ae19a01c21..504ae96cd3ddac06c803c04d48424dce12ab5012 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
@@ -223,7 +223,7 @@ uint32_t nve0_grgpc_code[] = {
 	0x0089d000,
 	0x081887f1,
 	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
+/* 0x00e2: wait_donez_ne */
 	0x87f1008a,
 	0x84b60400,
 	0x0088cf06,
@@ -240,7 +240,7 @@ uint32_t nve0_grgpc_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x011c: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
new file mode 100644
index 0000000000000000000000000000000000000000..5c68bf6d69aab39f9e29dd0154c60ac0567e3978
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
@@ -0,0 +1,755 @@
+/* fuc microcode for nvc0 PGRAPH/HUB
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_DATA
+gpc_count:		.b32 0
+rop_count:		.b32 0
+cmd_queue:		queue_init
+hub_mmio_list_head:	.b32 0
+hub_mmio_list_tail:	.b32 0
+
+ctx_current:		.b32 0
+
+.align 256
+chan_data:
+chan_mmio_count:	.b32 0
+chan_mmio_address:	.b32 0
+
+.align 256
+xfer_data: 		.skip 256
+
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+	push $r14
+	mov $r14 0x814
+	shl b32 $r14 6
+	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
+	mov $r14 0xc1c
+	shl b32 $r14 6
+	mov $r15 1
+	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
+	pop $r14
+	ret
+
+// HUB fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: total PGRAPH context size
+//
+init:
+	clear b32 $r0
+	mov $sp $r0
+	mov $xdbase $r0
+
+	// enable fifo access
+	mov $r1 0x1200
+	mov $r2 2
+	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+	mov $r1 0x400
+	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
+
+	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
+	mov $r3 0x404
+	shl b32 $r3 6
+	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
+	iowr I[$r3 + 0x000] $r2
+
+	// not sure what these are, route them because NVIDIA does, and
+	// the IRQ handler will signal the host if we ever get one.. we
+	// may find out if/why we need to handle these if so..
+	//
+	mov $r2 0x2004
+	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
+	mov $r2 0x200b
+	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
+	mov $r2 0x200c
+	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
+
+	// enable all INTR_UP interrupts
+	mov $r2 0xc24
+	shl b32 $r2 6
+	not b32 $r3 $r0
+	iowr I[$r2] $r3
+
+	// enable fifo, ctxsw, 9, 10, 15 interrupts
+	mov $r2 -0x78fc		// 0x8704
+	sethi $r2 0
+	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
+
+	// fifo level triggered, rest edge
+	sub b32 $r1 0x100
+	mov $r2 4
+	iowr I[$r1] $r2
+
+	// enable interrupts
+	bset $flags ie0
+
+	// fetch enabled GPC/ROP counts
+	mov $r14 -0x69fc	// 0x409604
+	sethi $r14 0x400000
+	call #nv_rd32
+	extr $r1 $r15 16:20
+	st b32 D[$r0 + #rop_count] $r1
+	and $r15 0x1f
+	st b32 D[$r0 + #gpc_count] $r15
+
+	// set BAR_REQMASK to GPC mask
+	mov $r1 1
+	shl b32 $r1 $r15
+	sub b32 $r1 1
+	mov $r2 0x40c
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r1
+	iowr I[$r2 + 0x100] $r1
+
+	// find context data for this chipset
+	mov $r2 0x800
+	shl b32 $r2 6
+	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
+	mov $r15 #chipsets - 8
+	init_find_chipset:
+		add b32 $r15 8
+		ld b32 $r3 D[$r15 + 0x00]
+		cmpu b32 $r3 $r2
+		bra e #init_context
+		cmpu b32 $r3 0
+		bra ne #init_find_chipset
+		// unknown chipset
+		ret
+
+	// context size calculation, reserve first 256 bytes for use by fuc
+	init_context:
+	mov $r1 256
+
+	// calculate size of mmio context data
+	ld b16 $r14 D[$r15 + 4]
+	ld b16 $r15 D[$r15 + 6]
+	sethi $r14 0
+	st b32 D[$r0 + #hub_mmio_list_head] $r14
+	st b32 D[$r0 + #hub_mmio_list_tail] $r15
+	call #mmctx_size
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't (currently) ever change
+	mov $r3 0x700
+	shl b32 $r3 6
+	shr b32 $r4 $r1 8
+	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
+	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
+	add b32 $r3 0x1300
+	add b32 $r1 $r15
+	shr b32 $r15 2
+	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
+
+	// strands, base offset needs to be aligned to 256 bytes
+	shr b32 $r1 8
+	add b32 $r1 1
+	shl b32 $r1 8
+	mov b32 $r15 $r1
+	call #strand_ctx_init
+	add b32 $r1 $r15
+
+	// initialise each GPC in sequence by passing in the offset of its
+	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
+	// has previously been uploaded by the host) running.
+	//
+	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
+	// when it has completed, and return the size of its context data
+	// in GPCn_CC_SCRATCH[1]
+	//
+	ld b32 $r3 D[$r0 + #gpc_count]
+	mov $r4 0x2000
+	sethi $r4 0x500000
+	init_gpc:
+		// setup, and start GPC ucode running
+		add b32 $r14 $r4 0x804
+		mov b32 $r15 $r1
+		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
+		add b32 $r14 $r4 0x800
+		mov b32 $r15 $r2
+		call #nv_wr32			// CC_SCRATCH[0] = chipset
+		add b32 $r14 $r4 0x10c
+		clear b32 $r15
+		call #nv_wr32
+		add b32 $r14 $r4 0x104
+		call #nv_wr32			// ENTRY
+		add b32 $r14 $r4 0x100
+		mov $r15 2			// CTRL_START_TRIGGER
+		call #nv_wr32			// CTRL
+
+		// wait for it to complete, and adjust context size
+		add b32 $r14 $r4 0x800
+		init_gpc_wait:
+			call #nv_rd32
+			xbit $r15 $r15 31
+			bra e #init_gpc_wait
+		add b32 $r14 $r4 0x804
+		call #nv_rd32
+		add b32 $r1 $r15
+
+		// next!
+		add b32 $r4 0x8000
+		sub b32 $r3 1
+		bra ne #init_gpc
+
+	// save context size, and tell host we're ready
+	mov $r2 0x800
+	shl b32 $r2 6
+	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
+	add b32 $r2 0x800
+	clear b32 $r1
+	bset $r1 31
+	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	// sleep until we have something to do
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call #queue_get
+	bra $p1 #main
+
+	// context switch, requested by GPU?
+	cmpu b32 $r14 0x4001
+	bra ne #main_not_ctx_switch
+		trace_set(T_AUTO)
+		mov $r1 0xb00
+		shl b32 $r1 6
+		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
+		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
+
+		xbit $r3 $r1 31
+		bra e #chsw_no_prev
+			xbit $r3 $r2 31
+			bra e #chsw_prev_no_next
+				push $r2
+				mov b32 $r2 $r1
+				trace_set(T_SAVE)
+				bclr $flags $p1
+				bset $flags $p2
+				call #ctx_xfer
+				trace_clr(T_SAVE);
+				pop $r2
+				trace_set(T_LOAD);
+				bset $flags $p1
+				call #ctx_xfer
+				trace_clr(T_LOAD);
+				bra #chsw_done
+			chsw_prev_no_next:
+				push $r2
+				mov b32 $r2 $r1
+				bclr $flags $p1
+				bclr $flags $p2
+				call #ctx_xfer
+				pop $r2
+				mov $r1 0xb00
+				shl b32 $r1 6
+				iowr I[$r1] $r2
+				bra #chsw_done
+		chsw_no_prev:
+			xbit $r3 $r2 31
+			bra e #chsw_done
+				bset $flags $p1
+				bclr $flags $p2
+				call #ctx_xfer
+
+		// ack the context switch request
+		chsw_done:
+		mov $r1 0xb0c
+		shl b32 $r1 6
+		mov $r2 1
+		iowr I[$r1 + 0x000] $r2		// 0x409b0c
+		trace_clr(T_AUTO)
+		bra #main
+
+	// request to set current channel? (*not* a context switch)
+	main_not_ctx_switch:
+	cmpu b32 $r14 0x0001
+	bra ne #main_not_ctx_chan
+		mov b32 $r2 $r15
+		call #ctx_chan
+		bra #main_done
+
+	// request to store current channel context?
+	main_not_ctx_chan:
+	cmpu b32 $r14 0x0002
+	bra ne #main_not_ctx_save
+		trace_set(T_SAVE)
+		bclr $flags $p1
+		bclr $flags $p2
+		call #ctx_xfer
+		trace_clr(T_SAVE)
+		bra #main_done
+
+	main_not_ctx_save:
+		shl b32 $r15 $r14 16
+		or $r15 E_BAD_COMMAND
+		call #error
+		bra #main
+
+	main_done:
+	mov $r1 0x820
+	shl b32 $r1 6
+	clear b32 $r2
+	bset $r2 31
+	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+
+	// incoming fifo command?
+	iord $r10 I[$r0 + 0x200]	// INTR
+	and $r11 $r10 0x00000004
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r11 0x1900
+		mov $r13 #cmd_queue
+		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
+		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
+		call #queue_put
+		add b32 $r11 0x400
+		mov $r14 1
+		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
+
+	// context switch request?
+	ih_no_fifo:
+	and $r11 $r10 0x00000100
+	bra e #ih_no_ctxsw
+		// enqueue a context switch for later processing
+		mov $r13 #cmd_queue
+		mov $r14 0x4001
+		call #queue_put
+
+	// anything we didn't handle, bring it to the host's attention
+	ih_no_ctxsw:
+	mov $r11 0x104
+	not b32 $r11
+	and $r11 $r10 $r11
+	bra e #ih_no_other
+		mov $r10 0xc1c
+		shl b32 $r10 6
+		iowr I[$r10] $r11	// INTR_UP_SET
+
+	// ack, and wake up main()
+	ih_no_other:
+	iowr I[$r0 + 0x100] $r10	// INTR_ACK
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+#ifdef NVGF
+// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
+ctx_4160s:
+	mov $r14 0x4160
+	sethi $r14 0x400000
+	mov $r15 1
+	call #nv_wr32
+	ctx_4160s_wait:
+		call #nv_rd32
+		xbit $r15 $r15 4
+		bra e #ctx_4160s_wait
+	ret
+
+// Without clearing again at end of xfer, some things cause PGRAPH
+// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
+// still function with it set however...
+ctx_4160c:
+	mov $r14 0x4160
+	sethi $r14 0x400000
+	clear b32 $r15
+	call #nv_wr32
+	ret
+#endif
+
+// Again, not real sure
+//
+// In: $r15 value to set 0x404170 to
+//
+ctx_4170s:
+	mov $r14 0x4170
+	sethi $r14 0x400000
+	or $r15 0x10
+	call #nv_wr32
+	ret
+
+// Waits for a ctx_4170s() call to complete
+//
+ctx_4170w:
+	mov $r14 0x4170
+	sethi $r14 0x400000
+	call #nv_rd32
+	and $r15 0x10
+	bra ne #ctx_4170w
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r14 0x614
+	shl b32 $r14 6
+	mov $r15 0x270
+	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
+	mov $r15 8
+	ctx_redswitch_delay:
+		sub b32 $r15 1
+		bra ne #ctx_redswitch_delay
+	mov $r15 0x770
+	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
+	ret
+
+// Not a clue what this is for, except that unless the value is 0x10, the
+// strand context is saved (and presumably restored) incorrectly..
+//
+// In: $r15 value to set to (0x00/0x10 are used)
+//
+ctx_86c:
+	mov $r14 0x86c
+	shl b32 $r14 6
+	iowr I[$r14] $r15	// HUB(0x86c) = val
+	mov $r14 -0x75ec
+	sethi $r14 0x400000
+	call #nv_wr32		// ROP(0xa14) = val
+	mov $r14 -0x5794
+	sethi $r14 0x410000
+	call #nv_wr32		// GPC(0x86c) = val
+	ret
+
+// ctx_load - load's a channel's ctxctl data, and selects its vm
+//
+// In: $r2 channel address
+//
+ctx_load:
+	trace_set(T_CHAN)
+
+	// switch to channel, somewhat magic in parts..
+	mov $r10 12		// DONE_UNK12
+	call #wait_donez
+	mov $r1 0xa24
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r0	// 0x409a24
+	mov $r3 0xb00
+	shl b32 $r3 6
+	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
+	mov $r1 0xa0c
+	shl b32 $r1 6
+	mov $r4 7
+	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
+	iowr I[$r1 + 0x100] $r4	// MEM_CMD
+	ctx_chan_wait_0:
+		iord $r4 I[$r1 + 0x100]
+		and $r4 0x1f
+		bra ne #ctx_chan_wait_0
+	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
+
+	// load channel header, fetch PGRAPH context pointer
+	mov $xtargets $r0
+	bclr $r2 31
+	shl b32 $r2 4
+	add b32 $r2 2
+
+	trace_set(T_LCHAN)
+	mov $r1 0xa04
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r2		// MEM_BASE
+	mov $r1 0xa20
+	shl b32 $r1 6
+	mov $r2 0x0002
+	sethi $r2 0x80000000
+	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
+	mov $r1 0x10			// chan + 0x0210
+	mov $r2 #xfer_data
+	sethi $r2 0x00020000		// 16 bytes
+	xdld $r1 $r2
+	xdwait
+	trace_clr(T_LCHAN)
+
+	// update current context
+	ld b32 $r1 D[$r0 + #xfer_data + 4]
+	shl b32 $r1 24
+	ld b32 $r2 D[$r0 + #xfer_data + 0]
+	shr b32 $r2 8
+	or $r1 $r2
+	st b32 D[$r0 + #ctx_current] $r1
+
+	// set transfer base to start of context, and fetch context header
+	trace_set(T_LCTXH)
+	mov $r2 0xa04
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r1		// MEM_BASE
+	mov $r2 1
+	mov $r1 0xa20
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdld $r0 $r1
+	xdwait
+	trace_clr(T_LCTXH)
+
+	trace_clr(T_CHAN)
+	ret
+
+// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
+//            the active channel for ctxctl, but not actually transfer
+//            any context data.  intended for use only during initial
+//            context construction.
+//
+// In: $r2 channel address
+//
+ctx_chan:
+#ifdef NVGF
+	call #ctx_4160s
+#endif
+	call #ctx_load
+	mov $r10 12			// DONE_UNK12
+	call #wait_donez
+	mov $r1 0xa10
+	shl b32 $r1 6
+	mov $r2 5
+	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
+	ctx_chan_wait:
+		iord $r2 I[$r1 + 0x000]
+		or $r2 $r2
+		bra ne #ctx_chan_wait
+#ifdef NVGF
+	call #ctx_4160c
+#endif
+	ret
+
+// Execute per-context state overrides list
+//
+// Only executed on the first load of a channel.  Might want to look into
+// removing this and having the host directly modify the channel's context
+// to change this state...  The nouveau DRM already builds this list as
+// it's definitely needed for NVIDIA's, so we may as well use it for now
+//
+// Input: $r1 mmio list length
+//
+ctx_mmio_exec:
+	// set transfer base to be the mmio list
+	ld b32 $r3 D[$r0 + #chan_mmio_address]
+	mov $r2 0xa04
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r3		// MEM_BASE
+
+	clear b32 $r3
+	ctx_mmio_loop:
+		// fetch next 256 bytes of mmio list if necessary
+		and $r4 $r3 0xff
+		bra ne #ctx_mmio_pull
+			mov $r5 #xfer_data
+			sethi $r5 0x00060000	// 256 bytes
+			xdld $r3 $r5
+			xdwait
+
+		// execute a single list entry
+		ctx_mmio_pull:
+		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
+		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
+		call #nv_wr32
+
+		// next!
+		add b32 $r3 8
+		sub b32 $r1 1
+		bra ne #ctx_mmio_loop
+
+	// set transfer base back to the current context
+	ctx_mmio_done:
+	ld b32 $r3 D[$r0 + #ctx_current]
+	iowr I[$r2 + 0x000] $r3		// MEM_BASE
+
+	// disable the mmio list now, we don't need/want to execute it again
+	st b32 D[$r0 + #chan_mmio_count] $r0
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdst $r0 $r1
+	xdwait
+	ret
+
+// Transfer HUB context data between GPU and storage area
+//
+// In: $r2 channel address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// according to mwk, some kind of wait for idle
+	mov $r15 0xc00
+	shl b32 $r15 6
+	mov $r14 4
+	iowr I[$r15 + 0x200] $r14
+	ctx_xfer_idle:
+		iord $r14 I[$r15 + 0x000]
+		and $r14 0x2000
+		bra ne #ctx_xfer_idle
+
+	bra not $p1 #ctx_xfer_pre
+	bra $p2 #ctx_xfer_pre_load
+	ctx_xfer_pre:
+		mov $r15 0x10
+		call #ctx_86c
+#ifdef NVGF
+		call #ctx_4160s
+#endif
+		bra not $p1 #ctx_xfer_exec
+
+	ctx_xfer_pre_load:
+		mov $r15 2
+		call #ctx_4170s
+		call #ctx_4170w
+		call #ctx_redswitch
+		clear b32 $r15
+		call #ctx_4170s
+		call #ctx_load
+
+	// fetch context pointer, and initiate xfer on all GPCs
+	ctx_xfer_exec:
+	ld b32 $r1 D[$r0 + #ctx_current]
+	mov $r2 0x414
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
+	mov $r14 -0x5b00
+	sethi $r14 0x410000
+	mov b32 $r15 $r1
+	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
+	add b32 $r14 4
+	xbit $r15 $flags $p1
+	xbit $r2 $flags $p2
+	shl b32 $r2 1
+	or $r15 $r2
+	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+
+	// strands
+	mov $r1 0x4afc
+	sethi $r1 0x20000
+	mov $r2 0xc
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
+	call #strand_wait
+	mov $r2 0x47fc
+	sethi $r2 0x20000
+	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
+	xbit $r2 $flags $p1
+	add b32 $r2 3
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 6		// first, last
+	mov $r11 0		// base = 0
+	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
+	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
+	mov $r14 0		// not multi
+	call #mmctx_xfer
+
+	// wait for GPCs to all complete
+	mov $r10 8		// DONE_BAR
+	call #wait_doneo
+
+	// wait for strand xfer to complete
+	call #strand_wait
+
+	// post-op
+	bra $p1 #ctx_xfer_post
+		mov $r10 12		// DONE_UNK12
+		call #wait_donez
+		mov $r1 0xa10
+		shl b32 $r1 6
+		mov $r2 5
+		iowr I[$r1] $r2		// MEM_CMD
+		ctx_xfer_post_save_wait:
+			iord $r2 I[$r1]
+			or $r2 $r2
+			bra ne #ctx_xfer_post_save_wait
+
+	bra $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		mov $r15 2
+		call #ctx_4170s
+		clear b32 $r15
+		call #ctx_86c
+		call #strand_post
+		call #ctx_4170w
+		clear b32 $r15
+		call #ctx_4170s
+
+		bra not $p1 #ctx_xfer_no_post_mmio
+		ld b32 $r1 D[$r0 + #chan_mmio_count]
+		or $r1 $r1
+		bra e #ctx_xfer_no_post_mmio
+			call #ctx_mmio_exec
+
+		ctx_xfer_no_post_mmio:
+#ifdef NVGF
+		call #ctx_4160c
+#endif
+
+	ctx_xfer_done:
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
index 9f174be6bc826033b3547c7c929d85a774edd765..f144f665b80733c5b329df0e1964ed5ef283a91c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 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"),
@@ -20,32 +19,17 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h
- */
+#define NVGF
+#include "macros.fuc"
 
 .section #nvc0_grhub_data
-include(`nvc0.fuc')
-gpc_count:		.b32 0
-rop_count:		.b32 0
-cmd_queue:		queue_init
-hub_mmio_list_head:	.b32 0
-hub_mmio_list_tail:	.b32 0
-
-ctx_current:		.b32 0
-
-.align 256
-chan_data:
-chan_mmio_count:	.b32 0
-chan_mmio_address:	.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
 
-.align 256
-xfer_data: 		.b32 0
-
-.align 256
 chipsets:
 .b8  0xc0 0 0 0
 .b16 #nvc0_hub_mmio_head
@@ -124,710 +108,12 @@ mmctx_data(0x4064c0, 2)
 nvc1_hub_mmio_tail:
 mmctx_data(0x4064bc, 3)
 nvd9_hub_mmio_tail:
+#undef INCLUDE_DATA
 
 .section #nvc0_grhub_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
-	push $r14
-	mov $r14 0x814
-	shl b32 $r14 6
-	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
-	mov $r14 0xc1c
-	shl b32 $r14 6
-	mov $r15 1
-	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
-	pop $r14
-	ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: total PGRAPH context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-	mov $xdbase $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
-
-	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
-	mov $r3 0x404
-	shl b32 $r3 6
-	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
-	iowr I[$r3 + 0x000] $r2
-
-	// not sure what these are, route them because NVIDIA does, and
-	// the IRQ handler will signal the host if we ever get one.. we
-	// may find out if/why we need to handle these if so..
-	//
-	mov $r2 0x2004
-	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
-	mov $r2 0x200b
-	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
-	mov $r2 0x200c
-	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
-	// enable all INTR_UP interrupts
-	mov $r2 0xc24
-	shl b32 $r2 6
-	not b32 $r3 $r0
-	iowr I[$r2] $r3
-
-	// enable fifo, ctxsw, 9, 10, 15 interrupts
-	mov $r2 -0x78fc		// 0x8704
-	sethi $r2 0
-	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
-
-	// fifo level triggered, rest edge
-	sub b32 $r1 0x100
-	mov $r2 4
-	iowr I[$r1] $r2
-
-	// enable interrupts
-	bset $flags ie0
-
-	// fetch enabled GPC/ROP counts
-	mov $r14 -0x69fc	// 0x409604
-	sethi $r14 0x400000
-	call #nv_rd32
-	extr $r1 $r15 16:20
-	st b32 D[$r0 + #rop_count] $r1
-	and $r15 0x1f
-	st b32 D[$r0 + #gpc_count] $r15
-
-	// set BAR_REQMASK to GPC mask
-	mov $r1 1
-	shl b32 $r1 $r15
-	sub b32 $r1 1
-	mov $r2 0x40c
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1
-	iowr I[$r2 + 0x100] $r1
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r15 #chipsets - 8
-	init_find_chipset:
-		add b32 $r15 8
-		ld b32 $r3 D[$r15 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// context size calculation, reserve first 256 bytes for use by fuc
-	init_context:
-	mov $r1 256
-
-	// calculate size of mmio context data
-	ld b16 $r14 D[$r15 + 4]
-	ld b16 $r15 D[$r15 + 6]
-	sethi $r14 0
-	st b32 D[$r0 + #hub_mmio_list_head] $r14
-	st b32 D[$r0 + #hub_mmio_list_tail] $r15
-	call #mmctx_size
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't (currently) ever change
-	mov $r3 0x700
-	shl b32 $r3 6
-	shr b32 $r4 $r1 8
-	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
-	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
-	add b32 $r3 0x1300
-	add b32 $r1 $r15
-	shr b32 $r15 2
-	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
-
-	// strands, base offset needs to be aligned to 256 bytes
-	shr b32 $r1 8
-	add b32 $r1 1
-	shl b32 $r1 8
-	mov b32 $r15 $r1
-	call #strand_ctx_init
-	add b32 $r1 $r15
-
-	// initialise each GPC in sequence by passing in the offset of its
-	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
-	// has previously been uploaded by the host) running.
-	//
-	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
-	// when it has completed, and return the size of its context data
-	// in GPCn_CC_SCRATCH[1]
-	//
-	ld b32 $r3 D[$r0 + #gpc_count]
-	mov $r4 0x2000
-	sethi $r4 0x500000
-	init_gpc:
-		// setup, and start GPC ucode running
-		add b32 $r14 $r4 0x804
-		mov b32 $r15 $r1
-		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
-		add b32 $r14 $r4 0x800
-		mov b32 $r15 $r2
-		call #nv_wr32			// CC_SCRATCH[0] = chipset
-		add b32 $r14 $r4 0x10c
-		clear b32 $r15
-		call #nv_wr32
-		add b32 $r14 $r4 0x104
-		call #nv_wr32			// ENTRY
-		add b32 $r14 $r4 0x100
-		mov $r15 2			// CTRL_START_TRIGGER
-		call #nv_wr32			// CTRL
-
-		// wait for it to complete, and adjust context size
-		add b32 $r14 $r4 0x800
-		init_gpc_wait:
-			call #nv_rd32
-			xbit $r15 $r15 31
-			bra e #init_gpc_wait
-		add b32 $r14 $r4 0x804
-		call #nv_rd32
-		add b32 $r1 $r15
-
-		// next!
-		add b32 $r4 0x8000
-		sub b32 $r3 1
-		bra ne #init_gpc
-
-	// save context size, and tell host we're ready
-	mov $r2 0x800
-	shl b32 $r2 6
-	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
-	add b32 $r2 0x800
-	clear b32 $r1
-	bset $r1 31
-	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	// sleep until we have something to do
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// context switch, requested by GPU?
-	cmpu b32 $r14 0x4001
-	bra ne #main_not_ctx_switch
-		trace_set(T_AUTO)
-		mov $r1 0xb00
-		shl b32 $r1 6
-		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
-		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
-
-		xbit $r3 $r1 31
-		bra e #chsw_no_prev
-			xbit $r3 $r2 31
-			bra e #chsw_prev_no_next
-				push $r2
-				mov b32 $r2 $r1
-				trace_set(T_SAVE)
-				bclr $flags $p1
-				bset $flags $p2
-				call #ctx_xfer
-				trace_clr(T_SAVE);
-				pop $r2
-				trace_set(T_LOAD);
-				bset $flags $p1
-				call #ctx_xfer
-				trace_clr(T_LOAD);
-				bra #chsw_done
-			chsw_prev_no_next:
-				push $r2
-				mov b32 $r2 $r1
-				bclr $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-				pop $r2
-				mov $r1 0xb00
-				shl b32 $r1 6
-				iowr I[$r1] $r2
-				bra #chsw_done
-		chsw_no_prev:
-			xbit $r3 $r2 31
-			bra e #chsw_done
-				bset $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-
-		// ack the context switch request
-		chsw_done:
-		mov $r1 0xb0c
-		shl b32 $r1 6
-		mov $r2 1
-		iowr I[$r1 + 0x000] $r2		// 0x409b0c
-		trace_clr(T_AUTO)
-		bra #main
-
-	// request to set current channel? (*not* a context switch)
-	main_not_ctx_switch:
-	cmpu b32 $r14 0x0001
-	bra ne #main_not_ctx_chan
-		mov b32 $r2 $r15
-		call #ctx_chan
-		bra #main_done
-
-	// request to store current channel context?
-	main_not_ctx_chan:
-	cmpu b32 $r14 0x0002
-	bra ne #main_not_ctx_save
-		trace_set(T_SAVE)
-		bclr $flags $p1
-		bclr $flags $p2
-		call #ctx_xfer
-		trace_clr(T_SAVE)
-		bra #main_done
-
-	main_not_ctx_save:
-		shl b32 $r15 $r14 16
-		or $r15 E_BAD_COMMAND
-		call #error
-		bra #main
-
-	main_done:
-	mov $r1 0x820
-	shl b32 $r1 6
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// context switch request?
-	ih_no_fifo:
-	and $r11 $r10 0x00000100
-	bra e #ih_no_ctxsw
-		// enqueue a context switch for later processing
-		mov $r13 #cmd_queue
-		mov $r14 0x4001
-		call #queue_put
-
-	// anything we didn't handle, bring it to the host's attention
-	ih_no_ctxsw:
-	mov $r11 0x104
-	not b32 $r11
-	and $r11 $r10 $r11
-	bra e #ih_no_other
-		mov $r10 0xc1c
-		shl b32 $r10 6
-		iowr I[$r10] $r11	// INTR_UP_SET
-
-	// ack, and wake up main()
-	ih_no_other:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
-ctx_4160s:
-	mov $r14 0x4160
-	sethi $r14 0x400000
-	mov $r15 1
-	call #nv_wr32
-	ctx_4160s_wait:
-		call #nv_rd32
-		xbit $r15 $r15 4
-		bra e #ctx_4160s_wait
-	ret
-
-// Without clearing again at end of xfer, some things cause PGRAPH
-// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
-// still function with it set however...
-ctx_4160c:
-	mov $r14 0x4160
-	sethi $r14 0x400000
-	clear b32 $r15
-	call #nv_wr32
-	ret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	or $r15 0x10
-	call #nv_wr32
-	ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	call #nv_rd32
-	and $r15 0x10
-	bra ne #ctx_4170w
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x270
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0x770
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
-	ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
-	mov $r14 0x86c
-	shl b32 $r14 6
-	iowr I[$r14] $r15	// HUB(0x86c) = val
-	mov $r14 -0x75ec
-	sethi $r14 0x400000
-	call #nv_wr32		// ROP(0xa14) = val
-	mov $r14 -0x5794
-	sethi $r14 0x410000
-	call #nv_wr32		// GPC(0x86c) = val
-	ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
-	trace_set(T_CHAN)
-
-	// switch to channel, somewhat magic in parts..
-	mov $r10 12		// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa24
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r0	// 0x409a24
-	mov $r3 0xb00
-	shl b32 $r3 6
-	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
-	mov $r1 0xa0c
-	shl b32 $r1 6
-	mov $r4 7
-	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
-	iowr I[$r1 + 0x100] $r4	// MEM_CMD
-	ctx_chan_wait_0:
-		iord $r4 I[$r1 + 0x100]
-		and $r4 0x1f
-		bra ne #ctx_chan_wait_0
-	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
-
-	// load channel header, fetch PGRAPH context pointer
-	mov $xtargets $r0
-	bclr $r2 31
-	shl b32 $r2 4
-	add b32 $r2 2
-
-	trace_set(T_LCHAN)
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_BASE
-	mov $r1 0xa20
-	shl b32 $r1 6
-	mov $r2 0x0002
-	sethi $r2 0x80000000
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
-	mov $r1 0x10			// chan + 0x0210
-	mov $r2 #xfer_data
-	sethi $r2 0x00020000		// 16 bytes
-	xdld $r1 $r2
-	xdwait
-	trace_clr(T_LCHAN)
-
-	// update current context
-	ld b32 $r1 D[$r0 + #xfer_data + 4]
-	shl b32 $r1 24
-	ld b32 $r2 D[$r0 + #xfer_data + 0]
-	shr b32 $r2 8
-	or $r1 $r2
-	st b32 D[$r0 + #ctx_current] $r1
-
-	// set transfer base to start of context, and fetch context header
-	trace_set(T_LCTXH)
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1		// MEM_BASE
-	mov $r2 1
-	mov $r1 0xa20
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdld $r0 $r1
-	xdwait
-	trace_clr(T_LCTXH)
-
-	trace_clr(T_CHAN)
-	ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-//            the active channel for ctxctl, but not actually transfer
-//            any context data.  intended for use only during initial
-//            context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-	call #ctx_4160s
-	call #ctx_load
-	mov $r10 12			// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa10
-	shl b32 $r1 6
-	mov $r2 5
-	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
-	ctx_chan_wait:
-		iord $r2 I[$r1 + 0x000]
-		or $r2 $r2
-		bra ne #ctx_chan_wait
-	call #ctx_4160c
-	ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel.  Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state...  The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
-	// set transfer base to be the mmio list
-	ld b32 $r3 D[$r0 + #chan_mmio_address]
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	clear b32 $r3
-	ctx_mmio_loop:
-		// fetch next 256 bytes of mmio list if necessary
-		and $r4 $r3 0xff
-		bra ne #ctx_mmio_pull
-			mov $r5 #xfer_data
-			sethi $r5 0x00060000	// 256 bytes
-			xdld $r3 $r5
-			xdwait
-
-		// execute a single list entry
-		ctx_mmio_pull:
-		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
-		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-		call #nv_wr32
-
-		// next!
-		add b32 $r3 8
-		sub b32 $r1 1
-		bra ne #ctx_mmio_loop
-
-	// set transfer base back to the current context
-	ctx_mmio_done:
-	ld b32 $r3 D[$r0 + #ctx_current]
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	// disable the mmio list now, we don't need/want to execute it again
-	st b32 D[$r0 + #chan_mmio_count] $r0
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdst $r0 $r1
-	xdwait
-	ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// according to mwk, some kind of wait for idle
-	mov $r15 0xc00
-	shl b32 $r15 6
-	mov $r14 4
-	iowr I[$r15 + 0x200] $r14
-	ctx_xfer_idle:
-		iord $r14 I[$r15 + 0x000]
-		and $r14 0x2000
-		bra ne #ctx_xfer_idle
-
-	bra not $p1 #ctx_xfer_pre
-	bra $p2 #ctx_xfer_pre_load
-	ctx_xfer_pre:
-		mov $r15 0x10
-		call #ctx_86c
-		call #ctx_4160s
-		bra not $p1 #ctx_xfer_exec
-
-	ctx_xfer_pre_load:
-		mov $r15 2
-		call #ctx_4170s
-		call #ctx_4170w
-		call #ctx_redswitch
-		clear b32 $r15
-		call #ctx_4170s
-		call #ctx_load
-
-	// fetch context pointer, and initiate xfer on all GPCs
-	ctx_xfer_exec:
-	ld b32 $r1 D[$r0 + #ctx_current]
-	mov $r2 0x414
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
-	mov $r14 -0x5b00
-	sethi $r14 0x410000
-	mov b32 $r15 $r1
-	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
-	add b32 $r14 4
-	xbit $r15 $flags $p1
-	xbit $r2 $flags $p2
-	shl b32 $r2 1
-	or $r15 $r2
-	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 6		// first, last
-	mov $r11 0		// base = 0
-	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// wait for GPCs to all complete
-	mov $r10 8		// DONE_BAR
-	call #wait_doneo
-
-	// wait for strand xfer to complete
-	call #strand_wait
-
-	// post-op
-	bra $p1 #ctx_xfer_post
-		mov $r10 12		// DONE_UNK12
-		call #wait_donez
-		mov $r1 0xa10
-		shl b32 $r1 6
-		mov $r2 5
-		iowr I[$r1] $r2		// MEM_CMD
-		ctx_xfer_post_save_wait:
-			iord $r2 I[$r1]
-			or $r2 $r2
-			bra ne #ctx_xfer_post_save_wait
-
-	bra $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r15 2
-		call #ctx_4170s
-		clear b32 $r15
-		call #ctx_86c
-		call #strand_post
-		call #ctx_4170w
-		clear b32 $r15
-		call #ctx_4170s
-
-		bra not $p1 #ctx_xfer_no_post_mmio
-		ld b32 $r1 D[$r0 + #chan_mmio_count]
-		or $r1 $r1
-		bra e #ctx_xfer_no_post_mmio
-			call #ctx_mmio_exec
-
-		ctx_xfer_no_post_mmio:
-		call #ctx_4160c
-
-	ctx_xfer_done:
-	ret
-
+#include "com.fuc"
+#include "hub.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
index 0953c2db2d130cd11db173d2108645c38d383aff..d1bf230018300993ef962c490df6098451656f25 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
@@ -338,7 +338,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x0089d000,
 	0x081887f1,
 	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
+/* 0x00e2: wait_donez_ne */
 	0x87f1008a,
 	0x84b60400,
 	0x0088cf06,
@@ -355,7 +355,7 @@ uint32_t nvc0_grhub_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x011c: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
index b57a3db8df717946a3d4606fa12f47f0fbc4e901..c7225db6486c7fc10a212c9d069108c281794d6e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 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"),
@@ -20,32 +19,17 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 nve0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grhub.fuc.h
- */
+#define NVGK
+#include "macros.fuc"
 
 .section #nve0_grhub_data
-include(`nve0.fuc')
-gpc_count:		.b32 0
-rop_count:		.b32 0
-cmd_queue:		queue_init
-hub_mmio_list_head:	.b32 0
-hub_mmio_list_tail:	.b32 0
-
-ctx_current:		.b32 0
-
-.align 256
-chan_data:
-chan_mmio_count:	.b32 0
-chan_mmio_address:	.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
 
-.align 256
-xfer_data: 		.b32 0
-
-.align 256
 chipsets:
 .b8  0xe4 0 0 0
 .b16 #nve4_hub_mmio_head
@@ -170,684 +154,12 @@ mmctx_data(0x408840, 1)
 mmctx_data(0x408900, 3)
 mmctx_data(0x408980, 1)
 nvf0_hub_mmio_tail:
+#undef INCLUDE_DATA
 
 .section #nve0_grhub_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
-	push $r14
-	mov $r14 0x814
-	shl b32 $r14 6
-	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
-	mov $r14 0xc1c
-	shl b32 $r14 6
-	mov $r15 1
-	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
-	pop $r14
-	ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: total PGRAPH context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-	mov $xdbase $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
-
-	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
-	mov $r3 0x404
-	shl b32 $r3 6
-	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
-	iowr I[$r3 + 0x000] $r2
-
-	// not sure what these are, route them because NVIDIA does, and
-	// the IRQ handler will signal the host if we ever get one.. we
-	// may find out if/why we need to handle these if so..
-	//
-	mov $r2 0x2004
-	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
-	mov $r2 0x200b
-	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
-	mov $r2 0x200c
-	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
-	// enable all INTR_UP interrupts
-	mov $r2 0xc24
-	shl b32 $r2 6
-	not b32 $r3 $r0
-	iowr I[$r2] $r3
-
-	// enable fifo, ctxsw, 9, 10, 15 interrupts
-	mov $r2 -0x78fc		// 0x8704
-	sethi $r2 0
-	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
-
-	// fifo level triggered, rest edge
-	sub b32 $r1 0x100
-	mov $r2 4
-	iowr I[$r1] $r2
-
-	// enable interrupts
-	bset $flags ie0
-
-	// fetch enabled GPC/ROP counts
-	mov $r14 -0x69fc	// 0x409604
-	sethi $r14 0x400000
-	call #nv_rd32
-	extr $r1 $r15 16:20
-	st b32 D[$r0 + #rop_count] $r1
-	and $r15 0x1f
-	st b32 D[$r0 + #gpc_count] $r15
-
-	// set BAR_REQMASK to GPC mask
-	mov $r1 1
-	shl b32 $r1 $r15
-	sub b32 $r1 1
-	mov $r2 0x40c
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1
-	iowr I[$r2 + 0x100] $r1
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r15 #chipsets - 8
-	init_find_chipset:
-		add b32 $r15 8
-		ld b32 $r3 D[$r15 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// context size calculation, reserve first 256 bytes for use by fuc
-	init_context:
-	mov $r1 256
-
-	// calculate size of mmio context data
-	ld b16 $r14 D[$r15 + 4]
-	ld b16 $r15 D[$r15 + 6]
-	sethi $r14 0
-	st b32 D[$r0 + #hub_mmio_list_head] $r14
-	st b32 D[$r0 + #hub_mmio_list_tail] $r15
-	call #mmctx_size
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't (currently) ever change
-	mov $r3 0x700
-	shl b32 $r3 6
-	shr b32 $r4 $r1 8
-	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
-	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
-	add b32 $r3 0x1300
-	add b32 $r1 $r15
-	shr b32 $r15 2
-	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
-
-	// strands, base offset needs to be aligned to 256 bytes
-	shr b32 $r1 8
-	add b32 $r1 1
-	shl b32 $r1 8
-	mov b32 $r15 $r1
-	call #strand_ctx_init
-	add b32 $r1 $r15
-
-	// initialise each GPC in sequence by passing in the offset of its
-	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
-	// has previously been uploaded by the host) running.
-	//
-	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
-	// when it has completed, and return the size of its context data
-	// in GPCn_CC_SCRATCH[1]
-	//
-	ld b32 $r3 D[$r0 + #gpc_count]
-	mov $r4 0x2000
-	sethi $r4 0x500000
-	init_gpc:
-		// setup, and start GPC ucode running
-		add b32 $r14 $r4 0x804
-		mov b32 $r15 $r1
-		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
-		add b32 $r14 $r4 0x800
-		mov b32 $r15 $r2
-		call #nv_wr32			// CC_SCRATCH[0] = chipset
-		add b32 $r14 $r4 0x10c
-		clear b32 $r15
-		call #nv_wr32
-		add b32 $r14 $r4 0x104
-		call #nv_wr32			// ENTRY
-		add b32 $r14 $r4 0x100
-		mov $r15 2			// CTRL_START_TRIGGER
-		call #nv_wr32			// CTRL
-
-		// wait for it to complete, and adjust context size
-		add b32 $r14 $r4 0x800
-		init_gpc_wait:
-			call #nv_rd32
-			xbit $r15 $r15 31
-			bra e #init_gpc_wait
-		add b32 $r14 $r4 0x804
-		call #nv_rd32
-		add b32 $r1 $r15
-
-		// next!
-		add b32 $r4 0x8000
-		sub b32 $r3 1
-		bra ne #init_gpc
-
-	// save context size, and tell host we're ready
-	mov $r2 0x800
-	shl b32 $r2 6
-	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
-	add b32 $r2 0x800
-	clear b32 $r1
-	bset $r1 31
-	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	// sleep until we have something to do
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// context switch, requested by GPU?
-	cmpu b32 $r14 0x4001
-	bra ne #main_not_ctx_switch
-		trace_set(T_AUTO)
-		mov $r1 0xb00
-		shl b32 $r1 6
-		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
-		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
-
-		xbit $r3 $r1 31
-		bra e #chsw_no_prev
-			xbit $r3 $r2 31
-			bra e #chsw_prev_no_next
-				push $r2
-				mov b32 $r2 $r1
-				trace_set(T_SAVE)
-				bclr $flags $p1
-				bset $flags $p2
-				call #ctx_xfer
-				trace_clr(T_SAVE);
-				pop $r2
-				trace_set(T_LOAD);
-				bset $flags $p1
-				call #ctx_xfer
-				trace_clr(T_LOAD);
-				bra #chsw_done
-			chsw_prev_no_next:
-				push $r2
-				mov b32 $r2 $r1
-				bclr $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-				pop $r2
-				mov $r1 0xb00
-				shl b32 $r1 6
-				iowr I[$r1] $r2
-				bra #chsw_done
-		chsw_no_prev:
-			xbit $r3 $r2 31
-			bra e #chsw_done
-				bset $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-
-		// ack the context switch request
-		chsw_done:
-		mov $r1 0xb0c
-		shl b32 $r1 6
-		mov $r2 1
-		iowr I[$r1 + 0x000] $r2		// 0x409b0c
-		trace_clr(T_AUTO)
-		bra #main
-
-	// request to set current channel? (*not* a context switch)
-	main_not_ctx_switch:
-	cmpu b32 $r14 0x0001
-	bra ne #main_not_ctx_chan
-		mov b32 $r2 $r15
-		call #ctx_chan
-		bra #main_done
-
-	// request to store current channel context?
-	main_not_ctx_chan:
-	cmpu b32 $r14 0x0002
-	bra ne #main_not_ctx_save
-		trace_set(T_SAVE)
-		bclr $flags $p1
-		bclr $flags $p2
-		call #ctx_xfer
-		trace_clr(T_SAVE)
-		bra #main_done
-
-	main_not_ctx_save:
-		shl b32 $r15 $r14 16
-		or $r15 E_BAD_COMMAND
-		call #error
-		bra #main
-
-	main_done:
-	mov $r1 0x820
-	shl b32 $r1 6
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// context switch request?
-	ih_no_fifo:
-	and $r11 $r10 0x00000100
-	bra e #ih_no_ctxsw
-		// enqueue a context switch for later processing
-		mov $r13 #cmd_queue
-		mov $r14 0x4001
-		call #queue_put
-
-	// anything we didn't handle, bring it to the host's attention
-	ih_no_ctxsw:
-	mov $r11 0x104
-	not b32 $r11
-	and $r11 $r10 $r11
-	bra e #ih_no_other
-		mov $r10 0xc1c
-		shl b32 $r10 6
-		iowr I[$r10] $r11	// INTR_UP_SET
-
-	// ack, and wake up main()
-	ih_no_other:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	or $r15 0x10
-	call #nv_wr32
-	ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	call #nv_rd32
-	and $r15 0x10
-	bra ne #ctx_4170w
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x270
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0x770
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
-	ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
-	mov $r14 0x86c
-	shl b32 $r14 6
-	iowr I[$r14] $r15	// HUB(0x86c) = val
-	mov $r14 -0x75ec
-	sethi $r14 0x400000
-	call #nv_wr32		// ROP(0xa14) = val
-	mov $r14 -0x5794
-	sethi $r14 0x410000
-	call #nv_wr32		// GPC(0x86c) = val
-	ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
-	trace_set(T_CHAN)
-
-	// switch to channel, somewhat magic in parts..
-	mov $r10 12		// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa24
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r0	// 0x409a24
-	mov $r3 0xb00
-	shl b32 $r3 6
-	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
-	mov $r1 0xa0c
-	shl b32 $r1 6
-	mov $r4 7
-	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
-	iowr I[$r1 + 0x100] $r4	// MEM_CMD
-	ctx_chan_wait_0:
-		iord $r4 I[$r1 + 0x100]
-		and $r4 0x1f
-		bra ne #ctx_chan_wait_0
-	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
-
-	// load channel header, fetch PGRAPH context pointer
-	mov $xtargets $r0
-	bclr $r2 31
-	shl b32 $r2 4
-	add b32 $r2 2
-
-	trace_set(T_LCHAN)
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_BASE
-	mov $r1 0xa20
-	shl b32 $r1 6
-	mov $r2 0x0002
-	sethi $r2 0x80000000
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
-	mov $r1 0x10			// chan + 0x0210
-	mov $r2 #xfer_data
-	sethi $r2 0x00020000		// 16 bytes
-	xdld $r1 $r2
-	xdwait
-	trace_clr(T_LCHAN)
-
-	// update current context
-	ld b32 $r1 D[$r0 + #xfer_data + 4]
-	shl b32 $r1 24
-	ld b32 $r2 D[$r0 + #xfer_data + 0]
-	shr b32 $r2 8
-	or $r1 $r2
-	st b32 D[$r0 + #ctx_current] $r1
-
-	// set transfer base to start of context, and fetch context header
-	trace_set(T_LCTXH)
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1		// MEM_BASE
-	mov $r2 1
-	mov $r1 0xa20
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdld $r0 $r1
-	xdwait
-	trace_clr(T_LCTXH)
-
-	trace_clr(T_CHAN)
-	ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-//            the active channel for ctxctl, but not actually transfer
-//            any context data.  intended for use only during initial
-//            context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-	call #ctx_load
-	mov $r10 12			// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa10
-	shl b32 $r1 6
-	mov $r2 5
-	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
-	ctx_chan_wait:
-		iord $r2 I[$r1 + 0x000]
-		or $r2 $r2
-		bra ne #ctx_chan_wait
-	ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel.  Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state...  The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
-	// set transfer base to be the mmio list
-	ld b32 $r3 D[$r0 + #chan_mmio_address]
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	clear b32 $r3
-	ctx_mmio_loop:
-		// fetch next 256 bytes of mmio list if necessary
-		and $r4 $r3 0xff
-		bra ne #ctx_mmio_pull
-			mov $r5 #xfer_data
-			sethi $r5 0x00060000	// 256 bytes
-			xdld $r3 $r5
-			xdwait
-
-		// execute a single list entry
-		ctx_mmio_pull:
-		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
-		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-		call #nv_wr32
-
-		// next!
-		add b32 $r3 8
-		sub b32 $r1 1
-		bra ne #ctx_mmio_loop
-
-	// set transfer base back to the current context
-	ctx_mmio_done:
-	ld b32 $r3 D[$r0 + #ctx_current]
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	// disable the mmio list now, we don't need/want to execute it again
-	st b32 D[$r0 + #chan_mmio_count] $r0
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdst $r0 $r1
-	xdwait
-	ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// according to mwk, some kind of wait for idle
-	mov $r15 0xc00
-	shl b32 $r15 6
-	mov $r14 4
-	iowr I[$r15 + 0x200] $r14
-	ctx_xfer_idle:
-		iord $r14 I[$r15 + 0x000]
-		and $r14 0x2000
-		bra ne #ctx_xfer_idle
-
-	bra not $p1 #ctx_xfer_pre
-	bra $p2 #ctx_xfer_pre_load
-	ctx_xfer_pre:
-		mov $r15 0x10
-		call #ctx_86c
-		bra not $p1 #ctx_xfer_exec
-
-	ctx_xfer_pre_load:
-		mov $r15 2
-		call #ctx_4170s
-		call #ctx_4170w
-		call #ctx_redswitch
-		clear b32 $r15
-		call #ctx_4170s
-		call #ctx_load
-
-	// fetch context pointer, and initiate xfer on all GPCs
-	ctx_xfer_exec:
-	ld b32 $r1 D[$r0 + #ctx_current]
-	mov $r2 0x414
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
-	mov $r14 -0x5b00
-	sethi $r14 0x410000
-	mov b32 $r15 $r1
-	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
-	add b32 $r14 4
-	xbit $r15 $flags $p1
-	xbit $r2 $flags $p2
-	shl b32 $r2 1
-	or $r15 $r2
-	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 6		// first, last
-	mov $r11 0		// base = 0
-	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// wait for GPCs to all complete
-	mov $r10 8		// DONE_BAR
-	call #wait_doneo
-
-	// wait for strand xfer to complete
-	call #strand_wait
-
-	// post-op
-	bra $p1 #ctx_xfer_post
-		mov $r10 12		// DONE_UNK12
-		call #wait_donez
-		mov $r1 0xa10
-		shl b32 $r1 6
-		mov $r2 5
-		iowr I[$r1] $r2		// MEM_CMD
-		ctx_xfer_post_save_wait:
-			iord $r2 I[$r1]
-			or $r2 $r2
-			bra ne #ctx_xfer_post_save_wait
-
-	bra $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r15 2
-		call #ctx_4170s
-		clear b32 $r15
-		call #ctx_86c
-		call #strand_post
-		call #ctx_4170w
-		clear b32 $r15
-		call #ctx_4170s
-
-		bra not $p1 #ctx_xfer_no_post_mmio
-		ld b32 $r1 D[$r0 + #chan_mmio_count]
-		or $r1 $r1
-		bra e #ctx_xfer_no_post_mmio
-			call #ctx_mmio_exec
-
-		ctx_xfer_no_post_mmio:
-
-	ctx_xfer_done:
-	ret
-
+#include "com.fuc"
+#include "hub.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
index f22422e09045fa033cb9dda92fe1598937b10656..623e8698ace19e24933d7c1a101d4455cd626bc2 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
@@ -388,7 +388,7 @@ uint32_t nve0_grhub_code[] = {
 	0x0089d000,
 	0x081887f1,
 	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
+/* 0x00e2: wait_donez_ne */
 	0x87f1008a,
 	0x84b60400,
 	0x0088cf06,
@@ -405,7 +405,7 @@ uint32_t nve0_grhub_code[] = {
 	0x87f10089,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x011c: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
new file mode 100644
index 0000000000000000000000000000000000000000..43a0b9476efd8f3c9453b2155d63720335d23f30
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 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 <bskeggs@redhat.com>
+ */
+
+#include "os.h"
+
+#define mmctx_data(r,c) .b32 (((c - 1) << 26) | r)
+#define queue_init      .skip 72 // (2 * 4) + ((8 * 4) * 2)
+
+#define T_WAIT    0
+#define T_MMCTX   1
+#define T_STRWAIT 2
+#define T_STRINIT 3
+#define T_AUTO    4
+#define T_CHAN    5
+#define T_LOAD    6
+#define T_SAVE    7
+#define T_LCHAN   8
+#define T_LCTXH   9
+
+#define trace_set(bit) /*
+*/	mov $r8 0x83c /*
+*/	shl b32 $r8 6 /*
+*/	clear b32 $r9 /*
+*/	bset $r9 bit /*
+*/	iowr I[$r8 + 0x000] $r9
+
+#define trace_clr(bit) /*
+*/	mov $r8 0x85c /*
+*/	shl b32 $r8 6 /*
+*/	clear b32 $r9 /*
+*/	bset $r9 bit /*
+*/	iowr I[$r8 + 0x000] $r9
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
deleted file mode 100644
index f16a5d53319debf9954a317015495980d5b8adda..0000000000000000000000000000000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
+++ /dev/null
@@ -1,400 +0,0 @@
-/* fuc microcode util functions for nve0 PGRAPH
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
-	mov $r8 0x83c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
-	mov $r8 0x85c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-// queue_put - add request to queue
-//
-// In : $r13 queue pointer
-//	$r14 command
-//	$r15 data
-//
-queue_put:
-	// make sure we have space..
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	xor $r8 8
-	cmpu b32 $r8 $r9
-	bra ne #queue_put_next
-		mov $r15 E_CMD_OVERFLOW
-		call #error
-		ret
-
-	// store cmd/data on queue
-	queue_put_next:
-	and $r8 $r9 7
-	shl b32 $r8 3
-	add b32 $r8 $r13
-	add b32 $r8 8
-	st b32 D[$r8 + 0x0] $r14
-	st b32 D[$r8 + 0x4] $r15
-
-	// update PUT
-	add b32 $r9 1
-	and $r9 0xf
-	st b32 D[$r13 + 0x4] $r9
-	ret
-
-// queue_get - fetch request from queue
-//
-// In : $r13 queue pointer
-//
-// Out:	$p1  clear on success (data available)
-//	$r14 command
-// 	$r15 data
-//
-queue_get:
-	bset $flags $p1
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	cmpu b32 $r8 $r9
-	bra e #queue_get_done
-		// fetch first cmd/data pair
-		and $r9 $r8 7
-		shl b32 $r9 3
-		add b32 $r9 $r13
-		add b32 $r9 8
-		ld b32 $r14 D[$r9 + 0x0]
-		ld b32 $r15 D[$r9 + 0x4]
-
-		// update GET
-		add b32 $r8 1
-		and $r8 0xf
-		st b32 D[$r13 + 0x0] $r8
-		bclr $flags $p1
-queue_get_done:
-	ret
-
-// nv_rd32 - read 32-bit value from nv register
-//
-// In : $r14 register
-// Out: $r15 value
-//
-nv_rd32:
-	mov $r11 0x728
-	shl b32 $r11 6
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	iowr I[$r11 + 0x000] $r12	// MMIO_CTRL
-	nv_rd32_wait:
-		iord $r12 I[$r11 + 0x000]
-		xbit $r12 $r12 31
-		bra ne #nv_rd32_wait
-	mov $r10 6			// DONE_MMIO_RD
-	call #wait_doneo
-	iord $r15 I[$r11 + 0x100]	// MMIO_RDVAL
-	ret
-
-// nv_wr32 - write 32-bit value to nv register
-//
-// In : $r14 register
-//      $r15 value
-//
-nv_wr32:
-	mov $r11 0x728
-	shl b32 $r11 6
-	iowr I[$r11 + 0x200] $r15	// MMIO_WRVAL
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	bset $r12 30			// MMIO_CTRL_WRITE
-	iowr I[$r11 + 0x000] $r12	// MMIO_CTRL
-	nv_wr32_wait:
-		iord $r12 I[$r11 + 0x000]
-		xbit $r12 $r12 31
-		bra ne #nv_wr32_wait
-	ret
-
-// (re)set watchdog timer
-//
-// In : $r15 timeout
-//
-watchdog_reset:
-	mov $r8 0x430
-	shl b32 $r8 6
-	bset $r15 31
-	iowr I[$r8 + 0x000] $r15
-	ret
-
-// clear watchdog timer
-watchdog_clear:
-	mov $r8 0x430
-	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r0
-	ret
-
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
-//
-// In : $r10 bit to wait on
-//
-define(`wait_done', `
-$1:
-	trace_set(T_WAIT);
-	mov $r8 0x818
-	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r10	// CC_SCRATCH[6] = wait bit
-	wait_done_$1:
-		mov $r8 0x400
-		shl b32 $r8 6
-		iord $r8 I[$r8 + 0x000]	// DONE
-		xbit $r8 $r8 $r10
-		bra $2 #wait_done_$1
-	trace_clr(T_WAIT)
-	ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
-
-// mmctx_size - determine size of a mmio list transfer
-//
-// In : $r14 mmio list head
-//      $r15 mmio list tail
-// Out: $r15 transfer size (in bytes)
-//
-mmctx_size:
-	clear b32 $r9
-	nv_mmctx_size_loop:
-		ld b32 $r8 D[$r14]
-		shr b32 $r8 26
-		add b32 $r8 1
-		shl b32 $r8 2
-		add b32 $r9 $r8
-		add b32 $r14 4
-		cmpu b32 $r14 $r15
-		bra ne #nv_mmctx_size_loop
-	mov b32 $r15 $r9
-	ret
-
-// mmctx_xfer - execute a list of mmio transfers
-//
-// In : $r10 flags
-//		bit 0: direction (0 = save, 1 = load)
-//		bit 1: set if first transfer
-//		bit 2: set if last transfer
-//	$r11 base
-//	$r12 mmio list head
-//	$r13 mmio list tail
-//	$r14 multi_stride
-//	$r15 multi_mask
-//
-mmctx_xfer:
-	trace_set(T_MMCTX)
-	mov $r8 0x710
-	shl b32 $r8 6
-	clear b32 $r9
-	or $r11 $r11
-	bra e #mmctx_base_disabled
-		iowr I[$r8 + 0x000] $r11	// MMCTX_BASE
-		bset $r9 0			// BASE_EN
-	mmctx_base_disabled:
-	or $r14 $r14
-	bra e #mmctx_multi_disabled
-		iowr I[$r8 + 0x200] $r14 	// MMCTX_MULTI_STRIDE
-		iowr I[$r8 + 0x300] $r15 	// MMCTX_MULTI_MASK
-		bset $r9 1			// MULTI_EN
-	mmctx_multi_disabled:
-	add b32 $r8 0x100
-
-	xbit $r11 $r10 0
-	shl b32 $r11 16			// DIR
-	bset $r11 12			// QLIMIT = 0x10
-	xbit $r14 $r10 1
-	shl b32 $r14 17
-	or $r11 $r14			// START_TRIGGER
-	iowr I[$r8 + 0x000] $r11	// MMCTX_CTRL
-
-	// loop over the mmio list, and send requests to the hw
-	mmctx_exec_loop:
-		// wait for space in mmctx queue
-		mmctx_wait_free:
-			iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
-			and $r14 0x1f
-			bra e #mmctx_wait_free
-
-		// queue up an entry
-		ld b32 $r14 D[$r12]
-		or $r14 $r9
-		iowr I[$r8 + 0x300] $r14
-		add b32 $r12 4
-		cmpu b32 $r12 $r13
-		bra ne #mmctx_exec_loop
-
-	xbit $r11 $r10 2
-	bra ne #mmctx_stop
-		// wait for queue to empty
-		mmctx_fini_wait:
-			iord $r11 I[$r8 + 0x000]	// MMCTX_CTRL
-			and $r11 0x1f
-			cmpu b32 $r11 0x10
-			bra ne #mmctx_fini_wait
-		mov $r10 2				// DONE_MMCTX
-		call #wait_donez
-		bra #mmctx_done
-	mmctx_stop:
-		xbit $r11 $r10 0
-		shl b32 $r11 16			// DIR
-		bset $r11 12			// QLIMIT = 0x10
-		bset $r11 18			// STOP_TRIGGER
-		iowr I[$r8 + 0x000] $r11	// MMCTX_CTRL
-		mmctx_stop_wait:
-			// wait for STOP_TRIGGER to clear
-			iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
-			xbit $r11 $r11 18
-			bra ne #mmctx_stop_wait
-	mmctx_done:
-	trace_clr(T_MMCTX)
-	ret
-
-// Wait for DONE_STRAND
-//
-strand_wait:
-	push $r10
-	mov $r10 2
-	call #wait_donez
-	pop $r10
-	ret
-
-// unknown - call before issuing strand commands
-//
-strand_pre:
-	mov $r8 0x4afc
-	sethi $r8 0x20000
-	mov $r9 0xc
-	iowr I[$r8] $r9
-	call #strand_wait
-	ret
-
-// unknown - call after issuing strand commands
-//
-strand_post:
-	mov $r8 0x4afc
-	sethi $r8 0x20000
-	mov $r9 0xd
-	iowr I[$r8] $r9
-	call #strand_wait
-	ret
-
-// Selects strand set?!
-//
-// In: $r14 id
-//
-strand_set:
-	mov $r10 0x4ffc
-	sethi $r10 0x20000
-	sub b32 $r11 $r10 0x500
-	mov $r12 0xf
-	iowr I[$r10 + 0x000] $r12		// 0x93c = 0xf
-	mov $r12 0xb
-	iowr I[$r11 + 0x000] $r12		// 0x928 = 0xb
-	call #strand_wait
-	iowr I[$r10 + 0x000] $r14		// 0x93c = <id>
-	mov $r12 0xa
-	iowr I[$r11 + 0x000] $r12		// 0x928 = 0xa
-	call #strand_wait
-	ret
-
-// Initialise strand context data
-//
-// In : $r15 context base
-// Out: $r15 context size (in bytes)
-//
-// Strandset(?) 3 hardcoded currently
-//
-strand_ctx_init:
-	trace_set(T_STRINIT)
-	call #strand_pre
-	mov $r14 3
-	call #strand_set
-	mov $r10 0x46fc
-	sethi $r10 0x20000
-	add b32 $r11 $r10 0x400
-	iowr I[$r10 + 0x100] $r0	// STRAND_FIRST_GENE = 0
-	mov $r12 1
-	iowr I[$r11 + 0x000] $r12	// STRAND_CMD = LATCH_FIRST_GENE
-	call #strand_wait
-	sub b32 $r12 $r0 1
-	iowr I[$r10 + 0x000] $r12	// STRAND_GENE_CNT = 0xffffffff
-	mov $r12 2
-	iowr I[$r11 + 0x000] $r12	// STRAND_CMD = LATCH_GENE_CNT
-	call #strand_wait
-	call #strand_post
-
-	// read the size of each strand, poke the context offset of
-	// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
-	// about it later then.
-	mov $r8 0x880
-	shl b32 $r8 6
-	iord $r9 I[$r8 + 0x000]		// STRANDS
-	add b32 $r8 0x2200
-	shr b32 $r14 $r15 8
-	ctx_init_strand_loop:
-		iowr I[$r8 + 0x000] $r14	// STRAND_SAVE_SWBASE
-		iowr I[$r8 + 0x100] $r14	// STRAND_LOAD_SWBASE
-		iord $r10 I[$r8 + 0x200]	// STRAND_SIZE
-		shr b32 $r10 6
-		add b32 $r10 1
-		add b32 $r14 $r10
-		add b32 $r8 4
-		sub b32 $r9 1
-		bra ne #ctx_init_strand_loop
-
-	shl b32 $r14 8
-	sub b32 $r15 $r14 $r15
-	trace_clr(T_STRINIT)
-	ret
-')
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd1d380de094c1b47f013973d3c34f9f040ede63
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_GRAPH_OS_H__
+#define __NVKM_GRAPH_OS_H__
+
+#define E_BAD_COMMAND  0x00000001
+#define E_CMD_OVERFLOW 0x00000002
+
+#endif