Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / pci_common.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: pci_common.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_common.h"
22
23
24/***************************************************************************************************/
25//pci configuration space class functions//
26
27
28//fill in the default values for register values, masks, names etc.
29void pciConfSpace::initConf(confHeaderType htype){
30
31 if(htype == pciHeaderNull){
32 // for devices that know what they want
33 return;
34 }else if(htype == pciHeader0){
35
36//for now only type 0 header. type 1 support to be done
37
38 //common registers for all pci devices
39 //specific implementations must provide specific
40 //values for mask and init value if different from default
41
42 //NOTE: command and status registers are not added here since they are specialized
43 //versions of pciConfReg, requiring callback data pointer. they must be initialized
44 //after device instantiation and added to pci configuration space.
45 addConfReg(new pciConfReg("Vendor Id", 2, 0x0, 0x0), PCI_CONF_VENID);
46 addConfReg(new pciConfReg("Device id", 2, 0x0, 0x0), PCI_CONF_DEVID);
47 //addConfReg(new pciCommandReg("Command", 0x3ff, this), PCI_CONF_COMM);
48 //addConfReg(new pciStatusReg("Status", 0x0, 0xff90, this), PCI_CONF_STAT);
49 addConfReg(new pciConfReg("Revision Id", 1, 0x0, 0x0), PCI_CONF_REVID);
50 addConfReg(new pciConfReg("Programming class", 1, 0x0, 0x0), PCI_CONF_PROGCLASS);
51 addConfReg(new pciConfReg("Sub class", 1, 0x0, 0x0), PCI_CONF_SUBCLASS);
52 addConfReg(new pciConfReg("Base class", 1, 0x0, 0x0), PCI_CONF_BASCLASS);
53 addConfReg(new pciConfReg("Cache line size", 1, 0x0, 0xff), PCI_CONF_CACHE_LINESZ);
54 addConfReg(new pciConfReg("Latency time", 1, 0, 0xff), PCI_CONF_LATENCY_TIMER);
55 addConfReg(new pciConfReg("Header type", 1, 0x0, 0x00), PCI_CONF_HEADER); //default type 0
56 addConfReg(new pciConfReg("BIST", 4, 0x0, 0x40), PCI_CONF_BIST);
57
58 //these registers may or may not be implemented. The write mask is
59 //0x0. The specific device implementation must change the mask to correct
60 //value if the register is implemented and provide the correct init value.
61 //in case the register is read only, provide the init value
62
63 //NOTE: the base address registers(BAR) are not added here since they need the size
64 //information, known only to specific device implementation. should be added during initialization.
65 addConfReg(new pciConfReg("CardBus CIS pointer", 4,0x0,0x0), PCI_CONF_CIS);
66 addConfReg(new pciConfReg("Subsystem vendor id", 2,0x0,0x0), PCI_CONF_SUBVENID);
67 addConfReg(new pciConfReg("Subsystem Id", 2,0x0,0x0), PCI_CONF_SUBSYSID);
68 addConfReg(new pciConfReg("Expansion ROM base address", 4,0x0,0x0), PCI_CONF_ROM);
69 addConfReg(new pciConfReg("Capabilities pointer", 1,0x0,0x0), PCI_CONF_CAP_PTR);
70 addConfReg(new pciConfReg("Interrupt line", 1,0x0,0x0), PCI_CONF_ILINE);
71 addConfReg(new pciConfReg("Interrupt pin", 1,0x0,0x0), PCI_CONF_IPIN); //rdonly register
72 addConfReg(new pciConfReg("Min grant", 1,0x0,0x0), PCI_CONF_MIN_G); //rdonly
73 addConfReg(new pciConfReg("Min grant", 1,0x0,0x0), PCI_CONF_MAX_L); //rdonly
74
75 }else{
76 printf("confspace init: header type 1 unsupported yet.\n");
77 }
78}
79
80
81
82//add a configuration register to the map. If there is a conflict
83//in address range , then the old reg(s) are removed and new is installed.
84//this allows the device models to have device specific configuration
85//registers not part of the generic PCI model.
86bool pciConfSpace::addConfReg(pciConfReg * cr, int offset){
87
88 iter_t iter_low, iter;
89 if( ((iter = pciConfRegMap.lower_bound(offset)) != pciConfRegMap.end() ) && (iter->second->isHole == false) ){
90 printf("current Conf space registers-->\n");print();
91 printf("addConfReg error: conf reg at offset 0x%x already exist, name<%s>\nDeleted..\n",offset,iter->second->name);
92 deleteConfReg(offset);
93 //XXX corner case. inserting a larger reg than the 1 being deleted
94 }
95
96 cr->setDebug(debug_level);
97 iter_low = pciConfRegMap.lower_bound(offset);
98
99 assert(iter_low->second->isHole);
100 int size_hole1 = offset - iter_low->first;
101 int size_hole2 = iter_low->second->size - (size_hole1 + cr->size);
102
103 if(size_hole1 <= 0)
104 //hole size became 0. delete it
105 pciConfRegMap.erase(iter_low->first);
106 else
107 iter_low->second->size = size_hole1;
108
109 if(size_hole2 > 0){
110 pciConfReg * hole = new pciConfReg(size_hole2);
111 pciConfRegMap[offset + cr->size] = hole;
112 }
113
114 pciConfRegMap[offset] = cr;
115 return true;
116}
117
118bool pciConfSpace::deleteConfReg(int offset){
119
120 if( (pciConfRegMap.find(offset) == pciConfRegMap.end()) || pciConfRegMap.find(offset)->second->isHole == true ){
121 printf("deleteConfReg error: conf reg at offset 0x%x does not exist\n",offset);
122 return false;
123 }
124
125 iter_t iter_low, iter_high, iter;
126 iter = pciConfRegMap.find(offset);
127 iter_low = pciConfRegMap.upper_bound(offset);
128 iter_high = pciConfRegMap.lower_bound(offset);
129
130 int high_size = 0, high_offset = 0;
131 if(iter_high->second->isHole){
132 high_offset = iter_high->first;
133 high_size = iter_high->second->size;
134 pciConfRegMap.erase(iter_high->first);
135 }
136
137 if(iter_low->second->isHole){
138 iter_low->second->size += iter->second->size + high_size;
139 pciConfRegMap.erase(offset);
140 }else{
141 pciConfReg * hole = new pciConfReg(iter->second->size + high_size);
142 pciConfRegMap[offset] = hole;
143 }
144
145 return true;
146
147}
148
149
150//read/write contiguous 'size' bytes from 'offset' and return the value in buf in case of read.
151//it is assumed that alignment restrictions are maintained, with this kind of access.
152bool pciConfSpace::confAccessSize(int offset,bool wr, uint64_t * in_buf,uint8_t size){
153
154 // assert(offset <= 0xff); move to caller XXX
155 assert(size <= 4);
156
157 uint64_t local_buf = *in_buf;
158 uint64_t *buf = &local_buf;
159 uint32_t buf_lo = local_buf;
160
161 //if(offset % size != 0)//XXX move checking to caller
162 // return TARGET_ABORT;
163
164 iter_t iter = pciConfRegMap.lower_bound(offset); //find the element with key less than or equal
165 //to offset
166 assert(iter != pciConfRegMap.end());
167
168 //if(debug_level >= 2)
169 // iter->second->print();
170
171 uint8_t byte_offset = offset - iter->first;
172 uint8_t bytes_consumed = 0;
173 uint8_t buf_offset = 0;
174 while(size!=0){
175 if(iter->second->size > byte_offset){
176 if(wr){
177 bytes_consumed = iter->second->write(*buf,byte_offset,size);
178 *buf >>= bytes_consumed*8;
179 }else{
180 bytes_consumed = iter->second->read(&buf_lo,size,byte_offset,buf_offset);
181 local_buf = ((local_buf >> 32) << 32) | buf_lo;
182 buf_offset += bytes_consumed;
183 //*buf <<= (size - bytes_consumed) * 8;
184 }
185 size -= bytes_consumed;
186 byte_offset += bytes_consumed;
187 }else{
188 //iter++;
189 iter--;
190 //if(debug_level >= 2)
191 // iter->second->print();
192 byte_offset = 0;
193 }
194 }
195 if(!wr)
196 *in_buf = *buf;
197 return true;
198}
199
200// access the conf space with 'be' supplying the byte enables.
201// for a read, bytes with corresponding byte enable as 1 will be meaning ful
202// for a write, only those bytes with corresponding byte as 1 will be written to.
203// the function would try to read/write contiguous bytes using a single confAccessSize() call.
204bool pciConfSpace::confAccessByteE(int offset,bool wr, uint64_t * in_buf,uint8_t be){
205 assert ((be & 0xf0) == 0); // upper 4 bits have to be 0.
206
207 uint64_t local_buf = *in_buf;
208 bool ret = false;
209 bool to_rd_wr = false;
210 int bytes_to_rd_wr = 0;
211 uint64_t buf_1 = 0;
212 const int orig_offset = offset;
213
214 if(!wr){
215 // if a read, 0 out the bytes that have to be read
216 for(int i = 0; i < 4; i++)
217 if( (be >> i & 0x1) == 1)
218 *in_buf &= ~((uint64_t)0xff << i * 8);
219 }
220 for(int r_offset = 0; r_offset <= 4; r_offset++){// an extra iteration is needed to r/w the last byte
221 if( (be >> r_offset & 0x1) == 1){
222 buf_1 |= (local_buf & 0xff) << r_offset * 8;
223 to_rd_wr = true;
224 bytes_to_rd_wr++;
225 }else if(to_rd_wr){
226 ret |= confAccessSize(offset,wr, &buf_1,bytes_to_rd_wr);
227 to_rd_wr = false;
228 if(!wr)
229 *in_buf |= buf_1 << (offset - orig_offset) * 8;
230 offset += bytes_to_rd_wr;
231 buf_1 = 0;
232 bytes_to_rd_wr = 0;
233 }else
234 offset++;
235 local_buf >>= 8;
236 }
237 return ret;
238}
239
240
241inline bool pciConfSpace::setMask(int offset, uint32_t mask){
242 pciConfIter = pciConfRegMap.lower_bound(offset);
243
244 if(pciConfIter->first != offset || pciConfIter->second->isHole){
245 printf("conf space setMask: no register at offset 0x%x\n",offset);
246 return false;
247 }
248 pciConfIter->second->setMask(mask);
249 return true;
250}
251
252inline bool pciConfSpace::setVal(int offset, uint32_t value){
253 pciConfIter = pciConfRegMap.lower_bound(offset);
254
255 if(pciConfIter->first != offset || pciConfIter->second->isHole){
256 printf("conf space setVal : no register at offset 0x%x\n",offset);
257 return false;
258 }
259 pciConfIter->second->setVal(value);
260 return true;
261}
262
263
264
265
266
267