Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: pci_bus.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_bus.h" | |
22 | //////////////////module functions//////////////// | |
23 | ||
24 | // print interesting info about this module | |
25 | void | |
26 | pciBus::modinfo(){ | |
27 | ||
28 | pciDevMapIterator dmIter; | |
29 | printf(" bridge=<%s>\n", bridgeName); | |
30 | ||
31 | for(uint8_t i = 0; i < PCI_NSPACES; i++){ | |
32 | printf("%s",pci_space_name((pci_space_t)i)); | |
33 | printf("::devices:\n"); | |
34 | for(dmIter = pciAddrSpace[i].begin(); dmIter != pciAddrSpace[i].end(); dmIter++) | |
35 | dmIter->second->print(); | |
36 | } | |
37 | } | |
38 | ||
39 | // parse an arg | |
40 | bool | |
41 | pciBus::parse_arg(const char *arg){ | |
42 | if (argval("bridge", arg, &bridgeName)) | |
43 | debug_more("%s: bridge=<%s>\n", HERE, bridgeName); | |
44 | else | |
45 | return false; | |
46 | return true; | |
47 | } | |
48 | ||
49 | ||
50 | void | |
51 | //pciBus::module_added(mmi_instance_t, const char *target_name){ | |
52 | pciBus::module_added(mmi_instance_t target_mod, const char *target_name){ | |
53 | if (!strcmp(bridgeName, target_name)) { | |
54 | bridgeMod = target_mod;//mmi_get_module(bridgeName); | |
55 | bridgeIf = (pciBridgeIf*) mmi_get_interface(bridgeMod, PCI_BRIDGE_INTERFACE); | |
56 | if (bridgeIf) | |
57 | debug_info("%s: bridge <%s> connected\n", HERE, bridgeName); | |
58 | else | |
59 | debug_err("%s: ERROR: bridge <%s> has no interface\n", HERE, bridgeName); | |
60 | } | |
61 | } | |
62 | ||
63 | void | |
64 | //pciBus::module_deleted(mmi_instance_t, const char *target_name){ | |
65 | pciBus::module_deleted(mmi_instance_t, const char *target_name){ | |
66 | if (!strcmp(bridgeName, target_name)) { | |
67 | debug_info("%s: bridge <%s> disconnected\n", HERE, bridgeName); | |
68 | bridgeMod = 0; | |
69 | bridgeIf = 0; | |
70 | }else{ | |
71 | busif_delete_device(target_name); | |
72 | } | |
73 | } | |
74 | ||
75 | void * | |
76 | pciBus::get_interface(const char *name){ | |
77 | if (!strcmp(name, PCI_BUS_INTERFACE)) | |
78 | return (pciBusIf*)this; | |
79 | return 0; | |
80 | } | |
81 | ||
82 | bool | |
83 | pciBus::check_args(){ | |
84 | if (!bridgeName) { | |
85 | debug_err("%s: ERROR: must specify a host bridge\n", HERE); | |
86 | return false; | |
87 | } | |
88 | ||
89 | return true; | |
90 | } | |
91 | ||
92 | const char * | |
93 | pciBus::get_help(){ | |
94 | return Module::get_help_string(); | |
95 | } | |
96 | ||
97 | ||
98 | const char * | |
99 | Module::get_help_string(){ | |
100 | return "new pci bus impl"; | |
101 | } | |
102 | ||
103 | ||
104 | ||
105 | Module * | |
106 | Module::create(const char *_modname, const char *_instance_name){ | |
107 | return new pciBus(_modname, _instance_name); | |
108 | } | |
109 | ||
110 | pciBus::pciBus(const char *_modname, const char *_instance_name) | |
111 | : Module(_modname, _instance_name), | |
112 | bridgeName(0), bridgeMod(0), bridgeIf(0){} | |
113 | ||
114 | pciBus::~pciBus(){ | |
115 | debug_more("%s: destructor\n", HERE); | |
116 | } | |
117 | ||
118 | ||
119 | /////////////////////exported interface functions/////////////// | |
120 | ||
121 | bool pciBus::busif_add_device(const char *devname, uint8_t device, uint8_t function){ | |
122 | ||
123 | debug_info("%s: busif_add_device: <%s> dev=%d fun=%d\n", HERE, devname, device, function); | |
124 | ||
125 | mmi_instance_t dev_instance = mmi_get_instance(devname); | |
126 | ||
127 | if(dev_instance == 0){ | |
128 | debug_err("%s: Device named <%s> is not a module\n", HERE, devname); | |
129 | return false; | |
130 | } | |
131 | ||
132 | if(searchDevInfoListByName(devname)){ | |
133 | debug_err("%s: Device named <%s> already exists\n", HERE, devname); | |
134 | return false; | |
135 | } | |
136 | ||
137 | if(searchDevInfoListByDevFun(device,function)){ | |
138 | debug_err("%s: Can't install <%s>: device already exists at dev=%d fun=%d\n",\ | |
139 | HERE, devname, device, function); | |
140 | return false; | |
141 | } | |
142 | ||
143 | genericPciDevIf * dI = (genericPciDevIf*)mmi_get_interface(dev_instance,PCI_GENERIC_DEV_INTERFACE); | |
144 | if(dI == 0){ | |
145 | debug_err("%s: Device named <%s> has no device interface\n", HERE, devname); | |
146 | return false; | |
147 | } | |
148 | ||
149 | pciDevInfo* devInfo = new pciDevInfo(devname, dev_instance, dI, device, function); | |
150 | uint64_t base = device << 11 | function << 8; | |
151 | ||
152 | //map the configuration space. this space is always accessible and cannot be unmapped etc. | |
153 | if(!addSpace(new pciRange(base, base + 0xff, devInfo),PCI_CFG)){ | |
154 | debug_err("%s: cannot add configuration space for <%s>. Conflict in ranges!!\n",HERE,devname); | |
155 | return false; | |
156 | } | |
157 | devInfoList.push_back(devInfo); | |
158 | return true; | |
159 | } | |
160 | ||
161 | bool | |
162 | pciBus::busif_delete_device(const char *devname){ | |
163 | pciDevInfo * pdi = searchDevInfoListByName(devname); | |
164 | if(pdi){ | |
165 | removeMap(pdi); | |
166 | devInfoList.remove(pdi); | |
167 | delete(pdi); | |
168 | return true; | |
169 | }else{ | |
170 | debug_err("%s: cannot remove <%s>. non - existent device !!\n",HERE,devname); | |
171 | return false; | |
172 | } | |
173 | } | |
174 | ||
175 | ||
176 | bool pciBus::busif_map(const char *devname, pci_space_t space, uint64_t base, uint64_t size){ | |
177 | ||
178 | if(size == 0) | |
179 | return true; | |
180 | ||
181 | pciDevInfo * pdi = searchDevInfoListByName(devname); | |
182 | ||
183 | if(pdi){ | |
184 | if(!addSpace(new pciRange(base, base + size - 1,pdi),space)){ | |
185 | debug_more("busif_map: can not map in space for device <%s>. Conflicting range!!\n", devname); | |
186 | return false; | |
187 | } | |
188 | return true; | |
189 | }else{ | |
190 | debug_err("busif_map: device <%s> is not added to bus list\n",devname); | |
191 | return false; | |
192 | } | |
193 | } | |
194 | ||
195 | bool pciBus::busif_unmap(const char *devname, pci_space_t space,uint64_t base){ | |
196 | pciDevInfo * pdi = searchDevInfoListByName(devname); | |
197 | ||
198 | if(pdi){ | |
199 | if(!removeSpace(base, space)){ | |
200 | debug_err("busif_unmap: can not unmap space for device <%s>. map does not exist!!\n", devname); | |
201 | return false; | |
202 | } | |
203 | return true; | |
204 | }else{ | |
205 | debug_err("busif_unmap: device <%s> is not added to bus list\n",devname); | |
206 | return false; | |
207 | } | |
208 | } | |
209 | ||
210 | // interrupts | |
211 | int | |
212 | pciBus::busif_add_interrupt(int dev_num, int dev_type, int *slot_irl, bool isMultiFunction){ | |
213 | if (bridgeIf) | |
214 | return bridgeIf->busif_add_interrupt(getInstance(), dev_num, dev_type,slot_irl,isMultiFunction); | |
215 | return -1; | |
216 | } | |
217 | ||
218 | int | |
219 | pciBus::busif_free_interrupt(int dev_number){ | |
220 | if (bridgeIf) | |
221 | return bridgeIf->busif_free_interrupt(getInstance(),dev_number); | |
222 | return -1; | |
223 | } | |
224 | ||
225 | bool | |
226 | pciBus::busif_interrupt_in(bool set,int dev_num, int line, SAM_DeviceId *id) | |
227 | { | |
228 | if (bridgeIf){ | |
229 | bridgeIf->busif_interrupt_in(set,getInstance(),dev_num,line, id); | |
230 | return true; | |
231 | } | |
232 | return false; | |
233 | } | |
234 | ||
235 | uint64_t | |
236 | pciBus::busif_get_lowest_base(pci_space_t space, uint64_t sz){ | |
237 | pciDevMapIterator dmIter; | |
238 | dmIter = pciAddrSpace[space].begin(); | |
239 | ||
240 | if(dmIter == pciAddrSpace[space].end()){ | |
241 | debug_info("%s:returning address 0x%llx, size %llx, space %s\n",getName(),0,sz,pci_space_name(space)); | |
242 | ||
243 | return 0; // there is no other mapped device. | |
244 | } | |
245 | ||
246 | uint64_t end_prev = dmIter->second->end; | |
247 | uint64_t base = 0; | |
248 | ||
249 | dmIter++; | |
250 | for(; dmIter !=pciAddrSpace[space].end(); dmIter++){ | |
251 | uint64_t base_cur = dmIter->second->base; | |
252 | base = end_prev + 1; | |
253 | // align base to 'sz' bytes | |
254 | if(base % sz != 0) | |
255 | base = base + (sz - base%sz); | |
256 | ||
257 | if( (base_cur - base ) >= sz) | |
258 | debug_info("%s:returning address %llx, size%llx, space %s\n",getName(),base,sz,pci_space_name(space)); | |
259 | return base; | |
260 | ||
261 | end_prev = dmIter->second->end; | |
262 | } | |
263 | ||
264 | // no fit found till the end of list. | |
265 | base = end_prev + 1; | |
266 | if(base % sz != 0) | |
267 | base = base + (sz - base%sz); | |
268 | debug_info("%s:returning address %llx, size%llx, space %s\n",getName(),base,sz,pci_space_name(space)); | |
269 | return base; | |
270 | } | |
271 | ||
272 | ||
273 | pciXactnStatus | |
274 | pciBus::busif_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){ | |
275 | debug_info("%s: %s %s: paddr %llx offset %llx size %x\n", HERE, wr?"WRITE":"READ ", pci_space_name(space), paddr, offset, size); | |
276 | ||
277 | if(space == PCI_CFG){ | |
278 | int target_bus = offset >> 16 & 0xff; | |
279 | if(target_bus != busif_get_busno()){ | |
280 | printf("%s: type 1 transactions not supported on pci bus\n",getName()); | |
281 | return MASTER_ABORT; | |
282 | } | |
283 | offset -= busif_get_busno() << 16; | |
284 | } | |
285 | ||
286 | pciDevMapIterator dmIter; | |
287 | dmIter = pciAddrSpace[space].lower_bound(offset); | |
288 | ||
289 | //dmIter->second->print(); | |
290 | ||
291 | if(dmIter == pciAddrSpace[space].end()){ | |
292 | debug_more("unmapped access space = %s paddr=%llx, offset=%llx\n",pci_space_name(space), paddr,offset); | |
293 | return MASTER_ABORT; | |
294 | }else if(dmIter->second->end < offset){ | |
295 | debug_more("unmapped access space = %s paddr=%llx, offset=%llx\n",pci_space_name(space), paddr,offset); | |
296 | return MASTER_ABORT; | |
297 | }else{ | |
298 | if(debug_level >= 2) | |
299 | dmIter->second->print(); | |
300 | //return (dmIter->second->devInfo->devIf->devif_access_w_size(space, paddr, (offset - dmIter->second->base), wr, buf, size)); | |
301 | return (dmIter->second->devInfo->devIf->devif_access_w_size(space, paddr, offset, wr, buf, size, id)); | |
302 | } | |
303 | } | |
304 | ||
305 | ||
306 | pciXactnStatus pciBus::busif_access_w_byte_enables(pci_space_t space, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t byte_enable, SAM_DeviceId * id){ | |
307 | debug_info("%s: %s %s: paddr %llx offset %llx byte_enable %x\n", HERE, wr?"WRITE":"READ ", pci_space_name(space), paddr, offset, byte_enable); | |
308 | ||
309 | pciDevMapIterator dmIter; | |
310 | ||
311 | dmIter = pciAddrSpace[space].upper_bound(offset); | |
312 | ||
313 | if(dmIter == pciAddrSpace[space].end()){ | |
314 | debug_err("unmapped access space = %s paddr=%llx\n",pci_space_name(space), paddr); | |
315 | return MASTER_ABORT; | |
316 | }else if(dmIter->second->end < offset){ | |
317 | debug_err("unmapped access space = %s paddr=%llx\n",pci_space_name(space), paddr); | |
318 | return MASTER_ABORT; | |
319 | }else{ | |
320 | if(debug_level >= 2) | |
321 | dmIter->second->print(); | |
322 | if(space == PCI_CFG) | |
323 | offset -= busif_get_busno() << 16; | |
324 | return (dmIter->second->devInfo->devIf->devif_access_w_size(space, paddr, (offset - dmIter->second->base), wr, buf, byte_enable, id)); | |
325 | } | |
326 | } | |
327 | ||
328 | ||
329 | pciXactnStatus | |
330 | pciBus::busif_dma(bool wr, uint64_t vaddr, void *data, long count, SAM_DeviceId *id){ | |
331 | debug_info("%s: busif_dma_%s: vaddr 0x%llx count 0x%x\n", HERE, wr?"write":"read",vaddr, count); | |
332 | ||
333 | assert(bridgeIf); | |
334 | ||
335 | if(wr) | |
336 | bridgeIf->busif_dma_out(vaddr, data, count, getInstance(), 0, id); | |
337 | else | |
338 | bridgeIf->busif_dma_in(vaddr, data, count, getInstance(), 0, id); | |
339 | ||
340 | return SUCCESS; | |
341 | } | |
342 | ||
343 | pciXactnStatus pciBus::busif_special_cycle(uint16_t mssg, uint16_t data){ | |
344 | list<pciDevInfo *>::iterator i; | |
345 | ||
346 | for(i = devInfoList.begin(); i != devInfoList.end(); i++) | |
347 | (*i)->devIf->devif_special_cycle(mssg,data); | |
348 | ||
349 | return MASTER_ABORT; | |
350 | } | |
351 | ||
352 | pciXactnStatus pciBus::busif_intr_ack(uint64_t * data){ | |
353 | list<pciDevInfo *>::iterator i; | |
354 | ||
355 | for(i = devInfoList.begin(); i != devInfoList.end(); i++) | |
356 | (*i)->devIf->devif_intr_ack(data); | |
357 | ||
358 | return SUCCESS; | |
359 | } | |
360 | ||
361 | ||
362 |