Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: N2fcIommuMgr.vr | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | #include <vera_defines.vrh> | |
36 | ||
37 | // model some of the NCU/PIU CSRs | |
38 | //extern N2fcPiuShadowRegs PiuCsrs; | |
39 | ||
40 | // This is for accessing MEMORY | |
41 | //#include "niu_mem.vrh" | |
42 | //extern CSparseMem SparseMem; | |
43 | ||
44 | class N2fcIommuMgr { | |
45 | ||
46 | // bits in the MMU CONTROL reg | |
47 | bit process_disable = 0; | |
48 | bit snoop_en = 0; | |
49 | bit [1:0] cache_mode = 0; | |
50 | bit busid_sel = 0; | |
51 | bit sun4v_en = 0; | |
52 | bit bypass_en = 0; | |
53 | bit translation_en = 0; | |
54 | ||
55 | bit tsb_valid = 0; | |
56 | bit [38:0] tsb_pa = 0; | |
57 | bit [26:0] tsb_offset = 0; | |
58 | bit [2:0] tsb_pgsz = 0; | |
59 | bit [3:0] tsb_tblsz = 0; | |
60 | ||
61 | ||
62 | bit iotte_valid = 0; | |
63 | bit iotte_write = 0; | |
64 | bit iotte_keyvld = 0; | |
65 | bit [38:0] iotte_datapa = 0; | |
66 | bit [2:0] iotte_fnm = 0; | |
67 | bit [15:0] iotte_devkey = 0; | |
68 | ||
69 | ||
70 | bit msi = 0; | |
71 | ||
72 | // ****************************************************************** | |
73 | // Methods | |
74 | // ****************************************************************** | |
75 | ||
76 | public task new (); | |
77 | ||
78 | function bit get_physical_address(bit [63:0] va, var bit [39:0] pa, bit [7:0] busid, bit dmawr); | |
79 | function bit get_sun4v_pa (bit [63:0] va, var bit [39:0] pa, bit [7:0] busid, bit dmawr); | |
80 | ||
81 | // helper functions | |
82 | function bit is_bypass_mode(bit [63:0] va); | |
83 | function bit is_sun4u_mode(bit [63:0] va); | |
84 | function bit is_sun4v_mode(bit [63:0] va); | |
85 | ||
86 | task get_mmu_cntl_reg(); | |
87 | function bit [ 4:0] get_iotsb_no(bit [7:0] busid, bit va_bit63 ); | |
88 | function bit [63:0] get_sun4v_tsb(bit [4:0] iotsb_no ); | |
89 | function bit [63:0] get_iotte(bit [38:0] iotte_pa ); | |
90 | ||
91 | task set_msi(bit a_msi ) { msi = a_msi; } | |
92 | ||
93 | } | |
94 | ||
95 | //-------------------------------------------------------------------- | |
96 | // Method Name: new() | |
97 | // Description: initialize iommu mgr | |
98 | //-------------------------------------------------------------------- | |
99 | task N2fcIommuMgr::new() | |
100 | { | |
101 | get_mmu_cntl_reg(); | |
102 | } | |
103 | ||
104 | ||
105 | //-------------------------------------------------------------------- | |
106 | // Method Name: get_mmu_cntl_reg() | |
107 | // Description: initialize iommu control bits | |
108 | //-------------------------------------------------------------------- | |
109 | task N2fcIommuMgr::get_mmu_cntl_reg() | |
110 | { | |
111 | // load up the control bits from the MMU CONTROL reg | |
112 | process_disable = PiuCsrs.IoMmuControl[12]; | |
113 | snoop_en = PiuCsrs.IoMmuControl[10]; | |
114 | cache_mode = PiuCsrs.IoMmuControl[9:8]; | |
115 | busid_sel = PiuCsrs.IoMmuControl[3]; | |
116 | sun4v_en = PiuCsrs.IoMmuControl[2]; | |
117 | bypass_en = PiuCsrs.IoMmuControl[1]; | |
118 | translation_en = PiuCsrs.IoMmuControl[0]; | |
119 | } | |
120 | ||
121 | ||
122 | //-------------------------------------------------------------------- | |
123 | // Method Name: get_physical_address | |
124 | // Description: return physical address, and whether it is valid | |
125 | //-------------------------------------------------------------------- | |
126 | function bit N2fcIommuMgr::get_physical_address( bit [63:0] va, | |
127 | var bit [39:0] pa, | |
128 | bit [7:0] busid, | |
129 | bit dmawr ) | |
130 | { | |
131 | get_physical_address = 0; | |
132 | if (is_bypass_mode(va)) { | |
133 | pa = va[39:0]; | |
134 | get_physical_address = 1; | |
135 | } | |
136 | else if (is_sun4u_mode(va)) { | |
137 | printf("N2fcIommuMgr::get_physical_address sun4u mode support not ready yet, assumming V==R %0h\n", va); | |
138 | pa = va[39:0]; | |
139 | get_physical_address = 1; | |
140 | } | |
141 | else if (is_sun4v_mode(va)) { | |
142 | get_physical_address = get_sun4v_pa(va, pa, busid, dmawr); | |
143 | } | |
144 | else { | |
145 | printf("N2fcIommuMgr::get_physical_address %0h is not bypass, sun4u or sun4v. Probably an error.\n", va); | |
146 | } | |
147 | } | |
148 | ||
149 | //-------------------------------------------------------------------- | |
150 | // Method Name: get_sun4v_pa | |
151 | // Description: perform sun4v translation to get physical address | |
152 | //-------------------------------------------------------------------- | |
153 | function bit N2fcIommuMgr::get_sun4v_pa( bit [63:0] va, | |
154 | var bit [39:0] pa, | |
155 | bit [7:0] busid, | |
156 | bit dmawr) | |
157 | { | |
158 | bit [4:0] iotsb_no = get_iotsb_no(busid, va[63]); | |
159 | bit [63:0] tsb; | |
160 | bit [38:0] iotte_pa; | |
161 | bit [38:0] num_pages; | |
162 | bit [63:0] iotte; | |
163 | bit [38:0] byte_offset, byte_offset_mask; | |
164 | ||
165 | get_sun4v_pa = 0; | |
166 | tsb = get_sun4v_tsb(iotsb_no); | |
167 | ||
168 | if (!tsb_valid) { | |
169 | printf("N2fcIommuMgr::get_sun4v_pa tsb valid bit is 0. tsb is %h\n", tsb); | |
170 | return; | |
171 | } | |
172 | ||
173 | if ((tsb_pgsz == 3'b010) || (tsb_pgsz == 3'b100) || (tsb_pgsz == 3'b110) || (tsb_pgsz == 3'b111) ) { | |
174 | printf("N2fcIommuMgr::get_sun4v_pa invalid page size (%h) specified. tsb is %h\n", tsb_pgsz, tsb); | |
175 | return; | |
176 | } | |
177 | ||
178 | // calculate the iotte address | |
179 | iotte_pa = va[39:0] >> (13 + 3*tsb_pgsz); | |
180 | if ( iotte_pa < tsb_offset ) { | |
181 | printf("N2fcIommuMgr::get_sun4v_pa underflow subtracting offset %h from iotte_pa %h\n", tsb_offset, iotte_pa); | |
182 | return; | |
183 | } | |
184 | iotte_pa = iotte_pa - tsb_offset; // this is the Adjusted Page Number | |
185 | ||
186 | num_pages = 32'h400 << tsb_tblsz; // 11'b100_0000_0000 << tsb_tblsz; | |
187 | if ( iotte_pa > num_pages) { | |
188 | printf("N2fcIommuMgr::get_sun4v_pa adjusted page number (%h) out of range: num pages %h\n", iotte_pa, num_pages); | |
189 | return; | |
190 | } | |
191 | ||
192 | iotte_pa = (iotte_pa << 3) + tsb_pa; | |
193 | ||
194 | // get the iotte from dram memory | |
195 | iotte = get_iotte(iotte_pa); | |
196 | ||
197 | if ( !iotte_valid ) { | |
198 | printf("N2fcIommuMgr::get_sun4v_pa iotte valid bit is not 1. iotte is %h @ %h\n", iotte, iotte_pa); | |
199 | return; | |
200 | } | |
201 | ||
202 | if ( !iotte_write && dmawr ) { | |
203 | printf("N2fcIommuMgr::get_sun4v_pa write bit is 0 for dma write. iotte is %h @ %h\n", iotte, iotte_pa); | |
204 | return; | |
205 | } | |
206 | ||
207 | if ( iotte_keyvld ) { | |
208 | printf("N2fcIommuMgr::get_sun4v_pa KEY_VLD not supportted yet. iotte is %h @ %h\n", iotte, iotte_pa); | |
209 | //return; | |
210 | } | |
211 | ||
212 | // or the lower bits of the va with the iotte_datapa, and we're done! | |
213 | byte_offset_mask = (1 << (13 + 3*tsb_pgsz)) - 1; | |
214 | byte_offset = va & byte_offset_mask; | |
215 | pa = iotte_datapa | byte_offset; | |
216 | printf("N2fcIommuMgr::get_sun4v_pa va %0h => pa %0h\n", va, pa); | |
217 | get_sun4v_pa = 1; | |
218 | } | |
219 | ||
220 | //-------------------------------------------------------------------- | |
221 | // Method Name: is_bypass_mode | |
222 | // Description: return 1 if va is a bypass address and bypass is enabled | |
223 | // If this is an MSI address, then | |
224 | // bypass does not have to be enabled). | |
225 | //-------------------------------------------------------------------- | |
226 | function bit N2fcIommuMgr::is_bypass_mode(bit [63:0] va) | |
227 | { | |
228 | if ((bypass_en || msi) && (va[63:39] == 25'h1fff800)) | |
229 | is_bypass_mode = 1; | |
230 | else | |
231 | is_bypass_mode = 0; | |
232 | } | |
233 | ||
234 | //-------------------------------------------------------------------- | |
235 | // Method Name: is_sun4u_mode | |
236 | // Description: return 1 if va is a virtual address and sun4u is enabled | |
237 | //-------------------------------------------------------------------- | |
238 | function bit N2fcIommuMgr::is_sun4u_mode(bit [63:0] va) | |
239 | { | |
240 | if (translation_en && !sun4v_en && (va[63:32] == 32'h0)) | |
241 | is_sun4u_mode = 1; | |
242 | else | |
243 | is_sun4u_mode = 0; | |
244 | } | |
245 | ||
246 | //-------------------------------------------------------------------- | |
247 | // Method Name: is_sun4v_mode | |
248 | // Description: return 1 if va is a virtual address and sun4v is enabled | |
249 | //-------------------------------------------------------------------- | |
250 | function bit N2fcIommuMgr::is_sun4v_mode(bit [63:0] va) | |
251 | { | |
252 | if (translation_en && sun4v_en && (va[62:40] == 23'h000000)) | |
253 | is_sun4v_mode = 1; | |
254 | else | |
255 | is_sun4v_mode = 0; | |
256 | } | |
257 | ||
258 | ||
259 | //-------------------------------------------------------------------- | |
260 | // Method Name: get_iotsb_no | |
261 | // Description: return the sunv4 iotsb number based on the busid select, | |
262 | // the busid, and VA[63] | |
263 | //-------------------------------------------------------------------- | |
264 | function bit [4:0] N2fcIommuMgr::get_iotsb_no(bit [7:0] busid, | |
265 | bit va_bit63 ) | |
266 | { | |
267 | bit [ 3:0] dev2iotsb_reg_no = 0; | |
268 | bit [ 2:0] iotsb_no = 0; | |
269 | bit [63:0] temp_dev2iotsb_reg; | |
270 | ||
271 | if (busid_sel) { | |
272 | '{dev2iotsb_reg_no,iotsb_no} = {va_bit63,busid[5:0]}; | |
273 | } | |
274 | else { | |
275 | '{dev2iotsb_reg_no,iotsb_no} = {va_bit63,busid[6:1]}; | |
276 | } | |
277 | ||
278 | temp_dev2iotsb_reg = PiuCsrs.IoMmuDev2Iotsb[dev2iotsb_reg_no]; | |
279 | get_iotsb_no = temp_dev2iotsb_reg[((iotsb_no+1)*8)-4:(iotsb_no*8)]; | |
280 | } | |
281 | ||
282 | ||
283 | //-------------------------------------------------------------------- | |
284 | // Method Name: get_sun4v_tsb | |
285 | // Description: return the sunv4 tsb, also break it up into fields | |
286 | //-------------------------------------------------------------------- | |
287 | function bit [63:0] N2fcIommuMgr::get_sun4v_tsb(bit [4:0] iotsb_no ) | |
288 | { | |
289 | bit [63:0] tsb = PiuCsrs.IoMmuIoTsbDesc[iotsb_no]; | |
290 | ||
291 | tsb_valid = tsb[63]; | |
292 | tsb_pa = {tsb[59:34],13'b0}; | |
293 | tsb_offset = tsb[33:7]; | |
294 | tsb_pgsz = tsb[6:4]; | |
295 | tsb_tblsz = tsb[3:0]; | |
296 | ||
297 | get_sun4v_tsb = tsb; | |
298 | } | |
299 | ||
300 | //-------------------------------------------------------------------- | |
301 | // Method Name: get_iotte | |
302 | // Description: return the iotte, also break it up into fields | |
303 | //-------------------------------------------------------------------- | |
304 | function bit [63:0] N2fcIommuMgr::get_iotte(bit [38:0] iotte_pa ) | |
305 | { | |
306 | //bit [63:0] iotte = gMem.read_mem(iotte_pa); | |
307 | bit [63:0] iottele, iotte; | |
308 | SparseMem.ReadMem(iotte_pa, iottele, 8'hff); | |
309 | // ReadMem returns data in little endian format, so do byte swap | |
310 | // so that it maskes sense | |
311 | iotte = {iottele[7:0],iottele[15:8],iottele[23:16],iottele[31:24], | |
312 | iottele[39:32],iottele[47:40],iottele[55:48],iottele[63:56]}; | |
313 | iotte_valid = iotte[0]; | |
314 | iotte_write = iotte[1]; | |
315 | iotte_datapa = {iotte[38:13],13'b0}; | |
316 | iotte_fnm = iotte[5:3]; | |
317 | iotte_devkey = iotte[63:48]; | |
318 | iotte_keyvld = iotte[2]; | |
319 | ||
320 | get_iotte = iotte; | |
321 | } | |
322 |