Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / pcie_dev.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: pcie_dev.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 "pcie.h"
22#include "arg.h"
23
24
25genericPcieDev::genericPcieDev(confHeaderType htype){
26 confSpace = new pciConfSpace(0x1000);
27 //initConf(htype);
28
29 busName = 0;
30 busIf = 0;
31 device = -1;
32 function = -1;
33 msiCapOffset = -1;
34 pciExpCapOffset = -1;
35 aerCapOffset = -1;
36 aerCapable = false;
37 msgDB = new pciExpMsgUtility();
38 errDB = new pciExpErrUtility();
39}
40
41genericPcieDev::genericPcieDev(){
42confSpace = new pciConfSpace(0x1000);
43
44 busName = 0;
45 busIf = 0;
46 device = -1;
47 function = -1;
48 msiCapOffset = -1;
49 pciExpCapOffset = -1;
50 aerCapOffset = -1;
51 aerCapable = false;
52 msgDB = new pciExpMsgUtility();
53 errDB = new pciExpErrUtility();
54}
55
56bool genericPcieDev::mapSpace(pcie_space space, uint64_t base, uint64_t size){
57 assert(busIf);
58 return busIf->busif_map(devif_getName(),space, base, size);
59}
60bool genericPcieDev::unmapSpace(pcie_space space,uint64_t base){
61 assert(busIf);
62 return busIf->busif_unmap(devif_getName(),space, base);
63}
64
65pcieCompleter genericPcieDev::devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode, void * data,\
66 uint16_t length, uint8_t be, uint16_t reqId, tlp_X args, SAM_DeviceId *id){
67 if(id)
68 *id = (dynamic_cast<Module*>(this))->samId;
69 return pcieCompleter(UR,getId());
70}
71
72pcieCompleter genericPcieDev::devif_ioAccess(bool wr, uint32_t addr, void * data, uint8_t be, \
73 uint16_t reqId, uint16_t length, tlp_X args, SAM_DeviceId *id){
74 if(id)
75 *id = (dynamic_cast<Module*>(this))->samId;
76 return pcieCompleter(UR,getId());
77}
78
79pcieCompleter genericPcieDev::devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, \
80 void * data, uint16_t length, \
81 uint16_t vendorId, uint32_t vendor_data, tlp_X args, SAM_DeviceId *id){
82 if(id)
83 *id = (dynamic_cast<Module*>(this))->samId;
84 return pcieCompleter(UR,getId());
85}
86
87pcieCompleter genericPcieDev::devif_confAccess(bool wr, uint32_t offset, void * data, \
88 uint8_t be,uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args, SAM_DeviceId *id){
89
90 assert(offset <= 0xfff);
91 assert((be & 0xf0) == 0);
92 assert(length == 1);
93
94 if(id)
95 *id = (dynamic_cast<Module*>(this))->samId;
96
97 confSpace->confAccessByteE(offset, wr, (uint64_t *)data, be);
98 devif_confAccessCb(wr,offset,be);
99 return pcieCompleter(SC,getId());
100}
101
102
103// parse the busname, device, functions args
104
105
106bool genericPcieDev::dev_parse_arg(const char *arg){
107 if (argval("bus", arg, &busName)) {
108 Debug_more("%s: bus=<%s>\n", Here, busName);
109 } else if (argval("dev", arg, &device)) {
110 Debug_more("%s: dev=%d\n", Here, device);
111 } else if (argval("fun", arg, &function)) {
112 Debug_more("%s: fun=%d\n", Here, function);
113 }else{
114 Debug_err("%s: WARNING: unrecognized arg '%s'\n", Here, arg);
115 return false;
116 }
117 return true;
118}
119
120
121bool
122genericPcieDev::dev_check_args(){
123 if (!busName) {
124 Debug_err("%s: ERROR: must specify a PCI bus\n",devif_getName());
125 return false;
126 }else if(device == -1){
127 Debug_err("%s: ERROR: must specify device number\n", devif_getName());
128 return false;
129 }else if(function == -1){
130 Debug_err("%s: ERROR: must specify function number\n", devif_getName());
131 return false;
132 }
133 return true;
134}
135
136void
137genericPcieDev::dev_init_done(int dl){
138 confSpace->set_debug_level(dl);
139 pciDebug::set_debug_level(dl);
140 if(aerCapOffset != -1)
141 aerCapable = true;
142}
143
144
145void genericPcieDev::pcieDevInfo(){
146 printf("bus=<%s> dev=%d fun=%d\n",busName,device,function);
147 printf("configuration space reg info:\n");
148 confSpace->print();
149}
150
151
152
153// XXX the functions below "may" need some changes depending upon specific
154// PCIE needs. Need to do more research to be sure.
155bool genericPcieDev::dump(const char * dirname,const char *file){
156 char *filename;
157 FILE *fp;
158
159 if(file){
160 filename = new char[strlen(dirname) + strlen(file) + 6];
161 sprintf(filename,"%s/%s.pcie",dirname,file);
162
163 fp = fopen(filename,"w");
164 if(!fp){
165 Debug_err("%s pci dump. fopen failed for %s\n",devif_getName(), filename);
166 return false;
167 }
168 }else
169 fp = stderr;
170
171 pciConfReg * cr;
172
173 for(int offset = 0; offset < 0x1000;){
174 if(offset == PCI_CONF_COMM){
175 offset += 2;
176 continue;
177 }
178 cr = confSpace->getConfReg(offset);
179 if(!cr) // hole
180 offset++;
181 else{
182 if (cr->size == 8) {
183 assert(offset >= PCI_CONF_BASE0 && offset <= PCI_CONF_BASE5);
184
185 pcieBaseAddrReg *bar = (pcieBaseAddrReg *)cr;
186 fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s %s\n",\
187 offset,bar->getVal(),bar->getMask(),4,bar->name, "Low");
188 fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s %s\n",\
189 offset+4,bar->val_32To63,bar->mask_32To63,4,bar->name, "High");
190 }
191 else {
192 fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s\n",\
193 offset,cr->getVal(),cr->getMask(),cr->size,cr->name);
194 }
195 offset += cr->size;
196 }
197 }
198
199 cr = confSpace->getConfReg(PCI_CONF_COMM);
200 fprintf(fp,"0x%08lx 0x%08lx 0x%08lx 0x%x %s\n",\
201 PCI_CONF_COMM,cr->getVal(),cr->getMask(),cr->size,cr->name);
202
203 if(fp != stderr)
204 fclose(fp);
205
206 return true;
207}
208
209bool
210genericPcieDev::dev_module_added(const char *target_name){
211 if (busName && !strcmp(busName, target_name)) {
212 busName = target_name;
213 mmi_instance_t mod = mmi_get_instance(busName);
214 busIf = (pcieBusIf*)mmi_get_interface(mod, PCIE_BUS_INTERFACE);
215 if (!busIf) {
216 Debug_err("%s: ERROR: can't find interface for PCIE bus <%s>\n", Here, busName);
217 return false;
218 }else if(!busIf->busif_addDevice(devif_getName(), device, function)) {
219 Debug_err("%s: ERROR: could not add tp PCIE bus <%s>\n", Here, busName);
220 return false;
221 }else{
222 Debug_info("%s: bus <%s> connected: busif=%p\n", Here, busName, busIf);
223 }
224 }
225 return true;
226}
227
228
229bool
230genericPcieDev::dev_module_deleted(const char *target_name){
231 if (busName && !strcmp(busName, target_name)) {
232 busName = 0;
233 busIf = 0;
234 Debug_info("%s: bus <%s> disconnected\n", Here, busName);
235 }
236 return true;
237}
238
239
240
241// to be called after initPci() has been called
242bool genericPcieDev::restore(const char * dirname,const char * file){
243 char *filename = new char[strlen(dirname) + strlen(file) + 6];
244 sprintf(filename,"%s/%s.pcie",dirname,file);
245 char name[128];
246
247 char buf[1024];
248
249 int off, size;
250 uint32_t val;
251
252 FILE *fp = fopen(filename,"r");
253
254 if(!fp){
255 Debug_err("%s pci restore. fopen failed for %s\n",devif_getBusName(), filename);
256 return false;
257 }
258
259 pciConfReg * cr;
260 char str[100];
261 bool is_commd = false;
262
263 for(uint32_t offset = 0; offset < 0x1000;){
264 if(offset == PCI_CONF_COMM){
265 offset += 2;
266 continue;
267 }
268 cr = confSpace->getConfReg(offset);
269 if(!cr) // hole
270 offset++;
271 else{
272 uint8_t byte_offset = 0;
273 do {
274 fgets(buf,1024,fp);
275 char * csr_offset = strtok(buf," ");
276 off = strtoul(csr_offset,0,0);
277 char * csr_value = strtok(0," ");
278 val = strtoul(csr_value,0,0);
279
280 if (off != offset) {
281 // if mis-match, it must be restoring from an old chechpoint,
282 // and this must be the command register, which always comes last.
283 assert(off == PCI_CONF_COMM);
284 printf("can't find PCIE register (offset = 0x%u) in %s.pcie, default value is used\n", offset, file);
285 is_commd = true;
286 break;
287 }
288
289 char * csr_mask = strtok(0," ");
290 char * csr_size = strtok(0," ");
291 size = strtoul(csr_size,0,0);
292 cr->write(val,byte_offset,size);
293 devif_confAccessCb(true,offset,size);
294 offset += size;
295 byte_offset += size;
296 } while (byte_offset < cr->size);
297
298 if (is_commd)
299 break;
300 }
301 }
302
303 // restore the command register
304 cr = confSpace->getConfReg(PCI_CONF_COMM);
305 if (!is_commd)
306 fscanf(fp,"0x%x\t0x%x\t%s\n",&off,&val,name);
307 cr->write(val,0,cr->size);
308 devif_confAccessCb(true,PCI_CONF_COMM,cr->size);
309 fclose(fp);
310
311 return true;
312}
313
314
315
316
317void genericPcieDev::addMsiCap(uint8_t next_ptr, uint16_t offset, uint16_t reset_val){
318 //if(msiCapOffset != -1){
319 // printf("can;t have more than 1 MSI capability/function");
320 // return;
321 //}
322 msiCapOffset = offset;
323 confSpace->addConfReg(new pciConfReg(" msi cap id ", 1, msiCapId, 0x0, 0x0), offset);
324 confSpace->addConfReg(new pciConfReg(" msi next ptr ", 1, next_ptr, 0x0,0x0), offset + MSI_NEXTPTR_OFFSET);
325 confSpace->addConfReg(new msiCapMsgCntrl(reset_val),offset + MSI_MSGCNTRL_OFFSET);
326 confSpace->addConfReg(new pciConfReg(" msi addr0 ", 4, 0x0, 0xfffffffc, 0), offset + MSI_MSGADDR0_OFFSET);
327
328 bool is64bit = (reset_val >> msiCapMsgCntrl::is64bitAddrCapable_bp) & 1;
329 if(is64bit){
330 confSpace->addConfReg(new pciConfReg(" msi addr1 ", 4, 0x0, 0xffffffff), offset + MSI_MSGADDR1_OFFSET);
331 confSpace->addConfReg(new pciConfReg(" msi data ", 2, 0x0, 0xffff), offset + MSI_MSGDATA64_OFFSET);
332 }else
333 confSpace->addConfReg(new pciConfReg(" msi data ", 2, 0x0, 0xffff), offset + MSI_MSGDATA32_OFFSET);
334 return;
335 }
336
337void genericPcieDev::addAERCap(uint16_t capOffset, uint16_t nexCapPtr){
338 char reg_descr[100];
339 aerCapOffset = capOffset;
340 snprintf(reg_descr,100,"%s pciExpEnhncdCapHdr",devif_getName());
341 confSpace->addConfReg(new pciExpEnhncdCapHdr(0x10001 | nexCapPtr << pciExpEnhncdCapHdr::nxtCapOffset_rbp,0x0,0x0,reg_descr),capOffset);// AER capability, next ptr = 0, version = 1;
342
343
344 confSpace->addConfReg(new pciExpAER_UnCorrErrStatReg(),capOffset + UNCORR_ERR_STAT_OFFSET);
345 confSpace->addConfReg(new pciConfReg("pciExpAER_UnCorrErrMask",4,0x0,aerUncorrErrBitMask,0x0), capOffset + UNCORR_ERR_MASK_OFFSET);
346
347 confSpace->addConfReg(new pciConfReg("pciExpAER_UnCorrErrSev",4,0x0,aerUncorrErrBitMask,0x0), capOffset + UNCORR_ERR_SEVERITY_OFFSET);
348
349 confSpace->addConfReg(new pciExpAER_CorrErrStatReg(), capOffset + CORR_ERR_STAT_OFFSET);
350 confSpace->addConfReg(new pciConfReg("pciExpAER_CorrErrMask",4, 0x0, aerCorrErrBitMask,0x0),capOffset + CORR_ERR_MASK_OFFSET);
351
352 confSpace->addConfReg(new pciExpAER_ErrCapCntrlReg(0x1e0), capOffset + ADVANCED_ERR_CAPCNTRL_OFFSET);
353
354
355 confSpace->addConfReg(new pciConfReg("header log0",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET);
356 confSpace->addConfReg(new pciConfReg("header log1",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 4);
357 confSpace->addConfReg(new pciConfReg("header log2",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 8);
358 confSpace->addConfReg(new pciConfReg("header log3",4,0x0,0xffffffff,0x0),capOffset + HDR_LOG_OFFSET + 12);
359}
360
361
362pcieCompleter genericPcieDev::routeMsg(pciExpMsgCode code){
363 msgRouting r = msgDB->msgCode2Routing(code);
364 assert( r != routed_by_addr);
365 assert( r != routed_by_id);
366
367 // bridges should not use this function anymore. Only leaf devices are
368 // allowed.
369 SAM_DeviceId myId = (dynamic_cast<Module*>(this))->samId;
370 return busIf->busif_msgAccess((uint8_t)code, r, getId(),&myId);
371}
372
373// handle an error condition from the perspective of a receiver/completer
374// of a TLP or as the detecting agent( eg trainingErr) of an
375// error condition. the routine sets the error bits and sends error messages
376// as applicable. This routine also takes care of AER regs if implemented
377// it is assumed that this device is not a root port
378
379pcieCompleter genericPcieDev::processErrorRcvrCmpltr(pciExp_Error error, uint32_t * header){
380 // implement the flow chart section 6.2.5 of rev 1.0a
381 pciExpErrorType errType = errDB->error2DfltErrType(error);
382
383 pciConfReg * devStatReg = confSpace->getConfReg(pciExpCapOffset + PCI_EXP_DEV_STAT_OFFSET);
384 pciConfReg * devCntrlReg = confSpace->getConfReg(pciExpCapOffset + PCI_EXP_DEV_CTRL_OFFSET);
385
386 pciConfReg * cmdReg = confSpace->getConfReg(PCI_CONF_COMM);
387 pciConfReg * statReg = confSpace->getConfReg(PCI_CONF_STAT);
388
389 if(errType == errCorrectable){
390 // correctable errors
391 devStatReg->setBit(pciExpDevStatReg::corrErrDet_bp);
392 if(aerCapable){
393 pciConfReg * corrErrStatReg = confSpace->getConfReg(aerCapOffset + CORR_ERR_STAT_OFFSET);
394 corrErrStatReg->setBit(errDB->error2RegBitPos(error));
395 pciConfReg * corrErrMaskReg = confSpace->getConfReg(aerCapOffset + CORR_ERR_MASK_OFFSET);
396 bool errorIsMasked = corrErrMaskReg->getBit(errDB->error2RegBitPos(error));
397 if(errorIsMasked)
398 return pcieCompleter(SIM_OK);
399 }
400
401 if(devCntrlReg->getBit(pciExpDevCntrlReg::corrErrRepEn_bp))
402 return routeMsg(MSG_ERR_COR);
403 else
404 return pcieCompleter(SIM_OK);
405 }else{
406 // un correctable errors
407 // get the severity from severity register if aer is supported
408 // else get the defualt severity for this error.
409 uint8_t severityFatal;
410 if(aerCapable){
411 pciConfReg * unCorrSevReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_SEVERITY_OFFSET);
412 severityFatal = unCorrSevReg->getBit(errDB->error2RegBitPos(error));
413 }else
414 severityFatal = errType == errUnCorrectable_fatal ? true:false;
415 if(severityFatal)
416 devStatReg->setBit(pciExpDevStatReg::ftlErrDet_bp);
417 else
418 devStatReg->setBit(pciExpDevStatReg::nonFtlErrDet_bp);
419 // set the bits in dev stat reg in case its a UR
420 if(error == unsupportedRequest)
421 devStatReg->setBit(pciExpDevStatReg::unSprtdReqDet_bp);
422
423 if(error == poisonedTLP)
424 statReg->setBit(pcieStatusReg::DETECTED_PARITY_ERROR);
425
426 if(error == completerAbort)
427 statReg->setBit(pcieStatusReg::SIGNALED_TARGET_ABORT);
428
429 if(aerCapable){
430 pciConfReg * unCorrErrStatReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_STAT_OFFSET);
431 uint32_t unCorrErrStatOldVal = unCorrErrStatReg->getVal();
432 unCorrErrStatReg->setBit(errDB->error2RegBitPos(error));
433 pciConfReg * unCorrErrMaskReg = confSpace->getConfReg(aerCapOffset + UNCORR_ERR_MASK_OFFSET);
434 bool errorIsMasked = unCorrErrMaskReg->getBit(errDB->error2RegBitPos(error));
435
436 if(errorIsMasked)
437 return pcieCompleter(SIM_OK);
438
439 if(unCorrErrStatOldVal == 0){
440 // error is unmasked and this is the first error, set the
441 // first error pointer bit field
442 pciConfReg * capCtrlReg = confSpace->getConfReg(aerCapOffset + ADVANCED_ERR_CAPCNTRL_OFFSET);
443 capCtrlReg->setRange(pciExpAER_ErrCapCntrlReg::firstErrPointer_lbp, \
444 pciExpAER_ErrCapCntrlReg::firstErrPointer_rbp,errDB->error2RegBitPos(error));
445 // need to log the header as well
446 assert(header);
447 for(int i = 0; i < 4; i++)
448 confSpace->getConfReg(aerCapOffset + HDR_LOG_OFFSET + i * 4)->setVal(*(header + i));
449 }
450 }
451
452 // handle UR seperately
453 if(error == unsupportedRequest){
454 if(devCntrlReg->getBit(pciExpDevCntrlReg::unsprtdReqRepEn_bp) == 0)
455 return pcieCompleter(SIM_OK);
456 else if(severityFatal)
457 return routeMsg(MSG_ERR_FATAL);
458 else
459 return routeMsg(MSG_ERR_NONFATAL);
460 }
461
462 int serrEnable = cmdReg->getBit(pcieCommandReg::SERR_ENABLE);
463 if(serrEnable){
464 statReg->setBit(pcieStatusReg::SIGNALED_SYSTEM_ERROR);
465 }
466 if(serrEnable || devCntrlReg->getBit(pciExpDevCntrlReg::fatalErrRepEn_bp))
467 if(severityFatal)
468 return routeMsg(MSG_ERR_FATAL);
469
470 if(serrEnable || devCntrlReg->getBit(pciExpDevCntrlReg::nonFatalErrRepEn_bp ))
471 if(!severityFatal)
472 return routeMsg(MSG_ERR_NONFATAL);
473 return pcieCompleter(SIM_OK);
474 }
475}
476
477// return 0 on success, -1 on error
478int genericPcieDev::handleCompletion(pcieCompleter C){
479 pciConfReg * statReg = confSpace->getConfReg(PCI_CONF_STAT);
480
481 if(C.status == SIM_OK)// non posted requests
482 return 0;
483 else if(C.status == SC)
484 return 0;
485 else if(C.status == UR)
486 statReg->setBit(pcieStatusReg::RECEIVED_MASTER_ABORT);
487 else if(C.status == CA)
488 statReg->setBit(pcieStatusReg::RECEIVED_TARGET_ABORT);
489
490 // the next two are not part of specs. the target returns it
491 // so as to aid functional simulation (eg there is no way to timeout
492 // in the initiator in this kind of model)
493 else if(C.status == CMPL_TO)
494 processErrorRcvrCmpltr(completionTimeout);
495 else if(C.status == CMPL_POISONED){
496 pciConfReg * cmdReg = confSpace->getConfReg(PCI_CONF_COMM);
497 if(cmdReg->getBit(pcieCommandReg::PARITY_ERR_EN))
498 statReg->setBit(pcieStatusReg::MASTER_DATA_PARITY_ERROR);
499 }
500 else if(C.status == SIM_FAIL){
501 printf("ERROR: internal error in the simulator. returned SIM_FAIL\n");
502 return -1;
503 }else{
504 printf("ERROR: unknow completion <%d >received\n", C.status);
505 return -1;
506 }
507
508 return 0;
509}
510
511
512
513
514
515///////////////////////////////////////////////////////////////////////////////
516
517
518
519/*****************base address register*********/
520pcieBaseAddrReg::pcieBaseAddrReg(const char * name, genericPcieDev * d,uint64_t spaceSize,pcie_space sp , bool ismem32, bool isPrefetch): \
521 pciConfReg(name,4,0,0 ,(void*)d){
522
523 if(d == 0){
524 printf("baseAddrReg constructor error: must provide pointer to genericPciDev\n");
525 return;
526 }
527
528 if(spaceSize < 16){
529 printf("baseAddrReg constructor error: size must be greater than or equal 16\n");
530 return;
531 }
532
533 int first_set_bit = ffs((uint32_t)spaceSize);
534 if(first_set_bit == 0){
535 first_set_bit = ffs((uint32_t) (spaceSize >> 32));
536 mask = 0;
537 mask_32To63 = (uint32_t)-1 << (first_set_bit - 1);
538 }else{
539 mask_32To63 = 0xffffffff;
540 mask = (uint32_t)-1 << (first_set_bit - 1);
541 }
542
543 this->space = sp;
544 this->isPrefetchable = isPrefetch;
545 this->mapSize = spaceSize;
546 isMapped = false;
547 val_32To63 = 0;
548 mask_32To63 = 0xffffffff;
549
550 if(space == PCIE_MEM){
551 if(ismem32)
552 bartype = MEM32;
553 else{
554 bartype = MEM64;
555 size = 8;
556 }
557 }else
558 bartype = IO;
559 switch(space){
560 case PCIE_MEM:
561 switch(isPrefetchable){
562 case true:
563 val = bartype | PREFETCH;
564 break;
565 case false:
566 val = bartype;
567 break;
568 }
569 break;
570 case PCIE_IO:
571 val = IO;
572 break;
573 }
574
575 return;
576}
577
578uint8_t pcieBaseAddrReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
579 // simpler assumption for now of whole reg reads.
580 // if assert ever fails then add support for (bytes_to_write <= 4 == true) etc.
581 assert(bytes_to_write == 4);
582 assert(byte_offset == 0 or byte_offset == 4);
583
584 oldVal = val | (uint64_t)val_32To63 << 32;
585 if(byte_offset > 3){
586 if(debug_level >= 2)
587 printf("Name<%s>,size<0x%x>offset<0x4>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val_32To63,buf & mask_32To63);
588 val_32To63 = buf & mask_32To63;
589 }else
590 pciConfReg::write(buf, byte_offset, bytes_to_write);
591
592 reMap();
593 return 4;
594}
595
596void pcieBaseAddrReg::reMap(){
597 //read the command register
598 uint32_t commandRegVal;
599 pciConfReg * confReg;
600 confReg = ((genericPcieDev*)data)->confSpace->getConfReg(PCI_CONF_COMM);
601 if(confReg){
602 confReg->read(&commandRegVal,confReg->size);
603 if(space == PCIE_MEM){
604 bool space_enabled = commandRegVal & 1 << pcieCommandReg::MEM_SPACE;
605 if(!space_enabled)
606 return;
607 if(isMapped)
608 ((genericPcieDev*)data)->unmapSpace(PCIE_MEM,oldVal & ~0xf);
609
610 if(bartype == MEM32)
611 ((genericPcieDev*)data)->mapSpace(PCIE_MEM,val&~0xf,mapSize);
612 else
613 ((genericPcieDev*)data)->mapSpace(PCIE_MEM,(val|(uint64_t)val_32To63 << 32) &~0xf ,mapSize);
614 }else if(space == PCIE_IO){
615 bool space_enabled = (commandRegVal & 1 << pcieCommandReg::IO_SPACE);
616 if(!space_enabled)
617 return;
618 if(isMapped)
619 ((genericPcieDev*)data)->unmapSpace(PCIE_IO,oldVal & ~0xf);
620 ((genericPcieDev*)data)->mapSpace(PCIE_IO,val & ~0xf , mapSize);
621 }
622 }
623}
624
625bool pcieBaseAddrReg::map(){
626 assert(!isMapped);
627 //isMapped = true;
628
629 if(bartype == MEM64)
630 isMapped = ((genericPcieDev*)data)->mapSpace(space,(val|(uint64_t)val_32To63 << 32) & ~0xf , mapSize);
631 else
632 isMapped = ((genericPcieDev*)data)->mapSpace(space,val & ~0xf , mapSize);
633 return isMapped;
634}
635
636bool pcieBaseAddrReg::unmap(){
637 assert(isMapped);
638 //isMapped = false;
639 if(bartype == MEM64)
640 isMapped = ((genericPcieDev*)data)->unmapSpace(space,(val|(uint64_t)val_32To63 << 32) & ~0xf);
641 else
642 isMapped = ((genericPcieDev*)data)->unmapSpace(space,val & ~0xf);
643 return isMapped;
644}
645
646
647/********************Command reg************************/
648uint8_t pcieCommandReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
649 assert(byte_offset == 0);
650
651 uint8_t ret;
652 if(bytes_to_write <= 2)
653 ret = bytes_to_write;
654 else
655 ret = 2;
656
657 buf &= ~((int32_t)-1 << ret * 8);
658
659 //uint32_t changed_bits = val ^ (mask & buf);
660 uint32_t new_val = val | (mask & buf);
661 uint32_t changed_bits = new_val ^ val;
662
663 if(debug_level >= 2)
664 printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val,new_val);
665
666 val = new_val;
667
668 if(changed_bits & 1 << IO_SPACE){ //I/O space map bit has changed
669 if(val & 1 << IO_SPACE) //bit set to 1
670 mapSpace(PCIE_IO);
671 else
672 unMapSpace(PCIE_IO); //bit set to 0
673 }
674
675 if(changed_bits & 1 << MEM_SPACE){
676 if(val & 1 << MEM_SPACE){ //bit set to 1
677 mapSpace(PCIE_MEM);
678 }else{
679 unMapSpace(PCIE_MEM);
680 }
681 }
682
683 return ret;
684}
685
686void pcieCommandReg::mapSpace(pcie_space spc){
687 //base address regs range from 0x10 to 0x24
688 pcieBaseAddrReg * baseAddr;
689 for(int i = 0x10; i < 0x28; i+=4){
690 baseAddr = dynamic_cast<pcieBaseAddrReg*>(((genericPcieDev*)data)->confSpace->getConfReg(i));
691 if(baseAddr && baseAddr->space == spc){
692 baseAddr->map();
693 if(baseAddr->bartype == pcieBaseAddrReg::MEM64)
694 i+=4;
695 }
696 }
697}
698
699void pcieCommandReg::unMapSpace(pcie_space spc){
700 //base address regs range from 0x10 to 0x24
701 pcieBaseAddrReg * baseAddr;
702 for(int i = 0x10; i < 0x28; i+=4){
703 baseAddr = dynamic_cast<pcieBaseAddrReg*>(((genericPcieDev*)data)->confSpace->getConfReg(i));
704 if(baseAddr && baseAddr->space == spc){
705 baseAddr->unmap();
706 if(baseAddr->bartype == pcieBaseAddrReg::MEM64)
707 i+=4;
708 }
709 }
710}
711
712