493 lines · plain
1/* fuc microcode for gf100 PGRAPH/GPC2 *3 * Copyright 2011 Red Hat Inc.4 *5 * Permission is hereby granted, free of charge, to any person obtaining a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: Ben Skeggs24 */25 26/* TODO27 * - bracket certain functions with scratch writes, useful for debugging28 * - watchdog timer around ctx operations29 */30 31#ifdef INCLUDE_DATA32gpc_mmio_list_head: .b32 #mmio_list_base33gpc_mmio_list_tail:34tpc_mmio_list_head: .b32 #mmio_list_base35tpc_mmio_list_tail:36unk_mmio_list_head: .b32 #mmio_list_base37unk_mmio_list_tail: .b32 #mmio_list_base38 39gpc_id: .b32 040 41tpc_count: .b32 042tpc_mask: .b32 043 44#if NV_PGRAPH_GPCX_UNK__SIZE > 045unk_count: .b32 046unk_mask: .b32 047#endif48 49cmd_queue: queue_init50 51mmio_list_base:52#endif53 54#ifdef INCLUDE_CODE55#define gpc_addr(reg,addr) /*56*/ imm32(reg,addr) /*57*/ or reg NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE58#define gpc_wr32(addr,reg) /*59*/ gpc_addr($r14,addr) /*60*/ mov b32 $r15 reg /*61*/ call(nv_wr32)62 63// reports an exception to the host64//65// In: $r15 error code (see os.h)66//67error:68 push $r1469 nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)70 mov $r15 171 nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)72 pop $r1473 ret74 75#if CHIPSET >= GM10776tpc_strand_wait:77 push $r978 trace_set(T_STRTPC)79 tpc_strand_busy:80 nv_iord($r9, NV_PGRAPH_GPCX_GPCCS_TPC_STATUS, 0)81 bra b32 $r9 0x0 ne #tpc_strand_busy82 trace_clr(T_STRTPC)83 pop $r984 ret85 86#define tpc_strand_wait() call(tpc_strand_wait)87#define tpc_strand_enable() /*88*/ mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_ENABLE /*89*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15) /*90*/ tpc_strand_wait()91#define tpc_strand_disable() /*92*/ mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_DISABLE /*93*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15) /*94*/ tpc_strand_wait()95#define tpc_strand_seek(p) /*96*/ mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL /*97*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15) /*98*/ mov $r15 p /*99*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_SELECT, $r15) /*100*/ mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SEEK /*101*/ tpc_strand_wait()102#define tpc_strand_info(m) /*103*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15) /*104*/ mov $r15 m /*105*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_DATA, $r15) /*106*/ mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_GET_INFO /*107*/ gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15) /*108*/ tpc_strand_wait()109#endif110 111 112// GPC fuc initialisation, executed by triggering ucode start, will113// fall through to main loop after completion.114//115// Input:116// CC_SCRATCH[1]: context base117//118// Output:119// CC_SCRATCH[0]:120// 31:31: set to signal completion121// CC_SCRATCH[1]:122// 31:0: GPC context size123//124init:125 clear b32 $r0126 127 // setup stack128 nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)129 extr $r1 $r1 9:17130 shl b32 $r1 8131 mov $sp $r1132 133 // enable fifo access134 mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO135 nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)136 137 // setup i0 handler, and route all interrupts to it138 mov $r1 #ih139 mov $iv0 $r1140 nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)141 142 // enable fifo interrupt143 mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO144 nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)145 146 // enable interrupts147 bset $flags ie0148 149 // how many TPCs do we have?150 nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)151 mov $r3 1152 and $r2 0x1f153 shl b32 $r3 $r2154 sub b32 $r3 1155 st b32 D[$r0 + #tpc_count] $r2156 st b32 D[$r0 + #tpc_mask] $r3157 158 // determine which GPC we are, setup (optional) mmio access offset159 nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)160 st b32 D[$r0 + #gpc_id] $r2161 shl b32 $r2 15162 nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMIO_BASE, 0, $r2)163 164#if NV_PGRAPH_GPCX_UNK__SIZE > 0165 // figure out which, and how many, UNKs are actually present166 gpc_addr($r14, 0x500c30)167 clear b32 $r2168 clear b32 $r3169 clear b32 $r4170 init_unk_loop:171 call(nv_rd32)172 cmp b32 $r15 0173 bra z #init_unk_next174 mov $r15 1175 shl b32 $r15 $r2176 or $r4 $r15177 add b32 $r3 1178 init_unk_next:179 add b32 $r2 1180 add b32 $r14 4181 cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE182 bra ne #init_unk_loop183 init_unk_done:184 st b32 D[$r0 + #unk_count] $r3185 st b32 D[$r0 + #unk_mask] $r4186#endif187 188 // initialise context base, and size tracking189 nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)190 clear b32 $r3 // track GPC context size here191 192 // set mmctx base addresses now so we don't have to do it later,193 // they don't currently ever change194 shr b32 $r5 $r2 8195 nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)196 nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)197 198 // calculate GPC mmio context size199 ld b32 $r14 D[$r0 + #gpc_mmio_list_head]200 ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]201 call(mmctx_size)202 add b32 $r2 $r15203 add b32 $r3 $r15204 205 // calculate per-TPC mmio context size206 ld b32 $r14 D[$r0 + #tpc_mmio_list_head]207 ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]208 call(mmctx_size)209 ld b32 $r14 D[$r0 + #tpc_count]210 mulu $r14 $r15211 add b32 $r2 $r14212 add b32 $r3 $r14213 214#if NV_PGRAPH_GPCX_UNK__SIZE > 0215 // calculate per-UNK mmio context size216 ld b32 $r14 D[$r0 + #unk_mmio_list_head]217 ld b32 $r15 D[$r0 + #unk_mmio_list_tail]218 call(mmctx_size)219 ld b32 $r14 D[$r0 + #unk_count]220 mulu $r14 $r15221 add b32 $r2 $r14222 add b32 $r3 $r14223#endif224 225 // round up base/size to 256 byte boundary (for strand SWBASE)226 shr b32 $r3 2227 nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!228 shr b32 $r2 8229 shr b32 $r3 6230 add b32 $r2 1231 add b32 $r3 1232 shl b32 $r2 8233 shl b32 $r3 8234 235 // calculate size of strand context data236 mov b32 $r15 $r2237 call(strand_ctx_init)238 add b32 $r2 $r15239 add b32 $r3 $r15240 241#if CHIPSET >= GM107242 // calculate size of tpc strand context data243 mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL244 gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15)245 tpc_strand_enable();246 tpc_strand_seek(0);247 tpc_strand_info(-1);248 249 ld b32 $r4 D[$r0 + #tpc_count]250 gpc_addr($r5, NV_PGRAPH_GPC0_TPC0)251 tpc_strand_init_tpc_loop:252 add b32 $r14 $r5 NV_TPC_STRAND_CNT253 call(nv_rd32)254 mov b32 $r6 $r15255 clear b32 $r7256 tpc_strand_init_idx_loop:257 add b32 $r14 $r5 NV_TPC_STRAND_INDEX258 mov b32 $r15 $r7259 call(nv_wr32)260 add b32 $r14 $r5 NV_TPC_STRAND_SAVE_SWBASE261 shr b32 $r15 $r2 8262 call(nv_wr32)263 add b32 $r14 $r5 NV_TPC_STRAND_LOAD_SWBASE264 shr b32 $r15 $r2 8265 call(nv_wr32)266 add b32 $r14 $r5 NV_TPC_STRAND_WORDS267 call(nv_rd32)268 shr b32 $r15 6269 add b32 $r15 1270 shl b32 $r15 8271 add b32 $r2 $r15272 add b32 $r3 $r15273 add b32 $r7 1274 sub b32 $r6 1275 bra nz #tpc_strand_init_idx_loop276 add b32 $r5 NV_PGRAPH_GPC0_TPC0__SIZE277 sub b32 $r4 1278 bra nz #tpc_strand_init_tpc_loop279 280 mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL281 gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15)282 tpc_strand_disable();283#endif284 285 // save context size, and tell HUB we're done286 nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)287 clear b32 $r2288 bset $r2 31289 nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)290 291// Main program loop, very simple, sleeps until woken up by the interrupt292// handler, pulls a command from the queue and executes its handler293//294wait:295 sleep $p0296 bset $flags $p0297main:298 mov $r13 #cmd_queue299 call(queue_get)300 bra $p1 #wait301 302 // 0x0000-0x0003 are all context transfers303 cmpu b32 $r14 0x04304 bra nc #main_not_ctx_xfer305 // fetch $flags and mask off $p1/$p2306 mov $r1 $flags307 mov $r2 0x0006308 not b32 $r2309 and $r1 $r2310 // set $p1/$p2 according to transfer type311 shl b32 $r14 1312 or $r1 $r14313 mov $flags $r1314 // transfer context data315 call(ctx_xfer)316 bra #main317 318 main_not_ctx_xfer:319 shl b32 $r15 $r14 16320 or $r15 E_BAD_COMMAND321 call(error)322 bra #main323 324// interrupt handler325ih:326 push $r0327 push $r8328 mov $r8 $flags329 push $r8330 push $r9331 push $r10332 push $r11333 push $r13334 push $r14335 push $r15336 clear b32 $r0337 338 // incoming fifo command?339 nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)340 and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO341 bra e #ih_no_fifo342 // queue incoming fifo command for later processing343 mov $r13 #cmd_queue344 nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)345 nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)346 call(queue_put)347 mov $r14 1348 nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)349 350 // ack, and wake up main()351 ih_no_fifo:352 nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)353 354 pop $r15355 pop $r14356 pop $r13357 pop $r11358 pop $r10359 pop $r9360 pop $r8361 mov $flags $r8362 pop $r8363 pop $r0364 bclr $flags $p0365 iret366 367// Set this GPC's bit in HUB_BAR, used to signal completion of various368// activities to the HUB fuc369//370hub_barrier_done:371 mov $r15 1372 ld b32 $r14 D[$r0 + #gpc_id]373 shl b32 $r15 $r14374 nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET375 ret376 377// Disables various things, waits a bit, and re-enables them..378//379// Not sure how exactly this helps, perhaps "ENABLE" is not such a380// good description for the bits we turn off? Anyways, without this,381// funny things happen.382//383ctx_redswitch:384 mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER385 nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)386 mov $r14 8387 ctx_redswitch_delay:388 sub b32 $r14 1389 bra ne #ctx_redswitch_delay390 or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11391 or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE392 nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)393 ret394 395// Transfer GPC context data between GPU and storage area396//397// In: $r15 context base address398// $p1 clear on save, set on load399// $p2 set if opposite direction done/will be done, so:400// on save it means: "a load will follow this save"401// on load it means: "a save preceeded this load"402//403ctx_xfer:404 // set context base address405 nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)406#if CHIPSET >= GM107407 gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_MEM_BASE, $r15)408#endif409 bra not $p1 #ctx_xfer_not_load410 call(ctx_redswitch)411 ctx_xfer_not_load:412 413 // strands414 call(strand_pre)415 clear b32 $r2416 nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)417 xbit $r2 $flags $p1 // SAVE/LOAD418 add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE419 nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)420 421#if CHIPSET >= GM107422 tpc_strand_enable();423 tpc_strand_seek(0);424 xbit $r15 $flags $p1 // SAVE/LOAD425 add b32 $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SAVE426 gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)427#endif428 429 // mmio context430 xbit $r10 $flags $p1 // direction431 or $r10 2 // first432 imm32($r11,0x500000)433 ld b32 $r12 D[$r0 + #gpc_id]434 shl b32 $r12 15435 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn436 ld b32 $r12 D[$r0 + #gpc_mmio_list_head]437 ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]438 mov $r14 0 // not multi439 call(mmctx_xfer)440 441 // per-TPC mmio context442 xbit $r10 $flags $p1 // direction443#if !NV_PGRAPH_GPCX_UNK__SIZE444 or $r10 4 // last445#endif446 imm32($r11, 0x504000)447 ld b32 $r12 D[$r0 + #gpc_id]448 shl b32 $r12 15449 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0450 ld b32 $r12 D[$r0 + #tpc_mmio_list_head]451 ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]452 ld b32 $r15 D[$r0 + #tpc_mask]453 mov $r14 0x800 // stride = 0x800454 call(mmctx_xfer)455 456#if NV_PGRAPH_GPCX_UNK__SIZE > 0457 // per-UNK mmio context458 xbit $r10 $flags $p1 // direction459 or $r10 4 // last460 imm32($r11, 0x503000)461 ld b32 $r12 D[$r0 + #gpc_id]462 shl b32 $r12 15463 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_UNK0464 ld b32 $r12 D[$r0 + #unk_mmio_list_head]465 ld b32 $r13 D[$r0 + #unk_mmio_list_tail]466 ld b32 $r15 D[$r0 + #unk_mask]467 mov $r14 0x200 // stride = 0x200468 call(mmctx_xfer)469#endif470 471 // wait for strands to finish472 call(strand_wait)473#if CHIPSET >= GM107474 tpc_strand_wait()475#endif476 477 // if load, or a save without a load following, do some478 // unknown stuff that's done after finishing a block of479 // strand commands480 bra $p1 #ctx_xfer_post481 bra not $p2 #ctx_xfer_done482 ctx_xfer_post:483 call(strand_post)484#if CHIPSET >= GM107485 tpc_strand_disable()486#endif487 488 // mark completion in HUB's barrier489 ctx_xfer_done:490 call(hub_barrier_done)491 ret492#endif493