Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / n2_piu / sam_piu.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: sam_piu.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21#include "sam_piu.h"
22#include "dev_registry.h"
23
24extern devRegistry * samDevs;
25
26static const char *n2piu_help = "SAM N2 NCU module\n\
27Sysconf format is :\n\
28sysconf n2_piu <instance_name> ncu=<ncu name>\n\
29For UI help type <instance name>\n\
30For module specific info type \"modinfo <instance name>\"";
31
32
33static int access_piu(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, \
34 uint32_t size, uint64_t* buf, uint8_t bytemask){
35 samPiu * sp = (samPiu *)obj;
36 return sp->handlePio(cpuid,paddr,wr,size,buf,bytemask);
37}
38
39int n2piu_ui_cmd(void * obj, int argc, char * argv[]){
40 samPiu * i = (samPiu *)obj;
41 i->handle_ui(argc, argv);
42 return 0;
43}
44
45
46Module * Module::create(const char *_modname, const char *_instance_name){
47 return new samPiu(_modname, _instance_name);
48}
49
50samPiu::samPiu(const char *_modname, const char *_instance_name)
51 : Module(_modname, _instance_name){
52
53 piuModel.proc_type_namep = strdup("n2");
54 piuModel.config_devp = 0;
55 piuModel.config_procp = 0;
56 piuModel.sam_piu = (void*)this;
57 /*
58 * init PIU CSR with power on reset
59 */
60 piu_init_csr(&piuModel);
61
62 /*
63 * init error lookup table
64 */
65 piu_init_error_list();
66
67 primary_bus_no = 0;
68 secondary_bus_no = 0;
69 subordinate_bus_no = 0xff;
70 device = 0;
71 function = 0;
72 bus = ncu = 0;
73 busMod = ncuMod = 0;
74 busIf = 0;
75 ncuIf = 0;
76
77 N2_PIU_VERSION = strdup("1.0");
78
79 for(int i = 0; i < 64; i++)
80 pendingIntr[i] = false;
81 assert(pthread_mutex_init(&intxMutex,NULL)==0);
82 assert(pthread_mutex_init(&pendIntMutex,NULL)==0);
83 assert(pthread_mutex_init(&piuMutex,NULL)==0);
84 for (int i = 0; i< 32; i++)
85 assert(pthread_mutex_init(&msiMutex[i],NULL)==0);
86
87 mmi_register_instance_cmd(getInstance(),n2piu_help,n2piu_ui_cmd);
88
89 assert(pthread_mutex_init(&ncuMutex,NULL)==0);
90 event_fire_time = 0;
91}
92
93const char * Module::get_help_string(){
94 return n2piu_help;
95}
96
97const char * samPiu::get_help(){
98 return Module::get_help_string();
99}
100
101const char * samPiu::get_version(){
102 return N2_PIU_VERSION;
103}
104void samPiu::modinfo(){
105 printf("SAM-Legion PIU module\n");
106 printf("IOMAP a) base<%llx> size<%llx>\n",PIU_CSR_BASE,PIU_CSR_SIZE);
107 printf(" b) base<%llx> size<%llx>\n",PIU_PCIE_BASE,PIU_PCIE_SIZE);
108 printf("pri_bus <%d>, sec_bus<%d>, device<%d>, function<%d>\n",\
109 primary_bus_no, secondary_bus_no, device, function );
110 return;
111}
112
113bool samPiu::parse_arg(const char *arg){
114 if (argval("bus", arg, &bus)){
115 debug_more("%s: bus = %s\n", instance_name, bus);
116 return true;
117 }else if (argval("ncu", arg, &ncu)){
118 debug_more("%s: ncu = %s\n", instance_name, ncu);
119 return true;
120 }
121 return false;
122}
123
124bool samPiu::check_args(){
125 if(bus == 0){
126 debug_err("%s: ERROR: must specify downstream pcie bus name\n",getName());
127 return false;
128 }
129 return true;
130}
131
132
133void samPiu::module_added(mmi_instance_t i, const char *target_name){
134 if(bus && !strcmp(target_name,bus)){
135 busMod = i;
136 busIf = (pcieBusIf*)mmi_get_interface(i,PCIE_BUS_INTERFACE);
137 if(busIf == 0){
138 debug_err("%s: FATAL ERROR, could not get bus interface for %s\n",getName,bus);
139 exit(0);
140 }
141 busIf->setBridgeIf((genericPcieDevIf*)this);
142 }else if(ncu && !strcmp(ncu,target_name)){
143 ncuMod = i;
144 ncuIf = (n2Ncu*)mmi_get_interface(i,"ncu interface");
145 if(!ncuIf){
146 debug_err("%s: FATAL ERROR, could not get ncu interface for %s\n",getName,ncu);
147 exit(0);
148 }
149 }
150 return;
151}
152
153void samPiu::module_deleted(mmi_instance_t i, const char *target_name){
154 if(bus && !strcmp(bus,target_name)){
155 busMod = 0;
156 busIf = 0;
157 bus = 0;
158 }
159 return;
160}
161
162void *samPiu::get_interface(const char *name){
163 // no one should be calling this interface, since the bus's bridge interface
164 // is set by the bridge itself (for PIU in module_added)
165 if( !strcmp(name,GENERIC_PCIE_DEV_INTERFACE) )
166 return (genericPcieDevIf*)this;
167 return 0;
168}
169
170
171void samPiu::init_done(){
172 mmi_map_physio(PIU_CSR_BASE,PIU_CSR_SIZE,(void*)this,access_piu);
173 mmi_map_physio(PIU_PCIE_BASE,PIU_PCIE_SIZE,(void*)this,access_piu);
174
175 if(!restore_v5_dump()){
176 mmi_register_event(1000,samPiu_1ms_callback,(void*)this,0);
177 event_fire_time = 1000;
178 }
179 return;
180}
181
182void samPiu::timer_callback(){
183 // register a callback that fires every 10ms. Looks for any nacked
184 // interrupt by NCU and sends it if one exists. If the interrupt is
185 // nacked again, try it again later.
186
187
188 pthread_mutex_lock(&ncuMutex);
189
190 if(!irql.empty()){
191 VCPU_InterruptRequest * ir = irql.front();
192 int stat = ncuIf->sendPiuMondo(ir);
193
194 if(stat == -1){
195 // don't really expect this to happen, but if it does, just try again
196 debug_more("%s:interrupt nacked by NCU after 1ms delay !!\n",getName());
197 goto out;
198 }
199 debug_more("%s 1ms cb: sent interrupt to itid %d\n",getName(),irql.front()->itid);
200 // remove the irq and delete it since the interrupt has been sent
201 irql.pop_front();
202 delete ir;
203 }
204out:
205 event_fire_time = mmi_get_time()+1000;
206 mmi_register_event(event_fire_time,samPiu_1ms_callback,(void*)this,0);
207
208 pthread_mutex_unlock(&ncuMutex);
209}
210
211void samPiu_1ms_callback(void * obj, void * ){
212 samPiu * t = (samPiu*) obj;
213 t->timer_callback();
214}
215
216pcieCompleter samPiu::devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode,\
217 void * data, uint16_t length, uint8_t be, uint16_t reqId, tlp_X args, SAM_DeviceId *id){
218
219
220 // XXX place the dma record identifier 'id' here XXX //
221
222 int count = 0;
223 dev_access_t type = wr?DA_Store:DA_Load;
224 dev_mode_t md = mode == mem_addr32?PCIE_IS32:PCIE_IS64;
225
226 for(int i = 0; i < 8; i++)
227 if(be >> i & 0x1)
228 count++;
229 if(length > 2)
230 count += (length - 2) * 4;
231
232 uint8_t * data_ptr = (uint8_t*)data;
233
234 //debug_more("%s:devif_memAccess %s,length 0x%x, be 0x%x, count 0x%x\n", \
235 getName(),wr?"write":"read",length,be,count);
236
237 debug_more("%s: device %s DMA %s 0x%x bytes\n",getName(),samDevs->getName(*id),wr?"out":"in",count);
238
239 bool ret = true;
240 while(count){
241 // break down the requests on 8K boundary (smallest page size)
242 int bytes_in_page = (8*1024) - addr % (8*1024);
243 int bytes_to_transfer = count > bytes_in_page ? bytes_in_page:count;
244 ret &= piu_dma_access(&piuModel,addr,data_ptr,bytes_to_transfer,reqId,type,md,*id);
245 addr += bytes_to_transfer;
246 data_ptr += bytes_to_transfer;
247 count -= bytes_to_transfer;
248 }
249
250 if(ret)
251 return pcieCompleter(SC,getReqId());
252 else
253 return pcieCompleter(CA,getReqId()); // XXX ???
254}
255
256pcieCompleter samPiu::devif_msgAccess(uint8_t messageCode, msgRouting route, \
257 uint64_t tarIdOrAddr, uint16_t reqId, \
258 void * data, uint16_t length, \
259 uint16_t vendorId, uint32_t vendor_data, tlp_X args, SAM_DeviceId *id){
260
261 // handle intx messages
262
263 // XXX create trace records for device 'id' INTX interrupts here XXX //
264
265
266 debug_more("%s: device %s interrupt %s\n",getName(),samDevs->getName(*id),messageCode<=MSG_Assert_INTD ? "assert":"deassert");
267
268 switch(messageCode){
269 case MSG_Assert_INTA:
270 setIntx(reqId & 0xff, 0, true);
271 piu_assert_intx(&piuModel,0,reqId >> 3 & 0x1f);
272 break;
273 case MSG_Assert_INTB:
274 setIntx(reqId & 0xff, 1, true);
275 piu_assert_intx(&piuModel,1,reqId >> 3 & 0x1f);
276 break;
277 case MSG_Assert_INTC:
278 setIntx(reqId & 0xff, 2, true);
279 piu_assert_intx(&piuModel,2,reqId >> 3 & 0x1f);
280 break;
281 case MSG_Assert_INTD:
282 setIntx(reqId & 0xff, 3, true);
283 piu_assert_intx(&piuModel,3,reqId >> 3 & 0x1f);
284 break;
285 case MSG_Deassert_INTA:
286 setIntx(reqId & 0xff, 0, false);
287 piu_deassert_intx(&piuModel,0,reqId >> 3 & 0x1f);
288 break;
289 case MSG_Deassert_INTB:
290 setIntx(reqId & 0xff, 1, false);
291 piu_deassert_intx(&piuModel,1,reqId >> 3 & 0x1f);
292 break;
293 case MSG_Deassert_INTC:
294 setIntx(reqId & 0xff, 2, false);
295 piu_deassert_intx(&piuModel,2,reqId >> 3 & 0x1f);
296 break;
297 case MSG_Deassert_INTD:
298 setIntx(reqId & 0xff, 3, false);
299 piu_deassert_intx(&piuModel,3,reqId >> 3 & 0x1f);
300 break;
301 default:
302 debug_err("%s:devif_msgAccess: message code %x not supported yet\n", \
303 getName(),messageCode);
304 }
305 return SIM_OK;
306}
307
308
309int samPiu::handlePio(uint32_t cpuid,uint64_t paddr, mmi_bool_t wr, \
310 uint32_t size, uint64_t* buf, uint8_t bytemask){
311
312 pcieCompleter s;
313 maccess_t memop;
314
315 switch(size){
316 case 1:
317 memop = MA_Size8;
318 break;
319 case 2:
320 memop = MA_Size16;
321 break;
322 case 4:
323 memop = MA_Size32;
324 break;
325 case 8:
326 memop = MA_Size64;
327 break;
328 default:
329 assert(0);
330 }
331
332 switch(wr){
333 case false:
334 memop = (MACCESS)(memop | MA_Ld);
335 break;
336 case true:
337 memop = (MACCESS)(memop | MA_St);
338 break;
339 default:
340 assert(0);
341 }
342
343 if(wr && (paddr == PIU_CSR_BASE + PIU_DMU_PCIE_CONFREG_OFFSET)){
344 secondary_bus_no = (*buf) >> 24 & 0xff;
345 primary_bus_no = (*buf) >> 8 & 0xff;
346 device = (*buf) >> 3 & 0x1f;
347 function = (*buf) & 0x7;
348 }
349
350 if(!wr)
351 *buf = 0;
352
353 // hook for target of the PIO
354 SAM_DeviceId target = 0;
355 s = piu_cpu_access(&piuModel,paddr,memop,buf,&target);
356
357 debug_more("%s: accessed %s at 0x%llx\n",getName(),samDevs->getName(target),paddr);
358
359 if(s.status == SC)
360 return 0;
361 return -1;
362}
363
364
365#include "vcpu.h"
366void samPiu::sendMondo(pcie_mondo_t *m){
367
368 VCPU_InterruptRequest r;
369 r.itid = m->thread_id;
370 r.isid = getReqId();
371
372 r.data[0] = m->data[0];
373 r.data[1] = m->data[1];
374
375 // assume only a single cpu (64 strand) configuration.
376
377 int stat = ncuIf->sendPiuMondo(&r);
378
379 if(stat == -1){
380 debug_more("%s:interrupt nacked by NCU\n",getName());
381 pthread_mutex_lock(&ncuMutex);
382 VCPU_InterruptRequest *ir = new VCPU_InterruptRequest;
383 *ir = r;
384 irql.push_back(ir);
385 pthread_mutex_unlock(&ncuMutex);
386 return;
387 }
388
389 debug_more("%s: sent interrupt to strand %d, return stat %d\n",getName(),m->thread_id,stat);
390 //printf("%s: sent interrupt to strand %d, return stat %d\n",getName(),m->thread_id,stat);
391}
392
393void samPiu::handle_ui(int argc, char * argv[]){
394 if(argc == 1){
395 ui_cmd_usage();
396 return;
397 }else if(!strcmp(argv[1],"dump")){
398 FILE * fp = stderr;
399 if(argv[2]){
400 fp = fopen(argv[2],"w");
401 if(!fp){
402 printf("%s dump: error opening file <%s>\n",getName(),argv[2]);
403 fp = stderr;
404 }
405 }
406 dump(fp);
407 if( fp != stderr )
408 fclose(fp);
409 }else if(!strcmp(argv[1],"restore")){
410 FILE * fp;
411 if(argv[2]){
412 fp = fopen(argv[2],"r");
413 if(fp){
414 restore(fp);
415 fclose(fp);
416 }else
417 printf("%s restore: error opening file <%s>\n",getName(),argv[2]);
418 }else
419 printf("%s restore: no restore filename specified\n",getName());
420 }else if(!strcmp(argv[1],"debug")){
421 if(argv[2]){
422 debug_level = atoi(argv[2]);
423 printf("%s: set debug level to %d\n",getName(),debug_level);
424 }else
425 printf("%s: current debug level %d\n",getName(),debug_level);
426 }else
427 debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]);
428 return;
429}