Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / pcie_bus / pcie_bus.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: pcie_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 "pcie_bus.h"
22//////////////////module functions////////////////
23
24// print interesting info about this module
25void
26pcieBus::modinfo(){
27
28 pcieDevMapIterator dmIter;
29 printf(" bridge=<%s>\n", bridgeName);
30
31 for(uint8_t i = 0; i < 3; i++){
32 printf("%s",pcie_space_name((pcie_space)i));
33 printf("::devices:\n");
34 for(dmIter = pcieAddrSpace[i].begin(); dmIter != pcieAddrSpace[i].end(); dmIter++)
35 dmIter->second->print();
36 }
37}
38
39// parse an arg
40bool
41pcieBus::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
50void
51pcieBus::module_added(mmi_instance_t target_mod, const char *target_name){
52 if (!strcmp(bridgeName, target_name)) {
53 bridgeMod = target_mod;//mmi_get_module(bridgeName);
54 // let the bridge set the interface it wants to export
55 // instead of the other way round
56
57 // bridgeIf = (genericPcieDevIf*) mmi_get_interface(bridgeMod, GENERIC_PCIE_DEV_INTERFACE);
58
59 //if (bridgeIf)
60 // debug_info("%s: bridge <%s> connected\n", HERE, bridgeName);
61 //else
62 // debug_err("%s: ERROR: bridge <%s> has no interface\n", HERE, bridgeName);
63 }
64}
65
66void
67pcieBus::module_deleted(mmi_instance_t, const char *target_name){
68 if (!strcmp(bridgeName, target_name)) {
69 debug_info("%s: bridge <%s> disconnected\n", HERE, bridgeName);
70 bridgeMod = 0;
71 bridgeIf = 0;
72 }else{
73 busif_deleteDevice(target_name);
74 }
75}
76
77void *
78pcieBus::get_interface(const char *name){
79 if (!strcmp(name, PCIE_BUS_INTERFACE))
80 return (pcieBusIf*)this;
81 return 0;
82}
83
84bool
85pcieBus::check_args(){
86 if (!bridgeName) {
87 debug_err("%s: ERROR: must specify a host bridge\n", HERE);
88 return false;
89 }
90 return true;
91}
92
93const char *
94pcieBus::get_help(){
95 return Module::get_help_string();
96}
97
98
99const char *
100Module::get_help_string(){
101 return "new pcie bus impl";
102}
103
104
105
106Module *
107Module::create(const char *_modname, const char *_instance_name){
108 return new pcieBus(_modname, _instance_name);
109}
110
111pcieBus::pcieBus(const char *_modname, const char *_instance_name)
112 : Module(_modname, _instance_name),
113 bridgeName(0), bridgeMod(0), bridgeIf(0){}
114
115pcieBus::~pcieBus(){
116 debug_more("%s: destructor\n", HERE);
117}
118
119
120/////////////////////exported interface functions///////////////
121
122bool pcieBus::busif_addDevice(const char *devname, int device, int function){
123
124 debug_info("%s: busif_addDevice: <%s> dev=%d fun=%d\n", HERE, devname, device, function);
125
126 mmi_instance_t dev_instance = mmi_get_instance(devname);
127
128 if(dev_instance == 0){
129 debug_err("%s: Device named <%s> is not a module\n", HERE, devname);
130 return false;
131 }
132
133 if(searchDevInfoListByName(devname)){
134 debug_err("%s: Device named <%s> already exists\n", HERE, devname);
135 return false;
136 }
137
138 if(searchDevInfoListByDevFun(device,function)){
139 debug_err("%s: Can't install <%s>: device already exists at dev=%d fun=%d\n",\
140 HERE, devname, device, function);
141 return false;
142 }
143
144 genericPcieDevIf * dI = (genericPcieDevIf*)mmi_get_interface(dev_instance,GENERIC_PCIE_DEV_INTERFACE);
145 if(dI == 0){
146 debug_err("%s: Device named <%s> has no device interface\n", HERE, devname);
147 return false;
148 }
149
150 pcieDevInfo* devInfo = new pcieDevInfo(devname, dev_instance, dI, device, function);
151 uint64_t base = device << devShift | function << funShift; // 4 kb configuration space
152 // the mappings are local to this bus segment, hence no need for the bus number here
153 // which is needed for the global address resolution
154
155 //map the configuration space. this space is always accessible and cannot be unmapped etc.
156 if(!addSpace(new pcieRange(base, base + 0xfff, devInfo),PCIE_CFG)){
157 debug_err("%s: cannot add configuration space for <%s>. Conflict in ranges!!\n",HERE,devname);
158 return false;
159 }
160 devInfoList.push_back(devInfo);
161 return true;
162}
163
164bool
165pcieBus::busif_deleteDevice(const char *devname){
166 pcieDevInfo * pdi = searchDevInfoListByName(devname);
167 if(pdi){
168 removeMap(pdi);
169 devInfoList.remove(pdi);
170 delete(pdi);
171 return true;
172 }else{
173 debug_err("%s: cannot remove <%s>. non - existent device !!\n",HERE,devname);
174 return false;
175 }
176}
177
178
179bool pcieBus::busif_map(const char *devname, pcie_space space, uint64_t base, uint64_t size){
180
181 if(size == 0)
182 return true;
183
184 pcieDevInfo * pdi = searchDevInfoListByName(devname);
185
186 if(pdi){
187 if(!addSpace(new pcieRange(base, base + size - 1,pdi),space)){
188 debug_more("busif_map: can not map in space for device <%s>. Conflicting range!!\n", devname);
189 return false;
190 }
191 return true;
192 }else{
193 debug_err("busif_map: device <%s> is not added to bus list\n",devname);
194 return false;
195 }
196}
197
198bool pcieBus::busif_unmap(const char *devname, pcie_space space,uint64_t base){
199 pcieDevInfo * pdi = searchDevInfoListByName(devname);
200
201 if(pdi){
202 if(!removeSpace(base, space)){
203 debug_err("busif_unmap: can not unmap space for device <%s>. map does not exist!!\n", devname);
204 return false;
205 }
206 return true;
207 }else{
208 debug_err("busif_unmap: device <%s> is not added to bus list\n",devname);
209 return false;
210 }
211}
212
213
214
215
216int pcieBus::busif_getBusno(){
217 int bus = bridgeIf->devif_getBusNo();
218 assert(bus != -1);
219 return bus;
220}
221
222pcieCompleter pcieBus::busif_msgAccess(uint8_t messageCode, msgRouting route, uint16_t reqId, SAM_DeviceId *id,\
223 uint64_t tarIdOrAddr, \
224 void * data, uint16_t length, \
225 uint16_t vendorId, uint32_t vendor_data, tlp_X args){
226
227 switch(route){
228 case routed_to_RC:
229 // send it to the upstream bridge. If its not an RC it should forward the message upstream
230 return bridgeIf->devif_msgAccess(messageCode,route,tarIdOrAddr,reqId,data,length,vendorId, \
231 vendor_data, args, id);
232 case routed_by_addr:
233 // XXX not clear if the address is in MEM space or IO space or some other space from specs.
234 // the specs however say no messages defined currently use this routing. hence print an error
235 // message for now.
236 debug_err("%s: address routing unsupported \n", getName());
237 break;
238 case routed_by_id:
239 {
240 int targetBus = tarIdOrAddr >> 8 & 0xff;
241 if(targetBus != busif_getBusno()){
242 // message not intended for this bus segment
243 // send the message to the bridge for further routing
244 return bridgeIf->devif_msgAccess(messageCode,route,tarIdOrAddr,reqId,data,length,vendorId, \
245 vendor_data, args, id);
246 }
247 // target device on this bus segment
248 pcieDevInfo* devInfo = searchDevInfoListByDevFun(tarIdOrAddr >> 3 & 0x1f, tarIdOrAddr & 0x7);
249 if(devInfo){
250 return devInfo->devIf->devif_msgAccess(messageCode, route,tarIdOrAddr,reqId, data, length, \
251 vendorId, vendor_data, args, id);
252 }else{
253 debug_err("error %s:busif_msgAccess() - target %llx not present on this bus segment",getName(),tarIdOrAddr);
254 return pcieCompleter(SIM_FAIL);
255 }
256 }
257 case broadcast_from_RC:
258 {
259 // call the msgAccess function of all the downstream devices/functions
260 list<pcieDevInfo *>::iterator i;
261 for(i = devInfoList.begin(); i != devInfoList.end(); i++){
262 if((*i)->devIf != bridgeIf)
263 (*i)->devIf->devif_msgAccess(messageCode,route,tarIdOrAddr,reqId,data,length,vendorId,vendor_data, args, id);
264 }
265 break;
266 }
267 case local:
268 // should be terminated at the upstream endpoint. hence this message is just sent to the bridge.
269 // mesg could be intx, etc,
270 return bridgeIf->devif_msgAccess(messageCode,route,tarIdOrAddr,reqId,data,length,vendorId, \
271 vendor_data, args, id);
272 case gathered_routed_to_RC:
273 // send to the upstream switch. the switch gathers this message from all downstream devices
274 // and sends the mesg to RC ..
275 return bridgeIf->devif_msgAccess(messageCode,route,tarIdOrAddr,reqId,data,length,vendorId, \
276 vendor_data, args, id);
277 default:
278 debug_err("%s: unknown message routing type %x\n",getName(),route);
279 return pcieCompleter(SIM_FAIL);
280 }
281 return pcieCompleter(SIM_OK);
282}
283pcieCompleter pcieBus::busif_access(pcie_space space, bool wr, uint64_t addr, void * data, \
284 uint16_t length, uint8_t be, uint16_t reqId, addrMd_xactnType am_xt, SAM_DeviceId *id, tlp_X args){
285
286 genericPcieDevIf * targetDev;
287 debug_info("%s: %s %s: addr %llx length %x be 0x%x \n", getName(), wr?"WRITE":"READ ", \
288 pcie_space_name(space), addr, length, be);
289
290 if(space == PCIE_CFG){
291 int bus = addr >> busShift & 0xff;
292 if(bus != busif_getBusno()){
293 // configuration access that does not belong to this bus segment.
294 // forward to bridge downstream
295 list<pcieDevInfo *>::iterator i;
296 for(i = devInfoList.begin(); i != devInfoList.end(); i++){
297 if((*i)->devIf != bridgeIf){
298 if((*i)->devIf->devif_isBridge() == false)
299 continue;
300 int secbus = (*i)->devIf->devif_getBusNo();
301 int subbus = (*i)->devIf->devif_getSubBusNo();
302 if((bus >= secbus) && (bus <= subbus))
303 return (*i)->devIf->devif_confAccess(wr,addr,data,be,reqId,conf_type1,length,args,id);
304 }
305 }
306 debug_err("%s: unable to route config space access at addr %llx", getName(), addr);
307 return pcieCompleter(CA);
308 }
309 }
310
311 if(space == PCIE_CFG)
312 // get the address relative to this bus hierarchy
313 addr -= busif_getBusno() << busShift;
314
315 pcieDevMapIterator dmIter;
316 dmIter = pcieAddrSpace[space].lower_bound(addr);
317
318 if(dmIter == pcieAddrSpace[space].end()){
319 // possible dma/dvma space
320 if(reqId == getBridgeId())
321 return pcieCompleter(CA);
322 debug_more("%s: unmapped access space = %s addr=%llx, forwarding to bridge\n",getName(),pcie_space_name(space), addr);
323 targetDev = bridgeIf;
324 }else if(dmIter->second->end < addr){
325 // if the request is from the upstream bridge, don't send it back to it
326 if(reqId == getBridgeId())
327 return pcieCompleter(CA);
328 debug_more("%s: unmapped access space = %s addr=%llx, forwarding to bridge\n",getName(),pcie_space_name(space), addr);
329 targetDev = bridgeIf;
330 }else{
331 targetDev = dmIter->second->devInfo->devIf;
332 if(debug_level >= 2)
333 dmIter->second->print();
334 }
335
336 switch(space){
337 case PCIE_CFG:
338 // get the conf space offset
339 addr -= (dmIter->second->devInfo->device << devShift) + (dmIter->second->devInfo->function << funShift);
340 return targetDev->devif_confAccess(wr,addr,data,be,reqId,conf_type0, length,args,id);
341 case PCIE_MEM:
342 return targetDev->devif_memAccess(wr,addr,am_xt,data,length,be,reqId,args,id);
343 case PCIE_IO:
344 return targetDev->devif_ioAccess(wr,addr,data,be,reqId,length,args,id);
345 default:
346 debug_err("%s: unknown pcie space %d accessed\n",space);
347 return pcieCompleter(CA);
348 }
349}
350
351mmi_instance_t pcieBus::getDevInstance(int dev,int fun){
352
353 pcieDevInfo * di = searchDevInfoListByDevFun(dev,fun);
354 if(di)
355 return di->instance;
356 else
357 return 0;
358}
359
360/*
361pcieCompleter pcieBus::busif_access(pcie_space space, bool wr, uint64_t addr, void * data, \
362 uint16_t length, uint8_t be, uint16_t reqId, addrMd_xactnType am_xt, tlp_X args){
363
364
365 genericPcieDevIf * targetDev;
366 debug_info("%s: %s %s: addr %llx length %x be 0x%x \n", getName(), wr?"WRITE":"READ ", \
367 pcie_space_name(space), addr, length, be);
368
369 if(space == PCIE_CFG){
370 int bus = addr >> busShift & 0xff;
371 if(bus != busif_getBusno()){
372 // configuration access that does not belong to this bus segment.
373 // forward to bridges downstream, or upstream.
374 if( bus == bridgeIf->devif_getPriBusNo() ){
375 // access the upstream bridge
376 return bridgeIf->devif_confAccess(wr,addr,data,be,reqId,conf_type1,length,args);
377 }else{
378 // check each downstream device for being a bridge.
379 // if yes, check if the target bus falls between its secondary
380 // and subordinate bus number. if yes, send the xactn to it.
381 list<pcieDevInfo *>::iterator i;
382 for(i = devInfoList.begin(); i != devInfoList.end(); i++){
383 if((*i)->devIf != bridgeIf){
384 if((*i)->devIf->devif_isBridge() == false)
385 continue;
386 int secbus = (*i)->devIf->devif_getBusNo();
387 int subbus = (*i)->devIf->devif_getSubBusNo();
388 if((bus >= secbus) && (bus <= subbus))
389 return (*i)->devIf->devif_confAccess(wr,addr,data,be,reqId,conf_type1,length,args);
390 }
391 }
392 debug_err("%s: unable to route config space access at addr %llx", getName(), addr);
393 return pcieCompleter(CA);
394 }
395 }else{
396 // get the address relative to this bus hierarchy
397 addr -= busif_getBusno() << busShift;
398 pcieDevMapIterator dmIter;
399 dmIter = pcieAddrSpace[space].lower_bound(addr);
400 if(dmIter == pcieAddrSpace[space].end()){
401 if(reqId == getBridgeId())
402 // access is from the upstream bridge, and
403 // no device exist at specified config address
404 return pcieCompleter(CA);
405 }else{
406 // device belongs to this bus.
407 if(debug_level >= 2)
408 dmIter->second->print();
409 addr -= (dmIter->second->devInfo->device << devShift) + (dmIter->second->devInfo->function << funShift);
410 return targetDev->devif_confAccess(wr,addr,data,be,reqId,conf_type0, length,args);
411 }
412 }
413 }
414
415
416 // space is either MEM, or IO.
417
418}
419*/