Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: N2fcilupeuIngressDmaRdStr.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 | extern integer fc_peu_dma_ptr; | |
36 | ||
37 | class N2fcDmaRdPEUStr extends PEUStrBase { | |
38 | ||
39 | local bit [63:0] N2fcSAddr; | |
40 | local bit [63:0] N2fcEAddr; | |
41 | local bit N2fcAddrSpecified; | |
42 | local bit [31:0] length; | |
43 | local bit [31:0] dat; | |
44 | ||
45 | integer f_len; // The packet's payload length | |
46 | bit[3:0] f_firstDWBE; // It's "first DWBE" field | |
47 | bit[3:0] f_lastDWBE; // It's "last DWBE" field | |
48 | integer f_bndy; // The address' boundary | |
49 | bit f_lenSpecified; // Was a length specified? | |
50 | bit f_firstSpecified; // Was a "firstDWBE" specified? | |
51 | bit f_lastSpecified; // Was a "lastDWBE" specified? | |
52 | bit f_bndySpecified; // Was an addr bndy specified? | |
53 | bit f_poison; // Is the completion poisoned? | |
54 | bit f_UR; // Is the completion UR? | |
55 | bit f_CA; // Is the completion CA? | |
56 | bit f_INTx; // Do an INTx after completion? | |
57 | bit f_dma_read_lk; // Do a DMA Read Lock | |
58 | bit f_drop_cmpl; // Drop the completion | |
59 | string intx_cmd; | |
60 | N2fcIommuMgr MMU; | |
61 | bit [7:0] bus_id; | |
62 | integer f_tc; // The packet's traffic class | |
63 | ||
64 | task new( PEUTestEnv a_env ) | |
65 | { | |
66 | super.new( a_env ); | |
67 | f_lenSpecified = 0; | |
68 | f_firstSpecified = 0; | |
69 | f_lastSpecified = 0; | |
70 | f_bndySpecified = 0; | |
71 | f_poison = 0; | |
72 | f_UR = 0; | |
73 | f_CA = 0; | |
74 | f_INTx = 0; | |
75 | f_dma_read_lk = 0; | |
76 | f_drop_cmpl = 0; | |
77 | f_tc = -1; | |
78 | MMU = new(); | |
79 | ||
80 | printf ("%0d- N2fcDmaRdPEUStr:new first random # = %0h\n", get_time(LO), random() ); | |
81 | } | |
82 | ||
83 | task SetLen( integer a_len ) | |
84 | { | |
85 | f_len = a_len; | |
86 | f_lenSpecified = 1; | |
87 | } | |
88 | ||
89 | task SetFirstDWBE( bit[3:0] a_dwbe ) | |
90 | { | |
91 | f_firstDWBE = a_dwbe; | |
92 | f_firstSpecified = 1; | |
93 | } | |
94 | ||
95 | task SetLastDWBE( bit[3:0] a_dwbe ) | |
96 | { | |
97 | f_lastDWBE = a_dwbe; | |
98 | f_lastSpecified = 1; | |
99 | } | |
100 | ||
101 | task SetAddrBndy( integer a_bndy ) | |
102 | { | |
103 | f_bndy = a_bndy; | |
104 | f_bndySpecified = 1; | |
105 | } | |
106 | ||
107 | task SetPoisonedPayload() | |
108 | { | |
109 | f_poison = 1; | |
110 | } | |
111 | ||
112 | task SetUC( bit isUR ) | |
113 | { | |
114 | if ( isUR ) | |
115 | f_UR = 1; | |
116 | else | |
117 | f_CA = 1; | |
118 | } | |
119 | ||
120 | task DoIntxAfterCompletion(string cmd) | |
121 | { | |
122 | f_INTx = 1; | |
123 | intx_cmd = cmd; | |
124 | } | |
125 | ||
126 | task SetRdLk() | |
127 | { | |
128 | f_dma_read_lk = 1; | |
129 | } | |
130 | ||
131 | task DropCmpl() | |
132 | { | |
133 | f_drop_cmpl = 1; | |
134 | } | |
135 | ||
136 | ||
137 | task N2fcSetAddr( bit [63:0] i_saddr, bit [63:0] i_eaddr ) | |
138 | { | |
139 | N2fcAddrSpecified = 1; | |
140 | N2fcSAddr = i_saddr; | |
141 | N2fcEAddr = i_eaddr; | |
142 | } | |
143 | ||
144 | ||
145 | task Execute() | |
146 | { | |
147 | bit [63:0] address = 64'b0; // Virtual address | |
148 | bit [39:0] pa = 40'b0; // Physical address | |
149 | bit hdr_4dw; | |
150 | ||
151 | bit[PEC_PCI__HDR] ingressHdr; // The ingress TLP's header | |
152 | integer ingressData; // A payload descriptor | |
153 | bit[7:0] ingressTag; // The tag for the TLP | |
154 | bit[7:0] egressAddr; // The payload's DOU address | |
155 | integer dwTotal; // #DWs required for completion | |
156 | integer dwDone; // #DWs completed so far | |
157 | bit zero_len_read; | |
158 | ||
159 | shadow bit[PEC_PCI__HDR] egressHdr; // The egress TLP's header | |
160 | shadow integer egressData; // The completion payload | |
161 | shadow integer dma_ptr; // dma id | |
162 | ||
163 | if (N2fcAddrSpecified == 1) { | |
164 | address = N2fcSAddr; | |
165 | } | |
166 | else { | |
167 | error ("N2fcDmaRdPEUStr::Execute() : the start and end address must be specifed\n"); | |
168 | } | |
169 | ||
170 | // First, get in line for a DMA tag... | |
171 | f_env.allocDmaTag( ingressTag ); | |
172 | ||
173 | // Then build a TLP | |
174 | if ( f_lenSpecified ) | |
175 | f_env.genIngressRdReq( ingressTag, ingressHdr, ingressData, f_len ); | |
176 | else | |
177 | error ("N2fcDmaRdPEUStr::Execute() : the length must be specifed\n"); | |
178 | ||
179 | // Special case for DMA RD LK | |
180 | if ( f_dma_read_lk ) { | |
181 | ingressHdr[PEC_PCI__TYPE] = PEC_PCI__TYPE_MEM_LK; | |
182 | ingressHdr[PEC_PCI__TC] = 0; | |
183 | ||
184 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLkReq ); | |
185 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLkEP ); | |
186 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPLST_LKUR_2 ); | |
187 | } | |
188 | ||
189 | // set the Traffic Class (for non - DMA RD LK) | |
190 | else if( f_tc != -1 ) { | |
191 | ingressHdr[PEC_PCI__TC] = f_tc; | |
192 | } | |
193 | ||
194 | if( address[63:32] != 32'h00000000 ) { | |
195 | ingressHdr[PEC_PCI__FMT_4DW] = 1; // 4DW hdr fmt, 64-bit address | |
196 | ingressHdr[PEC_PCI__ADDR] = address; | |
197 | } | |
198 | else { | |
199 | ingressHdr[PEC_PCI__FMT_4DW] = 0; // 3DW hdr fmt, 32-bit address | |
200 | ingressHdr[PEC_PCI__ADDR32] = address[31:0]; | |
201 | } | |
202 | ||
203 | printf ("%0d- UDEBUG N2fcDmaRdPEUStr:Execute Address = %0h Byp = %0h, Len = 'd%0d\n", | |
204 | get_time(LO), address, address[63:39], f_len); | |
205 | ||
206 | // ...and set fields as requested | |
207 | // by the caller. | |
208 | ||
209 | if ( f_bndySpecified ) | |
210 | f_env.setAddrBndy( ingressHdr, f_bndy, 4 ); | |
211 | ||
212 | //N2 Set the DWBE after setAddrBndy since it adjusts the DWBE now | |
213 | if ( f_firstSpecified ) | |
214 | ingressHdr[PEC_PCI__FIRST_DWBE] = f_firstDWBE; | |
215 | if ( f_lastSpecified ) | |
216 | ingressHdr[PEC_PCI__LAST_DWBE] = f_lastDWBE; | |
217 | ||
218 | // Send the read-request through the | |
219 | // ingress pipeline. | |
220 | f_env.drivePCIE( ingressHdr, ingressData,*,*,*,*,*,1 ); | |
221 | ||
222 | ||
223 | zero_len_read = (ingressHdr[PEC_PCI__LEN] == 1) && | |
224 | (ingressHdr[PEC_PCI__FIRST_DWBE] == 0) && | |
225 | (ingressHdr[PEC_PCI__LAST_DWBE] == 0) ; | |
226 | bus_id = ingressHdr[ILUPEU_TLP_HDR_REQ_BUS_NUM_BITS]; | |
227 | ||
228 | fork { | |
229 | ||
230 | f_env.MMU.get_mmu_cntl_reg(); | |
231 | if (!MMU.get_physical_address(address, pa, bus_id, 1)) { | |
232 | f_CA = 1; | |
233 | } | |
234 | ||
235 | // get the l2sio_stub lock, to serialize new requests | |
236 | semaphore_get (WAIT, l2sio_stub.reqst_semph_id, 1); | |
237 | ||
238 | // Now send a completion to our original request through the | |
239 | // egress pipeline. | |
240 | if ( f_drop_cmpl ) | |
241 | { | |
242 | // no completion was requested, probably due to | |
243 | // error injection. However, the siu<->l2 monitor needs to | |
244 | // know to expect the RDD and rd return packets. | |
245 | dma_ptr = fc_peu_dma_ptr++; | |
246 | // l2sio_stub.l2_cl_idx = l2sio_stub.l2_cl_idx + 1; | |
247 | fork | |
248 | l2sio_stub.reassemble_dma_pkt("N2fcDmaRdPEUStr::Execute", | |
249 | ingressHdr[PEC_PCI__LEN], | |
250 | address, | |
251 | dma_ptr); | |
252 | join none | |
253 | repeat (1) @(posedge CLOCK); | |
254 | } | |
255 | else if ( f_UR || f_CA ) | |
256 | { | |
257 | printf ("UDEBUG : N2fcDmaRdPEUStr UR or CA\n"); | |
258 | f_env.genEgressCpl( ingressHdr, egressHdr, egressData ); | |
259 | egressHdr[PEC_PCI__FMT_DATA] = 0; | |
260 | egressHdr[PEC_PCI__LEN] = 0; | |
261 | egressHdr[PEC_PCI__CPL_ID] = 0; | |
262 | if ( f_UR ) | |
263 | egressHdr[PEC_PCI__CPL_STATUS] = PEC_PCI__CPL_STATUS_UR; | |
264 | else { | |
265 | egressHdr[PEC_PCI__CPL_STATUS] = PEC_PCI__CPL_STATUS_CA; | |
266 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPLST_CA_2 ); | |
267 | } | |
268 | fork | |
269 | f_env.expectPCIE( egressHdr, egressData, *, 1 ); | |
270 | join none | |
271 | repeat (1) @(posedge CLOCK); | |
272 | } | |
273 | else if ( ingressHdr[PEC_PCI__LEN] > 0 && | |
274 | 4*ingressHdr[PEC_PCI__LEN] <= f_env.getMaxPayloadSize() || | |
275 | f_dma_read_lk) | |
276 | { | |
277 | f_env.genEgressCpl( ingressHdr, egressHdr, egressData ); | |
278 | if ( f_poison ) { | |
279 | f_env.poisonPayload( egressData ); | |
280 | egressHdr[PEC_PCI__EP] = 1; | |
281 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPL_Poison ); | |
282 | } | |
283 | else if ( f_dma_read_lk ) { | |
284 | egressHdr[PEC_PCI__TYPE] = PEC_PCI__TYPE_CPL_LK; | |
285 | egressHdr[PEC_PCI__FMT ] = PEC_PCI__FMT_NO_DATA_3DW; | |
286 | egressHdr[PEC_PCI__LEN] = 0; | |
287 | egressHdr[PEC_PCI__CPL_STATUS] = PEC_PCI__CPL_STATUS_UR; | |
288 | egressHdr[PEC_PCI__BYTECOUNT] = 12'hxxx; //ingressHdr[PEC_PCI__LEN] * 4; | |
289 | egressHdr[PEC_PCI__LOWADDR] = 7'hxx; | |
290 | } | |
291 | egressHdr [PEC_PCI__CPL_ID] = 0; | |
292 | ||
293 | dma_ptr = fc_peu_dma_ptr++; | |
294 | fork | |
295 | f_env.expectPCIE( egressHdr, egressData, *, 1 , dma_ptr); | |
296 | join none | |
297 | repeat (1) @(posedge CLOCK); | |
298 | } | |
299 | // ...or as many as it takes for a | |
300 | // complex ('bulk') request. | |
301 | else | |
302 | { | |
303 | dwTotal = ingressHdr[PEC_PCI__LEN]; | |
304 | if ( dwTotal == 0 ) dwTotal = 1024; | |
305 | dwDone = 0; | |
306 | while( dwTotal > dwDone ) | |
307 | { | |
308 | f_env.genEgressPartialCpl( ingressHdr, egressHdr, egressData, dwDone ); | |
309 | dwDone = dwDone + egressHdr[PEC_PCI__LEN]; | |
310 | if ( f_poison ) { | |
311 | f_env.poisonPayload( egressData ); | |
312 | egressHdr[PEC_PCI__EP] = 1; | |
313 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPL_Poison ); | |
314 | } | |
315 | ||
316 | egressHdr [PEC_PCI__CPL_ID] = 0; | |
317 | ||
318 | dma_ptr = fc_peu_dma_ptr++; | |
319 | fork | |
320 | f_env.expectPCIE( egressHdr, egressData, *, 1, dma_ptr ); | |
321 | join none | |
322 | @(posedge CLOCK); | |
323 | } | |
324 | } | |
325 | ||
326 | if ( f_poison ) { | |
327 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPL_Poison ); | |
328 | } | |
329 | if ( f_CA ) { | |
330 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_CPLST_CA_2 ); | |
331 | } | |
332 | // The environment frees the completion's DOU space | |
333 | // So we only have to free the tag. | |
334 | f_env.freeDmaTag( ingressTag ); | |
335 | ||
336 | // release the l2sio_stub lock | |
337 | semaphore_put (l2sio_stub.reqst_semph_id, 1); | |
338 | ||
339 | // Does the cpu want an interrupt when the DMARD is done? | |
340 | if (f_INTx) { | |
341 | N2fcIntxStr intxStr; | |
342 | ||
343 | // wait for read completion | |
344 | wait_child(); | |
345 | ||
346 | // now do an INTx ASSERT command to let the cpu know the dmard is completed | |
347 | intxStr = new(f_env, intx_cmd, "ASSERT"); | |
348 | } | |
349 | ||
350 | } join none | |
351 | ||
352 | } /* end Execute */ | |
353 | ||
354 | } /* end DmaRdPECStr class*/ |