| /* |
| * Copyright © 2011 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> |
| * |
| */ |
| |
| #include "debug.h" |
| #include "evict.h" |
| |
| #define CR0_0_ME_STATE_CTRL (1 << 31) |
| #define CR0_0_BP_SUPPRESS (1 << 15) |
| #define CR0_0_SPF_EN (1 << 2) |
| #define CR0_0_ACC_DIS (1 << 1) |
| #define CR0_1_BES_CTRL (1 << 31) |
| #define CR0_1_HALT_CTRL (1 << 30) |
| #define CR0_1_SOFT_EXCEPTION_CTRL (1 << 29) |
| #define CR0_1_ILLGL_OP_STS (1 << 28) |
| #define CR0_1_STACK_OVRFLW_STS (1 << 27) |
| |
| #define CR0_0_ENTRY_UNMASK (CR0_0_SPF_EN | CR0_0_ACC_DIS) |
| // TODO: Need to fix this for non breakpoint case |
| #define CR0_1_ENTRY_UNMASK ~(CR0_1_BES_CTRL) |
| #define CR0_0_RETURN_MASK ~(CR0_0_ME_STATE_CTRL | CR0_0_SPF_EN | CR0_0_ACC_DIS) |
| |
| // TODO: not sure how to make this not hardcoded |
| #define PER_THREAD_SCRATCH_SIZE (1 << 20) |
| #define PER_THREAD_QWORDS (PER_THREAD_SCRATCH_SIZE >> 4) |
| |
| /* Should get this from brw_defines.h */ |
| #define BRW_DATAPORT_OWORD_BLOCK_2_OWORDS 2 |
| #define BRW_DATAPORT_OWORD_BLOCK_4_OWORDS 3 |
| #define BRW_DATAPORT_OWORD_BLOCK_8_OWORDS 4 |
| #define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 8 |
| #define BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0 |
| |
| /* desc field, ie. dword3 6.3.66.2 and 2.11.2.1.4 */ |
| #define SEND_MLEN_5 (5<<25) |
| #define SEND_MLEN_3 (3<<25) |
| #define SEND_MLEN_2 (2<<25) |
| #define SEND_MLEN_1 (1<<25) |
| #define SEND_RLEN_1 (1<<20) |
| #define SEND_RLEN_0 (0<<20) |
| #define SEND_HEADER_PRESENT (1<<19) |
| #define SEND_WRITE_COMMIT (1<<17) |
| #define SEND_TYPE_WRITE (GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE<<13) |
| #define SEND_TYPE_READ (BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ<<13) |
| #define SEND_BLOCK_SIZE1 (BRW_DATAPORT_OWORD_BLOCK_2_OWORDS<<8) |
| #define SEND_BLOCK_SIZE2 (BRW_DATAPORT_OWORD_BLOCK_4_OWORDS<<8) |
| #define SEND_BLOCK_SIZE4 (BRW_DATAPORT_OWORD_BLOCK_8_OWORDS<<8) |
| #define SEND_BINDING_TABLE (255<<0) |
| // No write commit |
| #define WRITE_DESC1_XXX SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_2 |
| #define WRITE_DESC1_WC SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_2 | SEND_WRITE_COMMIT |
| #define WRITE_DESC2 SEND_BINDING_TABLE | SEND_BLOCK_SIZE2 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_3 |
| #define WRITE_DESC4 SEND_BINDING_TABLE | SEND_BLOCK_SIZE4 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_5 |
| #define RECV_DESC1 SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_READ | SEND_HEADER_PRESENT | SEND_MLEN_1 | SEND_RLEN_1 |
| //#define SEND_DESC1 0x40902FF |
| #define SEND_DESC1_WC 0x40b02FF |
| |
| /* ex_desc field 6.3.66.2 */ |
| #define SEND_DP_RENDER_CACHE (5<<0) |
| #define SEND_EOT (1<<5) |
| #define SEND_EX_DESC SEND_DP_RENDER_CACHE |
| |
| /** |
| * WRITE_SCRATCH1 - Write 2 owords. |
| * cdst.2 - offset |
| * cdst.5 - per thread scratch base, relative to gsba?? |
| * cdst+1 - data to be written. |
| */ |
| #define WRITE_SCRATCH1(cdst) \ |
| send (16) null cdst SEND_EX_DESC WRITE_DESC1_XXX FLAGS |
| #define WRITE_SCRATCH1_WC(cdst) \ |
| send (16) g1 cdst SEND_EX_DESC WRITE_DESC1_WC FLAGS |
| #define WRITE_SCRATCH2(cdst) \ |
| send (16) null cdst SEND_EX_DESC WRITE_DESC2 FLAGS |
| #define WRITE_SCRATCH4(cdst) \ |
| send (16) null cdst SEND_EX_DESC WRITE_DESC4 FLAGS |
| |
| /** |
| * READ_SCRATCH1 - Read 2 owords. |
| * cdst.2 - offset |
| * cdst.5 - per thread scratch base, relative to gsba?? |
| * grf - register where read data is populated. |
| */ |
| #define READ_SCRATCH1(grf, cdst) \ |
| send (16) grf:ud cdst SEND_EX_DESC RECV_DESC1 FLAGS |
| |
| /** |
| * SET_OFFSET - setup mrf for the given offset prior to a send instruction. |
| * mrf - message register to be used as the header. |
| * offset - offset. |
| * |
| * If a WRITE_SCRATCH follows, mrf+1 -> mrf+1+n should contain the data to be |
| * written. |
| */ |
| #define SET_OFFSET(mrf, offset) \ |
| mov (1) mrf.5:ud g0.5:ud FLAGS; \ |
| mov (1) mrf.2:ud offset:ud FLAGS |
| |
| /** |
| * SAVE_CRF - save the control register |
| * clobbers: m0.2, m0.5 |
| */ |
| #define CR_OFFSET 0x40 |
| #define SAVE_CRF \ |
| SET_OFFSET(m0, CR_OFFSET); \ |
| mov (8) m1:ud 0xdeadbeef:ud FLAGS; \ |
| mov (1) m1.0:ud cr0.0 FLAGS; \ |
| mov (1) m1.1:ud cr0.1 FLAGS; \ |
| mov (1) m1.2:ud cr0.2 FLAGS; \ |
| mov (1) m1.3:ud sr0:ud FLAGS; \ |
| WRITE_SCRATCH1(m0) |
| |
| /* |
| * clobbers: m0.2, m0.5 |
| */ |
| #define STORE_GRF(grf, offset) \ |
| SET_OFFSET(m0, offset); \ |
| mov (8) m1:ud grf:ud FLAGS; \ |
| WRITE_SCRATCH1(m0) |
| |
| /* |
| * clobbers: m0.2, m0.5 |
| */ |
| #define LOAD_GRF(grf, offset) \ |
| SET_OFFSET(m0, offset); \ |
| READ_SCRATCH1(grf, m0) |
| |
| /* |
| * clobbers: mrf.2 mrf.5 |
| */ |
| #define STORE_MRF(mrf, offset) \ |
| SET_OFFSET(mrf, offset); \ |
| WRITE_SCRATCH1(mrf) |
| |
| /* |
| * non-quirky semantics, unlike STORE_MRF |
| * clobbers: g1 |
| */ |
| #define LOAD_MRF(mrf, offset) \ |
| LOAD_GRF(g1, offset); \ |
| mov (8) mrf:ud g1:ud FLAGS |
| |
| #define SAVE_ALL_MRF \ |
| /* m1 is saved already */ \ |
| STORE_MRF(m1, 0x2); \ |
| STORE_MRF(m2, 0x4); \ |
| STORE_MRF(m3, 0x6); \ |
| STORE_MRF(m4, 0x8); \ |
| STORE_MRF(m5, 0xa); \ |
| STORE_MRF(m6, 0xc); \ |
| STORE_MRF(m7, 0xe); \ |
| STORE_MRF(m8, 0x10); \ |
| STORE_MRF(m9, 0x12); \ |
| STORE_MRF(m10, 0x14); \ |
| STORE_MRF(m11, 0x16); \ |
| STORE_MRF(m12, 0x18); \ |
| STORE_MRF(m13, 0x1a); \ |
| STORE_MRF(m14, 0x1c) |
| |
| #define RESTORE_ALL_MRF \ |
| LOAD_MRF(m15, 0x1c); \ |
| LOAD_MRF(m14, 0x1a); \ |
| LOAD_MRF(m13, 0x18); \ |
| LOAD_MRF(m12, 0x16); \ |
| LOAD_MRF(m11, 0x14); \ |
| LOAD_MRF(m10, 0x12); \ |
| LOAD_MRF(m9, 0x10); \ |
| LOAD_MRF(m8, 0xe); \ |
| LOAD_MRF(m7, 0xc); \ |
| LOAD_MRF(m6, 0xa); \ |
| LOAD_MRF(m5, 0x8); \ |
| LOAD_MRF(m4, 0x6); \ |
| LOAD_MRF(m3, 0x4); \ |
| LOAD_MRF(m2, 0x2); \ |
| LOAD_MRF(m1, 0x0) |
| |
| #ifndef SANDYBRIDGE |
| #error Only SandyBridge is supported |
| #endif |
| |
| /* Default flags for an instruction */ |
| #define FLAGS { ALIGN1, SWITCH, MASK_DISABLE, ACCWRCTRL} |
| |
| /* |
| * We can clobber m0, and g0.4, everything else must be saved. |
| */ |
| Enter: |
| nop; |
| |
| or (1) cr0.0 cr0.0 CR0_0_ENTRY_UNMASK:ud FLAGS; |
| |
| /* |
| * g0.5 has the per thread scratch space when running in FS or VS. |
| * If we don't have a valid g0.5, we can calculate a per thread scratch offset |
| * using the system registers. The problem is we do not have a good way to know |
| * the offset from GSBA. The system routine will have to be hardcoded or |
| * dynamically patched with the correct offset. |
| * TID is in sr0.0[2:0] |
| * EUID is in sr0.0[11:8] |
| */ |
| |
| #ifdef GPGPU |
| mov (1) g0.4:ud 0:ud FLAGS; |
| #if 0 |
| /* This should work according to the docs, the add blows up */ |
| shr (1) g0.8:uw sr0.0:uw 5 FLAGS; |
| add (1) g0.16:ub gr0.16:ub sr0.0:ub FLAGS; |
| #else |
| shr (1) g0.8:uw sr0.0:uw 5 FLAGS; |
| mov (1) g0.9:uw sr0.0:uw FLAGS; |
| and (1) g0.9:uw g0.9:uw 0x7:uw FLAGS; |
| add (1) g0.8:uw g0.8:uw g0.9:uw FLAGS; |
| mov (1) g0.9:uw 0:uw FLAGS; |
| mul (1) g0.4:ud g0.4:ud PER_THREAD_QWORDS FLAGS; |
| #endif |
| #endif |
| |
| mov (8) m0:ud 0:ud FLAGS; |
| |
| /* Saves must occur in order so as not to clobber the next register */ |
| STORE_MRF(m0, 0); |
| STORE_GRF(g0, 0x20); |
| STORE_GRF(g1, 0x22); |
| SAVE_ALL_MRF; |
| |
| mov (8) g1:ud STATE_EU_MSG:ud FLAGS; |
| STORE_GRF(g1, STATE_QWORD); |
| |
| mov (8) g1:ud DEBUG_PROTOCOL_VERSION:ud FLAGS; |
| STORE_GRF(g1, COMMUNICATION_QWORD); |
| |
| SAVE_CRF; |
| |
| EVICT_CACHE; |
| wait n1:ud; |
| EVICT_CACHE; |
| |
| /* Using this to try to keep coherency */ |
| LOAD_GRF(g1, CR_OFFSET); |
| LOAD_GRF(g1, COMMUNICATION_QWORD); |
| LOAD_GRF(g1, STATE_QWORD); |
| |
| RESTORE_ALL_MRF; |
| LOAD_GRF(g1, 0x22); |
| LOAD_GRF(g0, 0x20); |
| |
| /* Clear breakpoint status */ |
| and (1) cr0.1 cr0.1 CR0_1_ENTRY_UNMASK:ud FLAGS; |
| |
| /* set breakpoint suppress this should be conditional on bes */ |
| or (1) cr0.0 cr0.0 CR0_0_BP_SUPPRESS:ud FLAGS; |
| |
| and (1) cr0.0 cr0.0 CR0_0_RETURN_MASK:ud FLAGS; |
| nop; |