Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: pci_common.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | #ifndef __PCI_COMMON_H__ | |
24 | #define __PCI_COMMON_H__ | |
25 | ||
26 | #include <map> | |
27 | #include <stdio.h> | |
28 | #include <stdarg.h> | |
29 | ||
30 | #include "pci.h" | |
31 | ||
32 | using namespace std; | |
33 | ||
34 | class pciConfReg{ | |
35 | public: | |
36 | ||
37 | int debug_level; | |
38 | char * name; | |
39 | uint16_t size; //size of the register | |
40 | void * data; //pointer to device. to be | |
41 | //used by devices providing | |
42 | //custom read/write for nonstandard conf regs, | |
43 | //unimplemented, reserved reg etc | |
44 | ||
45 | bool isHole; //true for unimplemented registers | |
46 | ||
47 | pciConfReg(uint16_t sz = 0x100){ | |
48 | name = new char[1]; | |
49 | *name = '\0'; | |
50 | size = sz; | |
51 | val = 0; | |
52 | mask = 0; | |
53 | isHole = true; | |
54 | data = 0; | |
55 | debug_level = 0; | |
56 | } | |
57 | // args (reg name, reg size, por value, write mask, impl. specific data) | |
58 | pciConfReg(const char * n,uint16_t sz, uint32_t v, uint32_t m ,void * d = 0){ | |
59 | name = new char[strlen(n)+1]; | |
60 | strcpy(name,n); | |
61 | size = sz; | |
62 | val = v; | |
63 | mask = m; | |
64 | data = d; | |
65 | isHole = false; | |
66 | debug_level = 0; | |
67 | } | |
68 | ||
69 | void setDebug(int level){ debug_level = level; } | |
70 | ||
71 | // devices with different read/write accesses (eg rw1c) should override | |
72 | // these functions to provide custom behaviour and to implement device | |
73 | // specific side effects | |
74 | ||
75 | // read 'bytes_to_read/write' bytes starting from 'byte_offset'. | |
76 | // if the 'size' of register is less than bytes_to_read/write then | |
77 | // read/write the whole register. return the number | |
78 | // of bytes read/written. | |
79 | virtual uint8_t read(uint32_t *buf, uint8_t bytes_to_read, uint8_t byte_offset = 0,uint8_t buf_offset = 0){ | |
80 | // return the bytes in buf. 'bytes_to_read' bytes are filled in from (char*)buf + buf_offset | |
81 | // w/0 affecting the other bytes in *buf. | |
82 | uint8_t bytes_read = (size - byte_offset) >= bytes_to_read ? bytes_to_read: size - byte_offset; | |
83 | uint64_t byte_mask = (~ ((uint64_t) -1 << bytes_read * 8));//eg for bytes_read=1, mask = 0xff | |
84 | *buf = (*buf & ~(byte_mask << buf_offset * 8)) | (val >> byte_offset * 8 & byte_mask) << buf_offset * 8; | |
85 | ||
86 | if(debug_level >= 2) | |
87 | print(); | |
88 | ||
89 | return bytes_read; | |
90 | } | |
91 | ||
92 | virtual uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){ | |
93 | uint32_t oldval = val; | |
94 | uint8_t bytes_written = (size - byte_offset) >= bytes_to_write ? bytes_to_write:size - byte_offset; | |
95 | uint64_t byte_mask = ~((uint64_t) -1 << bytes_written * 8); | |
96 | //reset the writable bits in 'val' to 0, in the range | |
97 | //val |= val & ~mask & (byte_mask << byte_offset); | |
98 | val = val & ~(mask & (byte_mask << byte_offset)); | |
99 | val |= ((buf & byte_mask) << byte_offset * 8) & mask; | |
100 | ||
101 | if(debug_level >= 2){ | |
102 | if(!isHole) | |
103 | printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val); | |
104 | else | |
105 | printf("Hole: size<0x%x>\n",size); | |
106 | } | |
107 | return bytes_written; | |
108 | } | |
109 | ||
110 | virtual void setMask(uint32_t m){mask = m;} | |
111 | virtual uint32_t getMask(){ return mask;} | |
112 | virtual void setVal(uint32_t v){val = v;} | |
113 | ||
114 | virtual void print(){ | |
115 | if(!isHole) | |
116 | printf("Name<%s>,size<0x%x>value<0x%lx>,mask<0x%lx>\n",name,size,val,mask); | |
117 | else | |
118 | printf("Hole: size<0x%x>\n",size); | |
119 | return; | |
120 | } | |
121 | ||
122 | inline bool isRO(){ | |
123 | return (mask == 0) ? true: false; | |
124 | } | |
125 | inline uint32_t getVal(){ | |
126 | return val; | |
127 | } | |
128 | ||
129 | protected: | |
130 | ||
131 | uint32_t val; //value. | |
132 | uint32_t mask; //mask for s/w access | |
133 | ||
134 | public: | |
135 | // set bit to either 0 or 1, taking into account the s/w mask | |
136 | virtual bool setBit(uint8_t bit_pos, uint8_t buf){ | |
137 | val |= val & ~mask & 1 << bit_pos; | |
138 | val |= mask & buf << bit_pos; | |
139 | return true; | |
140 | } | |
141 | ||
142 | // set the bit to 1 irrespective of s/w mask. | |
143 | // to be used by device models when acting from the h/w side | |
144 | virtual void setBit(uint8_t bit_pos){ | |
145 | val |= (uint32_t)1 << bit_pos; | |
146 | } | |
147 | // reset a bit to 0, overriding the mask | |
148 | virtual void resetBit(uint8_t bit_pos){ | |
149 | val &= ~((uint32_t)1 << bit_pos); | |
150 | } | |
151 | ||
152 | virtual bool getBit(uint8_t bit_pos, uint8_t *buf){ | |
153 | *buf = val >> bit_pos & 0x1; | |
154 | return true; | |
155 | } | |
156 | virtual uint8_t getBit(uint8_t bit_pos){ | |
157 | return val >> bit_pos & 0x1; | |
158 | } | |
159 | ||
160 | // set some bit range, overriding the s/w mask | |
161 | virtual bool setRange(uint8_t left_bit_pos, uint8_t right_bit_pos,uint32_t buf){ | |
162 | ||
163 | //bits counted from left to right | |
164 | ||
165 | uint32_t bit_mask = ((uint32_t)-1 << left_bit_pos + 1) ^ ((uint32_t)-1 << right_bit_pos); | |
166 | val |= val & bit_mask; //reset the bits to 0 | |
167 | val |= ((buf) << right_bit_pos) & bit_mask;//fill in the bit field | |
168 | return true; | |
169 | } | |
170 | virtual bool getRange(uint8_t left_bit_pos, uint8_t right_bit_pos,uint32_t *buf){ | |
171 | ||
172 | uint32_t bit_mask = (uint32_t)-1 << left_bit_pos ^ (uint32_t)-1 << right_bit_pos; | |
173 | *buf = val >> left_bit_pos & bit_mask; | |
174 | return true; | |
175 | } | |
176 | ||
177 | }; | |
178 | ||
179 | ||
180 | ||
181 | ||
182 | class pciConfSpace{ | |
183 | public: | |
184 | ||
185 | //comparison function (reverse than normal default case) | |
186 | class compare{ | |
187 | public: | |
188 | bool operator()(int key1, int key2)const{ | |
189 | return key1 > key2; | |
190 | } | |
191 | }; | |
192 | ||
193 | ||
194 | ||
195 | private: | |
196 | map<int,pciConfReg *,compare> pciConfRegMap; //key is the offset of the register into the conf space | |
197 | map<int,pciConfReg *,compare>::iterator pciConfIter; | |
198 | typedef map<int,pciConfReg *,compare>::iterator iter_t; | |
199 | int debug_level; | |
200 | void initConf(confHeaderType); | |
201 | ||
202 | public: | |
203 | bool addConfReg(pciConfReg * cr, int offset); | |
204 | bool deleteConfReg(int offset); | |
205 | bool confAccessSize(int offset,bool wr, uint64_t * buf,uint8_t size); | |
206 | bool pciConfSpace::confAccessByteE(int offset,bool wr, uint64_t * in_buf,uint8_t be); | |
207 | inline bool setMask(int offset, uint32_t mask); | |
208 | inline bool setVal(int offset, uint32_t value); | |
209 | ||
210 | // return pointer to the configuration register. useful for direct access | |
211 | // functions like setBit() etc | |
212 | pciConfReg *getConfReg(int offset){ | |
213 | ||
214 | iter_t iter = pciConfRegMap.find(offset); | |
215 | if(iter == pciConfRegMap.end()) | |
216 | return 0; | |
217 | else if(iter->second->isHole) | |
218 | return 0; | |
219 | else | |
220 | return iter->second; | |
221 | ||
222 | } | |
223 | ||
224 | uint32_t readConf(int offset){ | |
225 | uint32_t retval = 0; | |
226 | pciConfReg * reg = getConfReg(offset); | |
227 | if(reg) | |
228 | retval = reg->getVal(); | |
229 | //else | |
230 | // retval = -1; | |
231 | return retval; | |
232 | } | |
233 | ||
234 | pciConfSpace(confHeaderType htype = pciHeader0){ | |
235 | pciConfRegMap[0] = new pciConfReg(); | |
236 | initConf(htype); | |
237 | debug_level = 0; | |
238 | } | |
239 | ||
240 | // pcie conf reg map = 0x1000 | |
241 | pciConfSpace(int size = 0x100){ | |
242 | pciConfRegMap[0] = new pciConfReg(size); | |
243 | debug_level = 0; | |
244 | } | |
245 | ||
246 | void print(){ | |
247 | for(pciConfIter = pciConfRegMap.begin(); pciConfIter != pciConfRegMap.end(); pciConfIter++){ | |
248 | printf("offset:%x:",pciConfIter->first);pciConfIter->second->print(); | |
249 | } | |
250 | ||
251 | } | |
252 | void set_debug_level(int level){ | |
253 | debug_level = level; | |
254 | for(pciConfIter = pciConfRegMap.begin(); pciConfIter != pciConfRegMap.end(); pciConfIter++) | |
255 | pciConfIter->second->setDebug(level); | |
256 | } | |
257 | }; | |
258 | ||
259 | #define Here _Here(__FILE__, __LINE__) | |
260 | ||
261 | class pciDebug{ | |
262 | char herebuf[80]; | |
263 | int debug_l; | |
264 | public: | |
265 | void set_debug_level(int n){debug_l = n;} | |
266 | void Debug_err(const char *fmt, ...){ | |
267 | if (debug_l >= 0) { | |
268 | va_list ap; | |
269 | va_start(ap, fmt); | |
270 | vfprintf(stderr, fmt, ap); | |
271 | va_end(ap); | |
272 | } | |
273 | } | |
274 | ||
275 | void Debug_info(const char *fmt, ...){ | |
276 | if (debug_l >= 1) { | |
277 | va_list ap; | |
278 | va_start(ap, fmt); | |
279 | vfprintf(stderr, fmt, ap); | |
280 | va_end(ap); | |
281 | } | |
282 | } | |
283 | ||
284 | void Debug_more(const char *fmt, ...){ | |
285 | if (debug_l >= 2) { | |
286 | va_list ap; | |
287 | va_start(ap, fmt); | |
288 | vfprintf(stderr, fmt, ap); | |
289 | va_end(ap); | |
290 | } | |
291 | } | |
292 | ||
293 | const char * | |
294 | _Here(const char *f, int n){ | |
295 | const char *p = strrchr(f, '/'); | |
296 | snprintf(herebuf, sizeof herebuf, "%s(L%d)",p?(p+1):f, n); | |
297 | return herebuf; | |
298 | } | |
299 | }; | |
300 | ||
301 | ||
302 | #endif // __PCI_COMMON_H__ | |
303 |