Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: bridge.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 "bridge.h" | |
22 | #include <unistd.h> | |
23 | #include <assert.h> | |
24 | #include <errno.h> | |
25 | ||
26 | static const char * pcieToPciBridge_help = "\n\ | |
27 | SAM model for Intel 41210 Serial to Parallel PCIE-PCI bridge\n\ | |
28 | Sysconf format is:\n\ | |
29 | sysconf bridge <instance name> bus=<primary bus> dev=<device> fun=<function> secbus=<secondary bus>\n\ | |
30 | <instance name> is any user specified name for the module\n\ | |
31 | <primary bus> is the instance name of the upstream pcie bus module\n\ | |
32 | <device> is the device number of bridge on upstream pcie bus\n\ | |
33 | <function> is the function number of bridge on upstream pcie bus\n\ | |
34 | <secondary bus> is the instance name of the downstream pci bus module\n\ | |
35 | For UI help type <instance name>\n\ | |
36 | For module specific info type \'modinfo <instance name>\'"; | |
37 | ||
38 | pcieToPciBridge_ui_cmd (void * obj, int argc, char * argv[]){ | |
39 | pcieToPciBridge * i = dynamic_cast<pcieToPciBridge*>((Module *)obj); | |
40 | i->handle_ui(argc, argv); | |
41 | return 0; | |
42 | } | |
43 | ||
44 | ||
45 | #define BRIDGE_CAP_STRUCT_ADDR 0x44 | |
46 | #define BRIDGE_MSI_CAP_ADDR 0x5c | |
47 | #define BRIDGE_POWER_CAP_ADDR 0x6c | |
48 | #define BRIDGE_PCIX_CAP_ADDR 0xd8 | |
49 | #define BRIDGE_AER_CAP_OFFSET 0x100 | |
50 | #define BRIDGE_POWER_BUDGET_CAP_OFFSET 0x300 | |
51 | ||
52 | ||
53 | const char * | |
54 | Module::get_help_string(){ | |
55 | return pcieToPciBridge_help; | |
56 | } | |
57 | ||
58 | Module * | |
59 | Module::create(const char *_modname, const char *_instance_name){ | |
60 | return new pcieToPciBridge(_modname, _instance_name); | |
61 | } | |
62 | ||
63 | ||
64 | ||
65 | pcieToPciBridge::pcieToPciBridge(const char* modname, const char * instance_name) | |
66 | : Module(modname, instance_name){ | |
67 | debug_info("Pcie bridge: creating instance %s\n", instance_name); | |
68 | mem32_base = mem32_limit = 0; | |
69 | mem64_base = mem64_limit = 0; | |
70 | io_base = io_limit = 0; | |
71 | bCR = 0; | |
72 | mmi_register_instance_cmd(getInstance(),pcieToPciBridge_help,pcieToPciBridge_ui_cmd); | |
73 | pendingIntr[0] = pendingIntr[1] = pendingIntr[2] = pendingIntr[3] = false; | |
74 | assert(pthread_mutex_init(&intMutex,0) == 0); | |
75 | dump_version1_0 = strdup("v1.0"); // never change | |
76 | current_dump_version = dump_version1_0; // change if when dump format changes, | |
77 | // i.e. point current to new version | |
78 | // string | |
79 | } | |
80 | ||
81 | pcieToPciBridge::~pcieToPciBridge(){ | |
82 | debug_info("%s: destructor\n", HERE); | |
83 | } | |
84 | ||
85 | const char * | |
86 | pcieToPciBridge::get_help(){ | |
87 | return Module::get_help_string(); | |
88 | } | |
89 | ||
90 | ||
91 | void | |
92 | pcieToPciBridge::initPci(){ | |
93 | char reg_descr[100]; | |
94 | ||
95 | snprintf(reg_descr, 100, "%s-%s Vender ID", devif_getName(),busName); | |
96 | confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x8086,0x0,0x0),PCI_CONF_VENID); | |
97 | ||
98 | snprintf(reg_descr, 100, "%s-%s Device ID", devif_getName(),busName); | |
99 | confSpace->addConfReg(new pciConfReg(reg_descr, 2,function?0x0341:0x0340,0x0,0x0),PCI_CONF_DEVID); | |
100 | ||
101 | snprintf(reg_descr, 100, "%s-%s command register", devif_getName(),busName); | |
102 | confSpace->addConfReg(new bridgeCommandReg(reg_descr,(genericPcieDev*)this,0x547,0x0),PCI_CONF_COMM);// write mask = 0x547 | |
103 | ||
104 | snprintf(reg_descr,100,"%s-%s Primary device status reg", devif_getName(),busName); | |
105 | confSpace->addConfReg(new pcieStatusReg(reg_descr,(genericPcieDev*)this,0x10,0xf900),PCI_CONF_STAT);//write mask = 0xf900 | |
106 | // this reg has some rw1c bit fields. over-ride the pciStatusReg class r/w functions in case OS ever complains. | |
107 | ||
108 | snprintf(reg_descr,100,"%s-%s revision id", devif_getName(),busName); | |
109 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0,0x0),PCI_CONF_REVID);// rev id = 0x00, ro | |
110 | ||
111 | snprintf(reg_descr,100,"%s-%s prog interface",devif_getName(),busName); | |
112 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_PROGCLASS);//0x00, ro | |
113 | ||
114 | snprintf(reg_descr,100,"%s-%s sub class",devif_getName(),busName); | |
115 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x4,0x0),PCI_CONF_SUBCLASS);//0x04, ro | |
116 | ||
117 | snprintf(reg_descr,100,"%s-%s base class",devif_getName(),busName); | |
118 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x06,0x0),PCI_CONF_BASCLASS);//0x06, ro | |
119 | ||
120 | snprintf(reg_descr,100,"%s-%s cache line size",devif_getName(),busName); | |
121 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_CONF_CACHE_LINESZ);//0x00, | |
122 | ||
123 | snprintf(reg_descr,100,"%s-%s latency timer",devif_getName(),busName); | |
124 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_LATENCY_TIMER);//0x00, | |
125 | ||
126 | snprintf(reg_descr,100,"%s-%s Header type",devif_getName(),busName); | |
127 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x81,0x00),PCI_CONF_HEADER); | |
128 | ||
129 | snprintf(reg_descr,100,"%s-%s Primary Bus No",devif_getName(),busName); | |
130 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_PRIBUS);//0x00, rw | |
131 | ||
132 | snprintf(reg_descr,100,"%s-%s Secondary Bus No",devif_getName(),busName); | |
133 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_SECBUS);//0x00, rw | |
134 | ||
135 | snprintf(reg_descr,100,"%s-%s Subordinate Bus No",devif_getName(),busName); | |
136 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_BCNF_SUBBUS);//0x00, rw | |
137 | ||
138 | snprintf(reg_descr,100,"%s-%s Secondary Master Latency Timer",devif_getName(),busName); | |
139 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x40,0xf8),PCI_BCNF_LATENCY_TIMER);//0x40, rw | |
140 | ||
141 | snprintf(reg_descr,100,"%s-%s I/O Base",devif_getName(),busName); | |
142 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf0),PCI_BCNF_IO_BASE_LOW);//0x00, rw | |
143 | ||
144 | snprintf(reg_descr,100,"%s-%s I/O Limit",devif_getName(),busName); | |
145 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf0),PCI_BCNF_IO_LIMIT_LOW);//0x00, rw | |
146 | ||
147 | snprintf(reg_descr,100,"%s-%s Secondary Status",devif_getName(),busName); | |
148 | confSpace->addConfReg(new pciSecondaryStatusReg(0x2a,0xf900,0,reg_descr),PCI_BCNF_SEC_STATUS);//0x2a, rw | |
149 | ||
150 | snprintf(reg_descr,100,"%s-%s Memory Base",devif_getName(),busName); | |
151 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x00,0xfff0),PCI_BCNF_MEM_BASE);//0x00, rw | |
152 | ||
153 | snprintf(reg_descr,100,"%s-%s Memory Limit",devif_getName(),busName); | |
154 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x00,0xfff0),PCI_BCNF_MEM_LIMIT);//0x00, rw | |
155 | ||
156 | snprintf(reg_descr,100,"%s-%s Prefetchable Memory Base",devif_getName(),busName); | |
157 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x01,0xfff0),PCI_BCNF_PF_BASE_LOW);//0x01, rw | |
158 | ||
159 | snprintf(reg_descr,100,"%s-%s Prefetchable Memory Limit",devif_getName(),busName); | |
160 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x01,0xfff0),PCI_BCNF_PF_LIMIT_LOW);//0x01, rw | |
161 | ||
162 | snprintf(reg_descr,100,"%s-%s Prefetchable Memory Base Upper Portion",devif_getName(),busName); | |
163 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xffffffff),PCI_BCNF_PF_BASE_HIGH);//0x0, rw | |
164 | ||
165 | snprintf(reg_descr,100,"%s-%s Prefetchable Memory Limit Upper Portion",devif_getName(),busName); | |
166 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0xffffffff),PCI_BCNF_PF_LIMIT_HIGH);//0x0, rw | |
167 | ||
168 | snprintf(reg_descr,100,"%s-%s I/O Base High",devif_getName(),busName); | |
169 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),PCI_BCNF_IO_BASE_HI); //0x0, RO | |
170 | ||
171 | snprintf(reg_descr,100,"%s-%s I/O Limit High",devif_getName(),busName); | |
172 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),PCI_BCNF_IO_LIMIT_HI); //0x0, RO | |
173 | ||
174 | snprintf(reg_descr,100,"%s-%s Capabilities List Pointer",devif_getName(),busName); | |
175 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x44,0x0),PCI_BCNF_CAP_PTR); //0x44, RO | |
176 | ||
177 | snprintf(reg_descr,100,"%s-%s Interrupt Line",devif_getName(),busName); | |
178 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_BCNF_ILINE); //0x0, RW | |
179 | ||
180 | snprintf(reg_descr,100,"%s-%s Interrupt Pin",devif_getName(),busName); | |
181 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_BCNF_IPIN); //0x0, RO | |
182 | ||
183 | snprintf(reg_descr,100,"%s-%s Bridge control",devif_getName(),busName); | |
184 | confSpace->addConfReg(new pciBridgeControlReg(0x0,0xf7f,0x0,reg_descr),PCI_BCNF_BCNTRL); //0x0, RW | |
185 | ||
186 | snprintf(reg_descr,100,"%s-%s Bridge configuration",devif_getName(),busName); | |
187 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x2880,0x4683),PCI_BCNF_BCNF); //0x2880, RW | |
188 | ||
189 | snprintf(reg_descr,100,"%s-%s Multi-Transaction Timer",devif_getName(),busName); | |
190 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xf8),PCI_BCNF_MTT); //0x0, RW | |
191 | ||
192 | snprintf(reg_descr,100,"%s-%s PCI Clock Control",devif_getName(),busName); | |
193 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0xdf,0x7f),PCI_BCNF_PCLKC); //0xdf, RW | |
194 | ||
195 | snprintf(reg_descr,100,"%s PCI Express Capability Identifier",getName()); | |
196 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x10,0x00),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_CAP_ID_OFFSET);//ro | |
197 | ||
198 | snprintf(reg_descr,100,"%s Next Item Pointer",getName()); | |
199 | confSpace->addConfReg(new pciConfReg(reg_descr,1,BRIDGE_MSI_CAP_ADDR,0x0),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_NXT_CAP_PTR_OFFSET);//, ro | |
200 | ||
201 | snprintf(reg_descr,100,"%s PCI Express Capability",getName()); | |
202 | confSpace->addConfReg(new pciExpCapReg(0x71,0x0,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_CAP_REG_OFFSET);//0x1 | |
203 | ||
204 | snprintf(reg_descr,100,"%s PCI Express Device Capabilities Register",getName()); | |
205 | confSpace->addConfReg(new pciExpDevCapReg(0x1,0x0,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_DEV_CAP_OFFSET);// | |
206 | ||
207 | snprintf(reg_descr,100,"%s PCI Express Device Control Register",getName()); | |
208 | confSpace->addConfReg(new pciExpDevCntrlReg(0x2000,0xf0ef,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_DEV_CTRL_OFFSET);// | |
209 | ||
210 | snprintf(reg_descr,100,"%s PCI Express Device Status Register",getName()); | |
211 | confSpace->addConfReg(new pciExpDevStatReg(0x0,0xf,0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_DEV_STAT_OFFSET);// | |
212 | ||
213 | snprintf(reg_descr,100,"%s PCI Express Link Capabilities Register",getName()); | |
214 | confSpace->addConfReg(new pciExpLnkCapReg(0x3e481,0x0,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_CAP_OFFSET);// | |
215 | ||
216 | snprintf(reg_descr,100,"%s PCI Express Link Control Register",getName()); | |
217 | confSpace->addConfReg(new pciExpLnkCntrlReg(0x0,0xc3,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_CONT_OFFSET);// | |
218 | ||
219 | snprintf(reg_descr,100,"%s PCI Express Link Status Register",getName()); | |
220 | confSpace->addConfReg(new pciExpLnkStatReg(0x1081,0x0,0x0,reg_descr),BRIDGE_CAP_STRUCT_ADDR + PCI_EXP_LINK_STAT_OFFSET);// | |
221 | ||
222 | addMsiCap(BRIDGE_POWER_CAP_ADDR, BRIDGE_MSI_CAP_ADDR, 0x80); | |
223 | addAERCap(BRIDGE_AER_CAP_OFFSET,BRIDGE_POWER_BUDGET_CAP_OFFSET); | |
224 | ||
225 | // pcix power management registers | |
226 | snprintf(reg_descr,100,"%s PM_CAPID",getName()); | |
227 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x1,0x0),0x6c); | |
228 | snprintf(reg_descr,100,"%s PM_NXTP",getName()); | |
229 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0xd8,0x0),0x6d); | |
230 | snprintf(reg_descr,100,"%s PM_PMC",getName()); | |
231 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0xc802,0x0),0x6e); | |
232 | snprintf(reg_descr,100,"%s PM_PMCSR",getName()); | |
233 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x3),0x70); | |
234 | snprintf(reg_descr,100,"%s PM_BSE",getName()); | |
235 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0x72); | |
236 | snprintf(reg_descr,100,"%s PM_DATA",getName()); | |
237 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0x73); | |
238 | ||
239 | // pcix capability id | |
240 | snprintf(reg_descr,100,"%s PM_CAPID",getName()); | |
241 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x7,0x0),0xd8); | |
242 | snprintf(reg_descr,100,"%s PM_NXTP",getName()); | |
243 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),0xd9); | |
244 | ||
245 | ||
246 | // pcix registers | |
247 | snprintf(reg_descr,100,"%s PX_SSTS",getName()); | |
248 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x3,0x0),0xda); | |
249 | snprintf(reg_descr,100,"%s PX_BSTS",getName()); | |
250 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0xdc); | |
251 | snprintf(reg_descr,100,"%s PX_USTC",getName()); | |
252 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0xffffffff,0xffff0000),0xe0); | |
253 | snprintf(reg_descr,100,"%s PX_DSTC",getName()); | |
254 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0xffffffff,0xffff0000),0xe4); | |
255 | snprintf(reg_descr,100,"%s BINIT",getName()); | |
256 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x3,0x1f),0xfc); | |
257 | ||
258 | ||
259 | // pcix error registers | |
260 | snprintf(reg_descr,100,"%s PCIXERRUNC_PTR",getName()); | |
261 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),0x138); | |
262 | snprintf(reg_descr,100,"%s PCIEXERRUNC_SEV",getName()); | |
263 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0xffff),0x134); | |
264 | snprintf(reg_descr,100,"%s PCIEXRRUNC_MSK",getName()); | |
265 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x20,0xffff),0x130); | |
266 | snprintf(reg_descr,100,"%s PCIXERRUNC_STS",getName()); | |
267 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0xffff),0x12c); | |
268 | ||
269 | snprintf(reg_descr,100,"%s PCIXHDR_LOG0",getName()); | |
270 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x13c); | |
271 | snprintf(reg_descr,100,"%s PCIXHDR_LOG1",getName()); | |
272 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x140); | |
273 | snprintf(reg_descr,100,"%s PCIXHDR_LOG2",getName()); | |
274 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x144); | |
275 | snprintf(reg_descr,100,"%s PCIXHDR_LOG3",getName()); | |
276 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x148); | |
277 | ||
278 | snprintf(reg_descr,100,"%s ARB_CNTRL",getName()); | |
279 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0xff,0xffff),0x16a); | |
280 | snprintf(reg_descr,100,"%s SSR",getName()); | |
281 | confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0,0x0),0x170); | |
282 | snprintf(reg_descr,100,"%s PREFCTRL-Lower",getName()); | |
283 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x5060,0x3f0770),0x178); | |
284 | snprintf(reg_descr,100,"%s PREFCTRL-Upper",getName()); | |
285 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x4000,0xc00),0x17c); | |
286 | ||
287 | // power budgeting registers. | |
288 | snprintf(reg_descr,100,"%s power budgeting enhanced cap hdr",getName()); | |
289 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x10004,0x0),0x300); | |
290 | snprintf(reg_descr,100,"%s power budgeting data select",getName()); | |
291 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),0x304); | |
292 | snprintf(reg_descr,100,"%s power budgeting data register",getName()); | |
293 | confSpace->addConfReg(new pciConfReg(reg_descr,4,0x0,0x0),0x308); | |
294 | } | |
295 | ||
296 | void | |
297 | pcieToPciBridge::init_done(){ | |
298 | initPci(); | |
299 | dev_init_done(debug_level); | |
300 | mem32_base = GET_MEM_BASE(confSpace); | |
301 | mem32_limit = GET_MEM_LIMIT(confSpace); | |
302 | io_base = GET_IO_BASE(confSpace); | |
303 | io_limit = GET_IO_LIMIT(confSpace); | |
304 | mem64_base = GET_PF_MEM_BASE(confSpace); | |
305 | mem64_limit = GET_PF_MEM_LIMIT(confSpace); | |
306 | bCR = (bridgeCommandReg*)confSpace->getConfReg(PCI_CONF_COMM); | |
307 | } | |
308 | ||
309 | void | |
310 | pcieToPciBridge::module_added(mmi_instance_t target, const char *target_name){ | |
311 | if (secBusName && !strcmp(target_name,secBusName)){ | |
312 | secBusIf = (pciBusIf*)mmi_get_interface(target, PCI_BUS_INTERFACE); | |
313 | } | |
314 | if(busName && !strcmp(target_name, busName)){ | |
315 | busIf = (pcieBusIf*)mmi_get_interface(target, PCIE_BUS_INTERFACE); | |
316 | } | |
317 | dev_module_added(target_name); | |
318 | } | |
319 | ||
320 | void | |
321 | pcieToPciBridge::module_deleted(mmi_instance_t target, const char *target_name){ | |
322 | dev_module_deleted(target_name); | |
323 | } | |
324 | ||
325 | void | |
326 | pcieToPciBridge::modinfo(){ | |
327 | printf("%s is a Intel pcie-pci bridge device\n",getName()); | |
328 | printf("device id <0x%lx>, vendor id <0x%lx>\n",confSpace->readConf(PCI_CONF_VENID),\ | |
329 | confSpace->readConf(PCI_CONF_DEVID)); | |
330 | printf("it's primary pcie bus is <%s>, secondary pci bus is <%s>\n",busName,secBusName); | |
331 | printf("to display pcie config regs, type \'%s dump\'\n",getName()); | |
332 | } | |
333 | ||
334 | bool | |
335 | pcieToPciBridge::parse_arg(const char *arg){ | |
336 | if(argval("secbus",arg,&secBusName)){ | |
337 | debug_more("%s:secondary bus = %s\n",getName(),secBusName); | |
338 | return true; | |
339 | }else | |
340 | return dev_parse_arg(arg); | |
341 | } | |
342 | ||
343 | bool | |
344 | pcieToPciBridge::check_args(){ | |
345 | if(!secBusName){ | |
346 | debug_err("%s: ERROR: must specify a secondary PCI bus\n", getName()); | |
347 | return false; | |
348 | }else | |
349 | return dev_check_args(); | |
350 | } | |
351 | ||
352 | void* | |
353 | pcieToPciBridge::get_interface(const char *name){ | |
354 | if (!strcmp(name, GENERIC_PCIE_DEV_INTERFACE)) | |
355 | return (genericPcieDevIf*)this; | |
356 | else if(!strcmp(name, PCI_BRIDGE_INTERFACE)) | |
357 | return (pciBridgeIf*)this; | |
358 | else return 0; | |
359 | } | |
360 | ||
361 | ||
362 | pciExpMsgCode | |
363 | pcieToPciBridge::map_pin_vpin(int device, int line, bool ast) { | |
364 | int vpin = (device % 4 + line) % 4; | |
365 | ||
366 | if (ast) | |
367 | switch (vpin) { | |
368 | case 0: return MSG_Assert_INTA; | |
369 | case 1: return MSG_Assert_INTB; | |
370 | case 2: return MSG_Assert_INTC; | |
371 | case 3: return MSG_Assert_INTD; | |
372 | default: assert(0); | |
373 | } | |
374 | else | |
375 | switch (vpin) { | |
376 | case 0: return MSG_Deassert_INTA; | |
377 | case 1: return MSG_Deassert_INTB; | |
378 | case 2: return MSG_Deassert_INTC; | |
379 | case 3: return MSG_Deassert_INTD; | |
380 | default: assert(0); | |
381 | } | |
382 | } | |
383 | ||
384 | int | |
385 | pcieToPciBridge::busif_interrupt_in(bool set, mmi_instance_t busMod, int device, int line, SAM_DeviceId *id) { | |
386 | ||
387 | pciExpMsgCode vpin = map_pin_vpin(device, line, set); | |
388 | ||
389 | int ret; | |
390 | ||
391 | if(set) | |
392 | ret = handleCompletion(assertIntx(vpin,device,id)); | |
393 | else | |
394 | ret = handleCompletion(deassertIntx(vpin, device,id)); | |
395 | ||
396 | if (!ret) | |
397 | return 0; | |
398 | else { | |
399 | debug_err("ERROR: PCI/X device %d, pin %d INT assertion failed!\n", device, line); | |
400 | return -1; | |
401 | } | |
402 | } | |
403 | ||
404 | int | |
405 | pcieToPciBridge::busif_free_interrupt(mmi_instance_t busMod, int dev_number) { | |
406 | debug_more("%s: free interrupt\n",getName()); | |
407 | return 0; | |
408 | } | |
409 | ||
410 | int | |
411 | pcieToPciBridge::busif_dma_out(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId,SAM_DeviceId *id) { | |
412 | int length = (count - 1)/4 + 1; | |
413 | uint8_t be; | |
414 | // assume contiguous byte access. | |
415 | ||
416 | if(count <= 4){ | |
417 | be = pcie_countToBe(count); | |
418 | }else if(count <= 8){ | |
419 | be = pcie_countToBe(count); | |
420 | }else{ | |
421 | if((count % 4) == 0 ) be = 0xff; | |
422 | else{ | |
423 | be = pcie_countToBe(count % 4) << 4; | |
424 | be |= 0xf; | |
425 | } | |
426 | } | |
427 | ||
428 | debug_more("%s: busif_dma_out:byte count 0x%llx,pcie tlp length 0x%lx,pcie tlp be 0x%x\n",getName(),count,length,be); | |
429 | busIf->busif_access(PCIE_MEM, true, vaddr, data, length, be, PCIE_REQUESTER_ID(busIf->busif_getBusno(),0,0), mem_addr32,id); | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
434 | int | |
435 | pcieToPciBridge::busif_dma_in(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId, SAM_DeviceId *id) { | |
436 | int length = (count - 1)/4 + 1; | |
437 | uint8_t be; | |
438 | // assume contiguous byte access. | |
439 | ||
440 | if(count <= 4){ | |
441 | be = pcie_countToBe(count); | |
442 | }else if(count <= 8){ | |
443 | be = pcie_countToBe(count); | |
444 | }else{ | |
445 | if((count % 4) == 0 ) be = 0xff; | |
446 | else{ | |
447 | be = pcie_countToBe(count % 4) << 4; | |
448 | be |= 0xf; | |
449 | } | |
450 | } | |
451 | debug_more("%s: busif_dma_in:bytecount 0x%llx,pcie tlp length 0x%lx,pcie tlp be 0x%x\n",getName(),count,length,be); | |
452 | busIf->busif_access(PCIE_MEM, false, vaddr, data, length, be, PCIE_REQUESTER_ID(busIf->busif_getBusno(),0,0) , mem_addr32,id); | |
453 | ||
454 | return 0; | |
455 | } | |
456 | ||
457 | int | |
458 | pcieToPciBridge::busif_add_interrupt(mmi_instance_t busMod,int device,int dev_type, int slot_irl[],bool isMulti = false) { | |
459 | debug_more("%s:ADD INT\n",getName()); | |
460 | return 0; | |
461 | } | |
462 | ||
463 | /* PCI Express Enhanced Configuration address to conventional PCI | |
464 | Configuration address translation (type 1 to type 0) */ | |
465 | uint32_t | |
466 | pcieToPciBridge::pcie_eh1_pci0_translation(uint32_t addr) { | |
467 | uint16_t dev_fun, reg; uint32_t bus, ret; | |
468 | ||
469 | bus = addr >> busShift & 0xff; | |
470 | dev_fun = addr >> funShift & 0xff; | |
471 | reg = addr & 0xff; | |
472 | ret = bus << 16 | dev_fun << 8 | reg; | |
473 | ||
474 | return ret; | |
475 | } | |
476 | ||
477 | void | |
478 | pcieToPciBridge::devif_confAccessCb(bool wr, uint64_t offset, uint8_t be){ | |
479 | if (!wr) | |
480 | return; | |
481 | ||
482 | switch (offset) { | |
483 | case PCI_BCNF_PF_BASE_HIGH: | |
484 | case PCI_BCNF_PF_BASE_LOW: | |
485 | case PCI_BCNF_PF_LIMIT_HIGH: | |
486 | case PCI_BCNF_PF_LIMIT_LOW: | |
487 | if (!mem_mapped()){ | |
488 | mem64_base = GET_PF_MEM_BASE(confSpace); | |
489 | mem64_limit = GET_PF_MEM_LIMIT(confSpace); | |
490 | return; | |
491 | }else{ | |
492 | if(mem64_base < mem64_limit){ | |
493 | debug_more("%s unmap MEM64[%llx %llx]\n",getName(), mem64_base, mem64_limit); | |
494 | unmapSpace(PCIE_MEM, mem64_base); | |
495 | } | |
496 | mem64_base = GET_PF_MEM_BASE(confSpace); | |
497 | mem64_limit = GET_PF_MEM_LIMIT(confSpace); | |
498 | if (mem64_base < mem64_limit) { | |
499 | debug_more("%s remap: MEM64 [%llx %llx]\n", | |
500 | getName(), mem64_base, mem64_limit); | |
501 | mapSpace(PCIE_MEM, mem64_base, mem64_limit - mem64_base + 1); | |
502 | } | |
503 | } | |
504 | break; | |
505 | case PCI_BCNF_MEM_BASE: | |
506 | case PCI_BCNF_MEM_LIMIT: | |
507 | if (!mem_mapped()){ | |
508 | mem32_base = GET_MEM_BASE(confSpace); | |
509 | mem32_limit = GET_MEM_LIMIT(confSpace); | |
510 | return; | |
511 | }else{ | |
512 | if(mem32_base < mem32_limit){ | |
513 | debug_more("%s unmap MEM[%lx %lx]\n",getName(), mem32_base, mem32_limit); | |
514 | unmapSpace(PCIE_MEM, mem32_base); | |
515 | } | |
516 | mem32_base = GET_MEM_BASE(confSpace); | |
517 | mem32_limit = GET_MEM_LIMIT(confSpace); | |
518 | if (mem32_base < mem32_limit) { | |
519 | debug_more("%s remap: MEM [%lx %lx]\n", | |
520 | getName(), mem32_base, mem32_limit); | |
521 | mapSpace(PCIE_MEM, mem32_base, mem32_limit - mem32_base + 1); | |
522 | } | |
523 | } | |
524 | break; | |
525 | case PCI_BCNF_IO_BASE_LOW: | |
526 | case PCI_BCNF_IO_LIMIT_LOW: | |
527 | if (!io_mapped()){ | |
528 | io_base = GET_IO_BASE(confSpace); | |
529 | io_limit = GET_IO_LIMIT(confSpace); | |
530 | return; | |
531 | }else{ | |
532 | if(io_base < io_limit){ | |
533 | debug_more("%s unmap IO[%lx %lx]\n", getName(), io_base, io_limit); | |
534 | unmapSpace(PCIE_IO, io_base); | |
535 | } | |
536 | io_base = GET_IO_BASE(confSpace); | |
537 | io_limit = GET_IO_LIMIT(confSpace); | |
538 | if (io_base < io_limit) { | |
539 | debug_more("Bridge remap: IO [%lx %lx]\n", io_base, io_limit); | |
540 | mapSpace(PCIE_IO, io_base, io_limit - io_base + 1); | |
541 | } | |
542 | } | |
543 | break; | |
544 | default: | |
545 | return; | |
546 | } | |
547 | return; | |
548 | } | |
549 | ||
550 | pcieCompleter | |
551 | pcieToPciBridge::devif_confAccess(bool wr, uint32_t addr, void * data, uint8_t be, uint16_t reqId, | |
552 | addrMd_xactnType tType, uint16_t length, tlp_X args, SAM_DeviceId *id) { | |
553 | ||
554 | int size = byteEnabletoSize(be); // length is the number of words | |
555 | ||
556 | if (tType == conf_type1) { | |
557 | pciXactnStatus status; | |
558 | addr = pcie_eh1_pci0_translation(addr); | |
559 | ||
560 | if(wr){ | |
561 | *(uint64_t*)data &= 0xffffffff; | |
562 | uint32_t l_buf = *(uint64_t*)data; | |
563 | if(size == 4){ | |
564 | *(uint64_t*)data = swap_word(l_buf); | |
565 | }else if(size == 2){ | |
566 | *(uint64_t*)data = swap_hword(l_buf); | |
567 | }else if (size == 1) | |
568 | *(uint64_t*)data = l_buf; | |
569 | debug_more("%s conf wr xactn type 1: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n", | |
570 | getName(), addr, size, be,*(uint64_t*)data); | |
571 | } | |
572 | ||
573 | status = secBusIf->busif_access_w_size(PCI_CFG, addr, addr, wr, (uint64_t *)data, size,id); | |
574 | ||
575 | if(!wr){ | |
576 | uint32_t l_buf = *(uint64_t*)data; | |
577 | if(size == 4){ | |
578 | *(uint64_t*)data = swap_word(l_buf & 0xFFFFFFFF); | |
579 | }else if(size == 2){ | |
580 | *(uint64_t*)data = swap_hword(l_buf & 0xFFFF); | |
581 | }else if (size == 1) | |
582 | *(uint64_t*)data = l_buf & 0xFF; | |
583 | debug_more("%s conf rd xactn type 1: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n", | |
584 | getName(), addr, size, be, *(uint64_t*)data); | |
585 | if(debug_level >= 2) printf("\n"); | |
586 | } | |
587 | ||
588 | if ( status == SUCCESS ) | |
589 | return pcieCompleter(SC,getId()); | |
590 | else if( status == MASTER_ABORT) | |
591 | return pcieCompleter(CA,getId()); | |
592 | else | |
593 | return pcieCompleter(UR,getId()); | |
594 | } else { | |
595 | bool ret; | |
596 | if(id) | |
597 | *id = samId; | |
598 | if(wr){ | |
599 | *(uint64_t*)data &= 0xffffffff; | |
600 | uint32_t l_buf = *(uint64_t*)data; | |
601 | if(size == 4){ | |
602 | *(uint64_t*)data = swap_word(l_buf); | |
603 | }else if(size == 2){ | |
604 | *(uint64_t*)data = swap_hword(l_buf); | |
605 | }else if (size == 1) | |
606 | *(uint64_t*)data = l_buf; | |
607 | debug_more("%s conf xactn type 0: addr <0x%x> wr size<%d> be<0x%x> data<0x%llx>\n", | |
608 | getName(), addr, size, be,*(uint64_t*)data); | |
609 | } | |
610 | ||
611 | ret = confSpace->confAccessSize(addr, wr, (uint64_t *)data, size); | |
612 | if(wr && debug_level >= 2) printf("\n"); | |
613 | if(!wr){ | |
614 | uint32_t l_buf = *(uint64_t*)data; | |
615 | if(size == 4){ | |
616 | *(uint64_t*)data = swap_word(l_buf & 0xFFFFFFFF); | |
617 | }else if(size == 2){ | |
618 | *(uint64_t*)data = swap_hword(l_buf & 0xFFFF); | |
619 | }else if (size == 1) | |
620 | *(uint64_t*)data = l_buf & 0xFF; | |
621 | ||
622 | debug_more("%s conf xactn type 0: addr <0x%x> rd size<%d> be<0x%x> data<0x%llx>\n", | |
623 | getName(), addr, size, be, *(uint64_t*)data); | |
624 | if(debug_level >= 2) printf("\n"); | |
625 | } | |
626 | ||
627 | devif_confAccessCb(wr,addr,be); | |
628 | return (ret ? pcieCompleter(SC,getId()) : pcieCompleter(CA,getId())); | |
629 | } | |
630 | } | |
631 | ||
632 | pcieCompleter | |
633 | pcieToPciBridge::devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode, void * data,\ | |
634 | uint16_t length, uint8_t be, uint16_t reqId, tlp_X args,SAM_DeviceId * id) { | |
635 | ||
636 | int size = byteEnabletoSize(be); | |
637 | if (addr >= mem32_base && addr < mem32_limit || addr >= mem64_base && addr < mem64_limit) { | |
638 | if(wr) | |
639 | debug_more("%s downstream wr mem access: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n", | |
640 | getName(), addr, size, be, *(uint64_t*)data); | |
641 | secBusIf->busif_access_w_size(mode == mem_addr64 ? PCI_MEM64 : PCI_MEM32, addr, addr, wr, (uint64_t *)data, size,id); | |
642 | if(!wr) | |
643 | debug_more("%s downstream rd mem access: addr <0x%x> size<%d> be<0x%x> data<0x%llx>\n", | |
644 | getName(), addr, size, be, *(uint64_t*)data); | |
645 | return pcieCompleter(SC, getId()); | |
646 | } else{ | |
647 | if(id) *id = samId; | |
648 | return pcieCompleter(UR, getId()); | |
649 | } | |
650 | } | |
651 | ||
652 | pcieCompleter | |
653 | pcieToPciBridge::devif_ioAccess(bool wr, uint64_t addr, void * data, uint8_t be, uint16_t reqId, \ | |
654 | uint16_t length, tlp_X args, SAM_DeviceId *id) { | |
655 | if(id) | |
656 | *id = samId; | |
657 | return pcieCompleter(UR, getId()); | |
658 | } | |
659 | ||
660 | pcieCompleter | |
661 | pcieToPciBridge::devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, void * data, uint16_t length, uint16_t vendorId, uint32_t vendor_data, tlp_X args, SAM_DeviceId *id){ | |
662 | if(id) | |
663 | *id = samId; | |
664 | return pcieCompleter(UR,getId()); | |
665 | } | |
666 | ||
667 | bool pcieToPciBridge::dump (FILE * fp){ | |
668 | const int bufsize = 64 * 1024; | |
669 | char buf[bufsize]; | |
670 | char tbuf[bufsize]; | |
671 | ||
672 | char *dumpDir = DR_get_dir(); | |
673 | assert(dumpDir); | |
674 | bool ret = genericPcieDev::dump (dumpDir, getName()); | |
675 | ||
676 | ||
677 | // intx interrupts | |
678 | // dump the device numbers of downstream devices | |
679 | fprintf(fp,"%s\n",current_dump_version); | |
680 | fprintf(fp,"downstream devices with pending interrupts\n"); | |
681 | for(int i = 0; i < 4; i++){ | |
682 | sprintf(buf,"Int%c ",'A' + i); | |
683 | list<int>::iterator listIt; | |
684 | tbuf[0] = 0; | |
685 | for(listIt = intLine[i].begin(); listIt != intLine[i].end(); listIt++){ | |
686 | sprintf(tbuf,"0x%x ",*listIt); | |
687 | strcat(buf,tbuf); | |
688 | } | |
689 | fwrite(buf,strlen(buf),1,fp); | |
690 | fwrite("\n",strlen("\n"),1,fp); | |
691 | } | |
692 | ||
693 | // now dump the intx pending status | |
694 | fprintf(fp,"Pending interrupts to upstream bridge\n"); | |
695 | for(char i = 0; i < 4; i++) | |
696 | fprintf(fp,"int%c-%s\n", i+'A', pendingIntr[i]? "Asserted":"Deasserted"); | |
697 | fclose(fp); | |
698 | return ret; | |
699 | ||
700 | } | |
701 | ||
702 | bool pcieToPciBridge::restore (FILE * fp){ | |
703 | const int bufsize = 64 * 1024; | |
704 | char buf[bufsize]; | |
705 | ||
706 | char *dumpDir = DR_get_dir(); | |
707 | assert(dumpDir); | |
708 | bool ret = genericPcieDev::restore (dumpDir, getName()); | |
709 | ||
710 | ||
711 | // read the version string. | |
712 | fgets(buf,bufsize,fp); | |
713 | if(!strcmp(current_dump_version,buf)){ | |
714 | printf("%s: dump version unknown\n",getName()); | |
715 | assert(0); | |
716 | } | |
717 | ||
718 | ||
719 | // throw away the comment line | |
720 | fgets(buf,bufsize,fp); | |
721 | ||
722 | for(int i = 0; i < 4; i++){ | |
723 | fgets(buf,bufsize,fp); | |
724 | strtok(buf," "); // intr line number, ignore | |
725 | const char * port_val; | |
726 | while( port_val = strtok(0," ") ){ | |
727 | if(port_val[0] == '\n') | |
728 | break; | |
729 | uint64_t val = strtoull(port_val,0,0); | |
730 | intLine[i].push_back(val); | |
731 | intLine[i].sort(); | |
732 | intLine[i].unique(); | |
733 | pendingIntr[i] = true; | |
734 | } | |
735 | } | |
736 | ||
737 | // ignore the other dump data as it can be derived from data above | |
738 | ||
739 | return ret; | |
740 | ||
741 | ||
742 | } | |
743 | ||
744 | void pcieToPciBridge::handle_ui(int argc, char * argv[]){ | |
745 | if(argc == 1){ | |
746 | ui_cmd_usage(); | |
747 | return; | |
748 | }else if(!strcmp(argv[1],"dump")){ | |
749 | char * dumpDir; | |
750 | char buf[1024]; | |
751 | dumpDir = getcwd(buf,1024); | |
752 | assert( errno != ERANGE); | |
753 | genericPcieDev::dump (dumpDir, argv[2]); | |
754 | }else if(!strcmp(argv[1],"restore")){ | |
755 | if(argv[2]){ | |
756 | char *dumpDir; | |
757 | char buf[1024]; | |
758 | dumpDir = getcwd(buf,1024); | |
759 | assert( errno != ERANGE); | |
760 | genericPcieDev::restore (dumpDir, argv[2]); | |
761 | }else | |
762 | printf("%s restore: no restore filename specified\n",getName()); | |
763 | }else if(!strcmp(argv[1],"debug")){ | |
764 | if(argv[2]){ | |
765 | debug_level = atoi(argv[2]); | |
766 | confSpace->set_debug_level(debug_level); | |
767 | printf("%s: set debug level to %d\n",getName(),debug_level); | |
768 | }else | |
769 | printf("%s: current debug level %d\n",getName(),debug_level); | |
770 | ||
771 | }else | |
772 | debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]); | |
773 | ||
774 | return; | |
775 | } | |
776 | ||
777 | ||
778 | ||
779 |