Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / pci_dev.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: pci_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 "pci_dev.h"
22#include "ui.h"
23
24/*****************base address register*********/
25
26baseAddrReg::baseAddrReg(const char * name, genericPciDev * d,uint64_t spaceSize,pci_space_t sp , bool isPrefetch):\
27 pciConfReg(name,4,0,0 ,(void*)d){
28
29 if(d == 0){
30 printf("baseAddrReg constructor error: must provide pointer to genericPciDev\n");
31 return;
32 }
33
34 if(spaceSize < 16){
35 printf("baseAddrReg constructor error: size must be greater than or equal 16\n");
36 return;
37 }
38
39 int first_set_bit = ffs((uint32_t)spaceSize);
40 if(first_set_bit == 0){
41 first_set_bit = ffs((uint32_t) (spaceSize >> 32));
42 mask = 0;
43 mask_32To63 = (uint32_t)-1 << (first_set_bit - 1);
44 }else{
45 mask_32To63 = 0xffffffff;
46 mask = (uint32_t)-1 << (first_set_bit - 1);
47 }
48
49 this->space = sp;
50 this->isPrefetchable = isPrefetch;
51 this->mapSize = spaceSize;
52 isMapped = false;
53 val_32To63 = 0;
54 mask_32To63 = 0xffffffff;
55
56 switch(space){
57 case PCI_MEM32:
58 switch(isPrefetchable){
59 case true:
60 val = MEM32 | PREFETCH;
61 break;
62 case false:
63 val = MEM32;
64 break;
65 }
66 break;
67 case PCI_MEM64:
68 switch(isPrefetchable){
69 case true:
70 val = MEM64 | PREFETCH;
71 size = 8;
72 break;
73 case false:
74 val = MEM64;
75 size = 8;
76 break;
77 }
78 break;
79 case PCI_IO:
80 val = IO;
81 break;
82 }
83
84 return;
85}
86
87uint8_t baseAddrReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
88 // simpler assumption for now of whole reg reads.
89 // if assert ever fails then add support for (bytes_to_write <= 4 == true) etc.
90 assert(bytes_to_write == 4);
91 assert(byte_offset == 0 or byte_offset == 4);
92
93 oldVal = val | (uint64_t)val_32To63 << 32;
94 if(byte_offset > 3){
95 if(debug_level >= 2)
96 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);
97 val_32To63 = buf & mask_32To63;
98 }else
99 pciConfReg::write(buf, byte_offset, bytes_to_write);
100
101 reMap();
102 return 4;
103}
104
105void baseAddrReg::reMap(){
106 //read the command register
107 uint32_t commandRegVal;
108 pciConfReg * confReg;
109 confReg = ((genericPciDev*)data)->confSpace->getConfReg(PCI_CONF_COMM);
110 if(confReg){
111 confReg->read(&commandRegVal,confReg->size);
112 if(space == PCI_MEM32 && (commandRegVal & 1 << pciCommandReg::MEM_SPACE)){
113 if(isMapped)
114 ((genericPciDev*)data)->unMapBar(PCI_MEM32,oldVal & ~0xf);
115 ((genericPciDev*)data)->mapBar(PCI_MEM32,val & ~0xf , mapSize);
116 }else if(space == PCI_MEM64 && (commandRegVal & 1 << pciCommandReg::MEM_SPACE)){
117 if(isMapped)
118 ((genericPciDev*)data)->unMapBar(PCI_MEM64,oldVal & ~0xf);
119 ((genericPciDev*)data)->mapBar(PCI_MEM64,val & ~0xf , mapSize);
120 }else if(space == PCI_IO && (commandRegVal & 1 << pciCommandReg::IO_SPACE)){
121 if(isMapped)
122 ((genericPciDev*)data)->unMapBar(PCI_IO,oldVal & ~0xf);
123 ((genericPciDev*)data)->mapBar(PCI_IO,val & ~0xf , mapSize);
124 }//else
125 //printf("internal error base address reg remap()\n");
126 }
127}
128
129bool baseAddrReg::map(){
130 assert(!isMapped);
131 //isMapped = true;
132 isMapped = ((genericPciDev*)data)->mapBar(space,val & ~0xf , mapSize);
133 return isMapped;
134}
135
136bool baseAddrReg::unmap(){
137 assert(isMapped);
138 //isMapped = false;
139 isMapped = ((genericPciDev*)data)->unMapBar(space,val & ~0xf);
140 return isMapped;
141}
142
143
144/********************Command reg************************/
145uint8_t pciCommandReg::write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
146 assert(byte_offset == 0);
147 assert(bytes_to_write == 2);
148
149 //uint32_t changed_bits = val ^ (mask & buf);
150 uint32_t new_val = val | (mask & buf);
151 uint32_t changed_bits = new_val ^ val;
152
153 if(debug_level >= 2)
154 printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val,new_val);
155
156 val = new_val;
157
158 if(changed_bits & 1 << IO_SPACE){ //I/O space map bit has changed
159 if(val & 1 << IO_SPACE) //bit set to 1
160 mapSpace(PCI_IO);
161 else
162 unMapSpace(PCI_IO); //bit set to 0
163 }
164
165 if(changed_bits & 1 << MEM_SPACE){
166 if(val & 1 << MEM_SPACE){ //bit set to 1
167 mapSpace(PCI_MEM32);
168 mapSpace(PCI_MEM64);
169 }else{
170 unMapSpace(PCI_MEM32);
171 unMapSpace(PCI_MEM64); //bit set to 0
172 }
173 }
174
175 return 2;
176}
177
178void pciCommandReg::mapSpace(pci_space_t spc){
179 //base address regs range from 0x10 to 0x24
180 baseAddrReg * baseAddr;
181 for(int i = 0x10; i < 0x28; i+=4){
182 baseAddr = dynamic_cast<baseAddrReg*>(((genericPciDev*)data)->confSpace->getConfReg(i));
183 if(baseAddr && baseAddr->space == spc){
184 baseAddr->map();
185 if(spc == PCI_MEM64)
186 i+=4;
187 }
188 }
189}
190
191void pciCommandReg::unMapSpace(pci_space_t spc){
192 //base address regs range from 0x10 to 0x24
193 baseAddrReg * baseAddr;
194 for(int i = 0x10; i < 0x28; i+=4){
195 baseAddr = dynamic_cast<baseAddrReg*>(((genericPciDev*)data)->confSpace->getConfReg(i));
196 if(baseAddr && baseAddr->space == spc){
197 baseAddr->unmap();
198 if(spc == PCI_MEM64)
199 i+=4;
200 }
201 }
202}
203
204
205
206
207/***************************************************************************************************/
208
209genericPciDev::genericPciDev(confHeaderType htype){
210 confSpace = new pciConfSpace(htype);
211 dev_type = 0;
212 for(int i = 0; i < 3; i++){
213 int_pin_status[i] = false;
214 slot_irl[i] = -1;
215 }
216 interrupt_added = false;
217
218 busName = 0;
219 busIf = 0;
220 intrptIf = 0;
221
222 device = -1;
223 function = 0;
224
225
226 isMultiFunction = false;
227
228}
229
230//////////////////////functions exported to pci bus
231
232pciXactnStatus genericPciDev::devif_access_w_size(pci_space_t space, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t size, SAM_DeviceId * id){
233 bool ret;
234 if(id){
235 *id = (dynamic_cast<Module*>(this))->samId;
236 }
237 switch(space){
238 case PCI_CFG:
239 if(offset % size != 0)
240 return TARGET_ABORT;
241 offset -= device << 11 | function << 8;
242 ret = confSpace->confAccessSize(offset,wr,buf,size);
243 if(!ret)
244 return SIM_INTERNAL_ERROR;
245 pciDev_confAccessCb(wr,offset,size);
246 return SUCCESS;
247 case PCI_IO:
248 return pciTarget_ioaccess(offset,wr,buf,size);
249 case PCI_MEM32:
250 return pciTarget_mem32access(offset,wr,buf,size);
251 case PCI_MEM64:
252 return pciTarget_mem64access(offset,wr,buf,size);
253 default:
254 printf("Unknown PCI space %d\n",space);
255 return SIM_INTERNAL_ERROR;
256 }
257}
258
259pciXactnStatus genericPciDev::devif_access_w_byte_enable(pci_space_t, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t byte_enable, SAM_DeviceId * id){
260 if(id){
261 *id = (dynamic_cast<Module*>(this))->samId;
262 }
263 printf("INTERNAL ERROR : byte enable access not yet supported \n");
264 return SUCCESS;
265}
266
267
268/////////////////////////functions to implement device access as target
269
270// generic device does not respond to any access over the bus. hence
271// the access terminates in master abort.
272// specific devices must override only those access functions, which correspond to
273// implemented behaviour.
274
275pciXactnStatus genericPciDev::pciTarget_ioaccess(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
276 Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_IO");
277 return MASTER_ABORT;
278}
279
280pciXactnStatus genericPciDev::pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
281 Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_MEM32");
282 return MASTER_ABORT;
283}
284
285pciXactnStatus genericPciDev::pciTarget_mem64access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
286 Debug_err("%s: accessing unimplemented address space %s\n", pciDev_getName(), "PCI_MEM64");
287 return MASTER_ABORT;
288}
289
290pciXactnStatus genericPciDev::pciTarget_special_cycle(uint16_t mssg, uint16_t data){
291 return MASTER_ABORT;
292}
293
294pciXactnStatus genericPciDev::pciTarget_intr_ack(uint64_t *data){
295 return MASTER_ABORT;
296}
297
298////////////////////////////////initialization and module related fns
299
300void genericPciDev::pciDevInfo(){
301 printf("bus=<%s> dev=%d fun=%d\n",busName,device,function);
302 printf("configuration space reg info:\n");
303 confSpace->print();
304}
305
306
307
308bool
309genericPciDev::dev_module_added(const char *target_name)
310{
311 if (busName && !strcmp(busName, target_name)) {
312 busName = target_name;
313 mmi_instance_t mod = mmi_get_instance(busName);
314 busIf = (pciBusIf*)mmi_get_interface(mod, PCI_BUS_INTERFACE);
315 if (!busIf) {
316 Debug_err("%s: ERROR: can't find interface for PCI bus <%s>\n", Here, busName);
317 return false;
318 }else if(!busIf->busif_add_device(pciDev_getName(), device, function)) {
319 Debug_err("%s: ERROR: could not add tp PCI bus <%s>\n", Here, busName);
320 return false;
321 }else{
322 ui->verbose("%s: bus <%s> connected: busif=%p\n", Here, busName, busIf);
323 }
324 }
325 if(!interrupt_added && busIf && (busIf->busif_add_interrupt(device,dev_type, slot_irl,isMultiFunction) != -1))
326 interrupt_added = true;
327 return true;
328}
329
330
331bool
332genericPciDev::dev_module_deleted(const char *target_name){
333 if (busName && !strcmp(busName, target_name)) {
334 busName = 0;
335 busIf = 0;
336 Debug_info("%s: bus <%s> disconnected\n", Here, busName);
337 }
338 return true;
339}
340
341bool
342genericPciDev::dev_parse_arg(const char *arg){
343 if (argval("bus", arg, &busName)) {
344 Debug_more("%s: bus=<%s>\n", Here, busName);
345 } else if (argval("dev", arg, &device)) {
346 Debug_more("%s: dev=%d\n", Here, device);
347 } else if (argval("fun", arg, &function)) {
348 Debug_more("%s: fun=%d\n", Here, function);
349 }else{
350 Debug_err("%s: WARNING: unrecognized arg '%s'\n", Here, arg);
351 return false;
352 }
353 return true;
354}
355
356bool
357genericPciDev::dev_check_args(){
358 if (!busName) {
359 Debug_err("%s: ERROR: must specify a PCI bus\n", pciDev_getName());
360 return false;
361 }else if(device == -1){
362 Debug_err("%s: ERROR: must specify device number\n", pciDev_getName());
363 return false;
364 }else
365 return true;
366}
367
368void
369genericPciDev::dev_init_done(int debug_level){
370 if(!interrupt_added){
371 int ret = busIf->busif_add_interrupt(device, 0, slot_irl);
372 if(ret == -1)
373 Debug_err("%s:ERROR: failed to be assingned interrupt\n", pciDev_getName());
374 else
375 interrupt_added = true;
376 }
377 confSpace->set_debug_level(debug_level);
378 pciDebug::set_debug_level(debug_level);
379}
380
381/////////////////////////////////functions to called by specific PCI device when acting as bus master
382bool
383genericPciDev::pciMaster_set_int(int line, bool raise){
384 Module * m = dynamic_cast<Module*>(this);
385 assert (m);
386 SAM_DeviceId id = m->samId;
387 if (line < 0 || 4 <= line) {
388 Debug_err("%s: ERROR: dev_set_int_pin: pin=%d: should be 0..3\n", pciDev_getName(), line);
389 return false;
390 }
391
392 if (int_pin_status[line] != raise) {
393 int_pin_status[line] = raise;
394 if (busIf && interrupt_added){
395 busIf->busif_interrupt_in(raise,device, line,&id);
396 return true;
397 }
398 }
399 return true;
400}
401
402pciXactnStatus genericPciDev::pciMaster_dma(bool wr, uint64_t vaddr, void *data, long count){
403 Module * m = dynamic_cast<Module*>(this);
404 assert (m);
405 SAM_DeviceId id = m->samId;
406 if(busIf)
407 return busIf->busif_dma(wr,vaddr, data, count,&id);
408 Debug_err("%s: ERROR: no bus interface <%s> \n",pciDev_getName());
409 return SIM_INTERNAL_ERROR;
410}
411
412pciXactnStatus genericPciDev::pciMaster_intr_ack_cycle(uint64_t * data){
413 if(busIf)
414 return busIf->busif_intr_ack(data);
415 Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
416 return SIM_INTERNAL_ERROR;
417}
418
419pciXactnStatus genericPciDev::pciMaster_special_cycle(uint16_t mssg, uint16_t data){
420 if(busIf)
421 return busIf->busif_special_cycle(mssg, data);
422 Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
423 return SIM_INTERNAL_ERROR;
424}
425
426pciXactnStatus genericPciDev::pciMaster_bus_access_w_size(pci_space_t space, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t size){
427 if(busIf)
428 return busIf->busif_access_w_size(space,paddr,offset,wr,buf,size);
429 Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
430 return SIM_INTERNAL_ERROR;
431}
432
433pciXactnStatus genericPciDev::pciMaster_bus_access_w_byte_enable(pci_space_t space, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t byte_enable){
434 if(busIf)
435 return busIf->busif_access_w_byte_enables(space,paddr,offset,wr,buf,byte_enable);
436 Debug_err("%s: ERROR: no bus interface <%s>\n",pciDev_getName());
437 return SIM_INTERNAL_ERROR;
438}
439
440/////////////////////////////////
441
442
443bool genericPciDev::dump(const char * dirname,const char *file){
444 char *filename = new char[strlen(dirname) + strlen(file) + 6];
445 sprintf(filename,"%s/%s.pci",dirname,file);
446
447 FILE *fp = fopen(filename,"w");
448 if(!fp){
449 Debug_err("%s pci dump. fopen failed for %s\n",pciDev_getName(), filename);
450 return false;
451 }
452 pciConfReg * cr;
453
454 for(int offset = 0; offset < 0x100;){
455 if(offset == PCI_CONF_COMM){
456 offset += 2;
457 continue;
458 }
459 cr = confSpace->getConfReg(offset);
460 if(!cr) // hole
461 offset++;
462 else if(cr->isRO()) // Read only register. no need to save
463 offset += cr->size;
464 else{
465 fprintf(fp,"0x%x\t0x%x\n",offset,cr->getVal());
466 offset += cr->size;
467 }
468 }
469
470 cr = confSpace->getConfReg(PCI_CONF_COMM);
471 fprintf(fp,"0x%x\t0x%x\n",PCI_CONF_COMM,cr->getVal());
472 fclose(fp);
473
474 return true;
475}
476
477// to be called after initPci() has been called
478bool genericPciDev::restore(const char * dirname,const char * file){
479 char *filename = new char[strlen(dirname) + strlen(file) + 6];
480 sprintf(filename,"%s/%s.pci",dirname,file);
481
482 int off;
483 uint32_t val;
484
485 FILE *fp = fopen(filename,"r");
486
487 if(!fp){
488 Debug_err("%s pci restore. fopen failed for %s\n",pciDev_getName(), filename);
489 return false;
490 }
491
492 pciConfReg * cr;
493 char str[100];
494
495 for(int offset = 0; offset < 0x100;){
496 if(offset == PCI_CONF_COMM){
497 offset += 2;
498 continue;
499 }
500 cr = confSpace->getConfReg(offset);
501 if(!cr) // hole
502 offset++;
503 else if(cr->isRO()) // Read only register. no need to restore
504 offset += cr->size;
505 else{
506 fscanf(fp,"0x%x\t0x%x\n",&off,&val);
507 assert(off == offset);
508 cr->write(val,0,cr->size);
509 pciDev_confAccessCb(true,offset,cr->size);
510 offset += cr->size;
511 }
512 }
513
514 // restore the command register
515 cr = confSpace->getConfReg(PCI_CONF_COMM);
516 fscanf(fp,"0x%x\t0x%x\n",&off,&val);
517 cr->write(val,0,cr->size);
518 pciDev_confAccessCb(true,PCI_CONF_COMM,cr->size);
519 fclose(fp);
520
521 return true;
522}
523
524
525