1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Chia-I Wu <olv@lunarg.com>
26 */
27
28#ifndef ILO_BUILDER_MI_H
29#define ILO_BUILDER_MI_H
30
31#include "genhw/genhw.h"
32#include "intel_winsys.h"
33
34#include "ilo_core.h"
35#include "ilo_dev.h"
36#include "ilo_builder.h"
37
38static inline void
39gen6_MI_STORE_DATA_IMM(struct ilo_builder *builder,
40                       struct intel_bo *bo, uint32_t bo_offset,
41                       uint64_t val)
42{
43   const uint8_t cmd_len = (ilo_dev_gen(builder->dev) >= ILO_GEN(8)) ? 6 : 5;
44   uint32_t reloc_flags = INTEL_RELOC_WRITE;
45   uint32_t *dw;
46   unsigned pos;
47
48   ILO_DEV_ASSERT(builder->dev, 6, 8);
49
50   assert(bo_offset % 8 == 0);
51
52   pos = ilo_builder_batch_pointer(builder, cmd_len, &dw);
53
54   dw[0] = GEN6_MI_CMD(MI_STORE_DATA_IMM) | (cmd_len - 2);
55   /* must use GGTT on GEN6 as in PIPE_CONTROL */
56   if (ilo_dev_gen(builder->dev) == ILO_GEN(6)) {
57      dw[0] |= GEN6_MI_STORE_DATA_IMM_DW0_USE_GGTT;
58      reloc_flags |= INTEL_RELOC_GGTT;
59   }
60
61   dw[1] = 0; /* MBZ */
62
63   if (ilo_dev_gen(builder->dev) >= ILO_GEN(8)) {
64      dw[4] = (uint32_t) val;
65      dw[5] = (uint32_t) (val >> 32);
66
67      ilo_builder_batch_reloc64(builder, pos + 2, bo, bo_offset, reloc_flags);
68   } else {
69      dw[3] = (uint32_t) val;
70      dw[4] = (uint32_t) (val >> 32);
71
72      ilo_builder_batch_reloc(builder, pos + 2, bo, bo_offset, reloc_flags);
73   }
74}
75
76static inline void
77gen6_MI_LOAD_REGISTER_IMM(struct ilo_builder *builder,
78                          uint32_t reg, uint32_t val)
79{
80   const uint8_t cmd_len = 3;
81   uint32_t *dw;
82
83   ILO_DEV_ASSERT(builder->dev, 6, 8);
84
85   assert(reg % 4 == 0);
86
87   ilo_builder_batch_pointer(builder, cmd_len, &dw);
88
89   dw[0] = GEN6_MI_CMD(MI_LOAD_REGISTER_IMM) | (cmd_len - 2);
90   dw[1] = reg;
91   dw[2] = val;
92}
93
94static inline void
95gen6_MI_STORE_REGISTER_MEM(struct ilo_builder *builder, uint32_t reg,
96                           struct intel_bo *bo, uint32_t bo_offset)
97{
98   const uint8_t cmd_len = (ilo_dev_gen(builder->dev) >= ILO_GEN(8)) ? 4 : 3;
99   uint32_t reloc_flags = INTEL_RELOC_WRITE;
100   uint32_t *dw;
101   unsigned pos;
102
103   ILO_DEV_ASSERT(builder->dev, 6, 8);
104
105   assert(reg % 4 == 0 && bo_offset % 4 == 0);
106
107   pos = ilo_builder_batch_pointer(builder, cmd_len, &dw);
108
109   dw[0] = GEN6_MI_CMD(MI_STORE_REGISTER_MEM) | (cmd_len - 2);
110   dw[1] = reg;
111
112   if (ilo_dev_gen(builder->dev) >= ILO_GEN(8)) {
113      ilo_builder_batch_reloc64(builder, pos + 2, bo, bo_offset, reloc_flags);
114   } else {
115      /* must use GGTT on Gen6 as in PIPE_CONTROL */
116      if (ilo_dev_gen(builder->dev) == ILO_GEN(6)) {
117         dw[0] |= GEN6_MI_STORE_REGISTER_MEM_DW0_USE_GGTT;
118         reloc_flags |= INTEL_RELOC_GGTT;
119      }
120
121      ilo_builder_batch_reloc(builder, pos + 2, bo, bo_offset, reloc_flags);
122   }
123}
124
125static inline void
126gen6_MI_FLUSH_DW(struct ilo_builder *builder)
127{
128   const uint8_t cmd_len = 4;
129   uint32_t *dw;
130
131   ILO_DEV_ASSERT(builder->dev, 6, 8);
132
133   ilo_builder_batch_pointer(builder, cmd_len, &dw);
134
135   dw[0] = GEN6_MI_CMD(MI_FLUSH_DW) | (cmd_len - 2);
136   dw[1] = 0;
137   dw[2] = 0;
138   dw[3] = 0;
139}
140
141static inline void
142gen6_MI_REPORT_PERF_COUNT(struct ilo_builder *builder,
143                          struct intel_bo *bo, uint32_t bo_offset,
144                          uint32_t report_id)
145{
146   const uint8_t cmd_len = 3;
147   uint32_t reloc_flags = INTEL_RELOC_WRITE;
148   uint32_t *dw;
149   unsigned pos;
150
151   ILO_DEV_ASSERT(builder->dev, 6, 7.5);
152
153   assert(bo_offset % 64 == 0);
154
155   /* must use GGTT on GEN6 as in PIPE_CONTROL */
156   if (ilo_dev_gen(builder->dev) == ILO_GEN(6)) {
157      bo_offset |= GEN6_MI_REPORT_PERF_COUNT_DW1_USE_GGTT;
158      reloc_flags |= INTEL_RELOC_GGTT;
159   }
160
161   pos = ilo_builder_batch_pointer(builder, cmd_len, &dw);
162
163   dw[0] = GEN6_MI_CMD(MI_REPORT_PERF_COUNT) | (cmd_len - 2);
164   dw[2] = report_id;
165
166   ilo_builder_batch_reloc(builder, pos + 1, bo, bo_offset, reloc_flags);
167}
168
169static inline void
170gen7_MI_LOAD_REGISTER_MEM(struct ilo_builder *builder, uint32_t reg,
171                          struct intel_bo *bo, uint32_t bo_offset)
172{
173   const uint8_t cmd_len = (ilo_dev_gen(builder->dev) >= ILO_GEN(8)) ? 4 : 3;
174   uint32_t *dw;
175   unsigned pos;
176
177   ILO_DEV_ASSERT(builder->dev, 7, 8);
178
179   assert(reg % 4 == 0 && bo_offset % 4 == 0);
180
181   pos = ilo_builder_batch_pointer(builder, cmd_len, &dw);
182
183   dw[0] = GEN7_MI_CMD(MI_LOAD_REGISTER_MEM) | (cmd_len - 2);
184   dw[1] = reg;
185
186   if (ilo_dev_gen(builder->dev) >= ILO_GEN(8))
187      ilo_builder_batch_reloc64(builder, pos + 2, bo, bo_offset, 0);
188   else
189      ilo_builder_batch_reloc(builder, pos + 2, bo, bo_offset, 0);
190}
191
192/**
193 * Add a MI_BATCH_BUFFER_END to the batch buffer.  Pad with MI_NOOP if
194 * necessary.
195 */
196static inline void
197gen6_mi_batch_buffer_end(struct ilo_builder *builder)
198{
199   /*
200    * From the Sandy Bridge PRM, volume 1 part 1, page 107:
201    *
202    *     "The batch buffer must be QWord aligned and a multiple of QWords in
203    *      length."
204    */
205   const bool pad = !(builder->writers[ILO_BUILDER_WRITER_BATCH].used & 0x7);
206   uint32_t *dw;
207
208   ILO_DEV_ASSERT(builder->dev, 6, 8);
209
210   if (pad) {
211      ilo_builder_batch_pointer(builder, 2, &dw);
212      dw[0] = GEN6_MI_CMD(MI_BATCH_BUFFER_END);
213      dw[1] = GEN6_MI_CMD(MI_NOOP);
214   } else {
215      ilo_builder_batch_pointer(builder, 1, &dw);
216      dw[0] = GEN6_MI_CMD(MI_BATCH_BUFFER_END);
217   }
218}
219
220#endif /* ILO_BUILDER_MI_H */
221