Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / pci_bus / pci_bus.cc
CommitLineData
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
25void
26pciBus::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
40bool
41pciBus::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
51//pciBus::module_added(mmi_instance_t, const char *target_name){
52pciBus::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
63void
64//pciBus::module_deleted(mmi_instance_t, const char *target_name){
65pciBus::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
75void *
76pciBus::get_interface(const char *name){
77 if (!strcmp(name, PCI_BUS_INTERFACE))
78 return (pciBusIf*)this;
79 return 0;
80}
81
82bool
83pciBus::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
92const char *
93pciBus::get_help(){
94 return Module::get_help_string();
95}
96
97
98const char *
99Module::get_help_string(){
100 return "new pci bus impl";
101}
102
103
104
105Module *
106Module::create(const char *_modname, const char *_instance_name){
107 return new pciBus(_modname, _instance_name);
108}
109
110pciBus::pciBus(const char *_modname, const char *_instance_name)
111 : Module(_modname, _instance_name),
112 bridgeName(0), bridgeMod(0), bridgeIf(0){}
113
114pciBus::~pciBus(){
115 debug_more("%s: destructor\n", HERE);
116}
117
118
119/////////////////////exported interface functions///////////////
120
121bool 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
161bool
162pciBus::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
176bool 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
195bool 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
211int
212pciBus::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
218int
219pciBus::busif_free_interrupt(int dev_number){
220 if (bridgeIf)
221 return bridgeIf->busif_free_interrupt(getInstance(),dev_number);
222 return -1;
223}
224
225bool
226pciBus::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
235uint64_t
236pciBus::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
273pciXactnStatus
274pciBus::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
306pciXactnStatus 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
329pciXactnStatus
330pciBus::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
343pciXactnStatus 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
352pciXactnStatus 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