1 /* $Id: stp222x-main.c,v 1.4 2009/09/07 15:41:07 fredette Exp $ */
2
3 /* ic/stp222x-main.c - main emulation of the UPA to SBus interface
4 controller (STP2220) and the UPA to PCI interface controller
5 (STP2222): */
6
7 /*
8 * Copyright (c) 2009 Matt Fredette
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Matt Fredette.
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <tme/common.h>
39 _TME_RCSID("$Id: stp222x-main.c,v 1.4 2009/09/07 15:41:07 fredette Exp $");
40
41 /* includes: */
42 #include <tme/generic/bus-device.h>
43 #include "stp222x-impl.h"
44
45 /* macros: */
46
47 /* common register offsets: */
48 #define TME_STP222X_REG00_UPA_PORT_ID (0x0000)
49 #define TME_STP222X_REG00_UPA_PORT_CONFIG (0x0008)
50 #define TME_STP222X_REG00_CSR (0x0010)
51 /* 0x0018 unused */
52 #define TME_STP222X_REG00_ECC_CONTROL (0x0020)
53 /* 0x0028 unused */
54 #define TME_STP222X_REG00_UE_AFSR (0x0030)
55 #define TME_STP222X_REG00_UE_AFAR (0x0038)
56 #define TME_STP222X_REG00_CE_AFSR (0x0040)
57 #define TME_STP222X_REG00_CE_AFAR (0x0048)
58 #define TME_STP222X_REG01_PM_CR (0x0100)
59 #define TME_STP222X_REG01_PM_COUNT (0x0108)
60
61 /* the control/status register: */
62 #define TME_STP222X_CSR_IMPL ((((tme_uint64_t) 2) << 63) - (((tme_uint64_t) 1) << 60))
63 #define TME_STP222X_CSR_VER ((((tme_uint64_t) 2) << 59) - (((tme_uint64_t) 1) << 56))
64 #define TME_STP222X_CSR_MID ((((tme_uint64_t) 2) << 55) - (((tme_uint64_t) 1) << 51))
65 #define TME_STP222X_CSR_IGN ((((tme_uint64_t) 2) << 50) - (((tme_uint64_t) 1) << 46))
66 #define TME_STP222X_CSR_APCKEN (1 << 3)
67 #define TME_STP222X_CSR_APERR (1 << 2)
68 #define TME_STP222X_CSR_IAP (1 << 1)
69 #define TME_STP222X_CSR_MODE (1 << 0)
70
71 /* stp2220-specific registers: */
72 #define TME_STP2220_REG20_SBUS_CSR (0x2000)
73 /* 0x2028 unused */
74 #define TME_STP2220_REG20_SBUS_AFSR (0x2010)
75 #define TME_STP2220_REG20_SBUS_AFAR (0x2018)
76 #define TME_STP2220_REG20_SBUS_CONFIG(n) (0x2020 + (TME_STP222X_REG_SIZE * (n)))
77
78 /* the stp2220 slot size: */
79 #define TME_STP2220_SLOT_SIZE (256 * 1024 * 1024)
80
81 /* this gives the raw stp2220 address for a slot and offset: */
82 #define TME_STP2220_SBUS_ADDRESS(slot, offset) (((slot) * TME_STP2220_SLOT_SIZE) + (offset))
83
84 /* reset states: */
85 #define TME_STP222X_RESET_STATE_NEGATED (0)
86 #define TME_STP222X_RESET_STATE_NEGATING (TME_STP222X_RESET_STATE_NEGATED + TME_STP222X_CONN_NULL)
87 #define TME_STP222X_RESET_STATE_ASSERTED (TME_STP222X_RESET_STATE_NEGATING + 1)
88 #define TME_STP222X_RESET_STATE_ASSERTING (TME_STP222X_RESET_STATE_ASSERTED + TME_STP222X_CONN_NULL)
89
90 /* globals: */
91
92 /* the simple 64-bit register bus router: */
93 static const tme_bus_lane_t _tme_stp222x_bus_router_regs[sizeof(tme_uint64_t)] = {
94 TME_BUS_LANE_ROUTE(0),
95 TME_BUS_LANE_ROUTE(1),
96 TME_BUS_LANE_ROUTE(2),
97 TME_BUS_LANE_ROUTE(3),
98 TME_BUS_LANE_ROUTE(4),
99 TME_BUS_LANE_ROUTE(5),
100 TME_BUS_LANE_ROUTE(6),
101 TME_BUS_LANE_ROUTE(7)
102 };
103
104 /* the STP2220 mapping from obio slot and offset to IDI: */
105 static const struct {
106 tme_uint32_t _tme_stp2220_obio_slot;
107 tme_uint32_t _tme_stp2220_obio_offset;
108 tme_uint32_t _tme_stp2220_obio_idi;
109 } _tme_stp2220_obios[] = {
110 { TME_STP2220_SLOT_AUDIO, 0x0000000, TME_STP2220_IDI_AUDIO, },
111 { TME_STP2220_SLOT_MACIO, 0x8800000, TME_STP222X_IDI_SCSI },
112 { TME_STP2220_SLOT_MACIO, 0x8c00000, TME_STP222X_IDI_ETHER },
113 { TME_STP2220_SLOT_MACIO, 0xc800000, TME_STP222X_IDI_BPP },
114 { TME_STP2220_SLOT_SLAVIO, 0x1100000, TME_STP2220_IDI_ZS0_ZS1 },
115 { TME_STP2220_SLOT_SLAVIO, 0x1000000, TME_STP2220_IDI_ZS0_ZS1 },
116 { TME_STP2220_SLOT_SLAVIO, 0x1400000, TME_STP2220_IDI_FD },
117 };
118
119 /* this converts an I/O connection into a connection index: */
120 static tme_uint32_t
_tme_stp222x_io_conn_index(const struct tme_stp222x * stp222x,const struct tme_bus_connection * io_conn_bus)121 _tme_stp222x_io_conn_index(const struct tme_stp222x *stp222x,
122 const struct tme_bus_connection *io_conn_bus)
123 {
124 tme_uint32_t connid;
125 tme_uint32_t conn_index;
126
127 /* this must be an I/O connection: */
128 assert (io_conn_bus
129 != stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus);
130
131 /* get the connection id: */
132 connid = io_conn_bus->tme_bus_connection.tme_connection_id;
133
134 /* if this is a card connection: */
135 if ((connid
136 & TME_STP222X_CONNID_TYPE)
137 == TME_STP222X_CONNID_TYPE_CARD) {
138
139 /* if this is an stp2220: */
140 if (TME_STP222X_IS_2220(stp222x)) {
141
142 /* assume that this is the first master connection for this
143 card, which uses the card's primary master connection
144 index: */
145 conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP2220_CONNID_CARD_WHICH);
146
147 /* if this is an alternate connection for the card: */
148 if (connid & TME_STP2220_CONNID_CARD_ALTERNATE) {
149
150 /* starting from the first alternate master connection index
151 for this card and moving forward, search all remaining
152 connection indices: */
153 conn_index
154 = (TME_STP2220_SLOTS_CARD
155 + (connid & TME_STP2220_CONNID_CARD_WHICH));
156 for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != io_conn_bus; ) {
157 conn_index++;
158 assert (conn_index < stp222x->tme_stp222x_slave_conn_index_next);
159 }
160 }
161 }
162
163 /* otherwise, this is an stp2222: */
164 else {
165 abort();
166 }
167 }
168
169 /* otherwise, this is an obio connection id: */
170 else {
171
172 /* assume that this is an obio short connection id, and get the
173 connection index: */
174 conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP222X_CONNID_OBIO_SHORT_CONN_WHICH);
175
176 /* if this is an obio long connection id: */
177 if ((connid
178 & TME_STP222X_CONNID_OBIO_TYPE)
179 == TME_STP222X_CONNID_OBIO_TYPE_LONG) {
180
181 /* search all connection indices: */
182 conn_index = 0;
183 for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != io_conn_bus; ) {
184 conn_index++;
185 assert (conn_index < stp222x->tme_stp222x_slave_conn_index_next);
186 }
187 }
188 }
189
190 assert (stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus == io_conn_bus);
191 return (conn_index);
192 }
193
194 /* this converts an I/O connection and interrupt signal into an
195 IDI: */
196 static tme_uint32_t
_tme_stp222x_io_idi(const struct tme_stp222x * stp222x,const struct tme_bus_connection * io_conn_bus,unsigned int signal_int)197 _tme_stp222x_io_idi(const struct tme_stp222x *stp222x,
198 const struct tme_bus_connection *io_conn_bus,
199 unsigned int signal_int)
200 {
201 tme_uint32_t connid;
202 tme_uint32_t idi;
203 tme_uint32_t idi_addend;
204
205 /* this must be an I/O connection: */
206 assert (io_conn_bus
207 != stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus);
208
209 /* get the connection id: */
210 connid = io_conn_bus->tme_bus_connection.tme_connection_id;
211
212 /* if this is a card connection: */
213 if ((connid
214 & TME_STP222X_CONNID_TYPE)
215 == TME_STP222X_CONNID_TYPE_CARD) {
216
217 /* if this is an stp2220, bits 1..2 of a card connection id are
218 the card (slot) number, which are bits 3..4 of the connection's
219 base IDI. otherwise, this is an stp2222, and bits 1..3 of a
220 card connection id are the bus and slot number, which are bits
221 2..4 of the connection's base IDI. we take advantage of this
222 to quickly make the base IDI: */
223 #if TME_STP222X_CONNID_TYPE != (0x1 << 0)
224 #error "TME_STP222X_CONNID_TYPE changed"
225 #endif
226 #if TME_STP222X_CONNID_TYPE_CARD != 0
227 #error "TME_STP222X_CONNID_TYPE_CARD changed"
228 #endif
229 #if (TME_STP2222_CONNID_BUS_WHICH + TME_STP2222_CONNID_DEVICE_WHICH) != (0x7 << 1)
230 #error "TME_STP2222_CONNID_BUS_WHICH or TME_STP2222_CONNID_DEVICE_WHICH changed"
231 #endif
232 #if TME_STP2220_CONNID_CARD_WHICH != (0x3 << 1)
233 #error "TME_STP2220_CONN_CARD_WHICH changed"
234 #endif
235 idi = connid << 1;
236 if (TME_STP222X_IS_2220(stp222x)) {
237 idi <<= 1;
238 }
239 idi %= TME_STP222X_IDI0_OBIO;
240
241 /* the interrupt signal can't be unspecified: */
242 assert (signal_int != TME_BUS_SIGNAL_INT_UNSPEC);
243
244 /* convert the interrupt signal into an IDI addend: */
245 idi_addend = TME_BUS_SIGNAL_INDEX_INT(signal_int);
246
247 /* the IDI addend must be within range: */
248 assert (idi_addend
249 < (TME_STP222X_IS_2220(stp222x)
250 ? TME_SBUS_SLOT_INTS
251 : TME_PCI_SLOT_INTS));
252
253 /* add in the IDI addend: */
254 idi += idi_addend;
255 }
256
257 /* otherwise, this is an obio connection: */
258 else {
259
260 /* this must be a obio short connection id: */
261 assert ((connid
262 & TME_STP222X_CONNID_OBIO_TYPE)
263 == TME_STP222X_CONNID_OBIO_TYPE_SHORT);
264
265 /* get the connection's base IDI: */
266 idi = TME_FIELD_MASK_EXTRACTU(connid, TME_STP222X_CONNID_OBIO_SHORT_IDI);
267
268 /* if the interrupt signal is specified: */
269 if (signal_int != TME_BUS_SIGNAL_INT_UNSPEC) {
270
271 /* the audio connection is the only obio connection allowed to
272 specify its interrupt signal - zero is used for record, one
273 for playback: */
274 assert (signal_int == TME_BUS_SIGNAL_INT(0)
275 || signal_int == TME_BUS_SIGNAL_INT(1));
276 if (!TME_STP222X_IS_2220(stp222x)) {
277 assert (idi == TME_STP2220_IDI_AUDIO);
278
279 /* nothing to do */
280 }
281 else {
282 #if TME_STP2222_IDI_AUDIO_PLAYBACK != (TME_STP2222_IDI_AUDIO_RECORD + 1)
283 #error "TME_STP2222_IDI_AUDIO_ values changed"
284 #endif
285 assert (idi == TME_STP2222_IDI_AUDIO_RECORD);
286 idi += TME_BUS_SIGNAL_INDEX_INT(signal_int);
287 }
288 }
289 }
290
291 return (idi);
292 }
293
294 /* this converts an address into an address space: */
295 static tme_uint32_t
_tme_stp222x_lookup_address(const struct tme_stp222x * stp222x,tme_bus_addr64_t address,tme_bus_addr32_t * _region_size_m1)296 _tme_stp222x_lookup_address(const struct tme_stp222x *stp222x,
297 tme_bus_addr64_t address,
298 tme_bus_addr32_t *_region_size_m1)
299 {
300 tme_bus_addr32_t region_size_m1;
301 unsigned int aspace_i;
302 tme_uint32_t address_16_47;
303
304 /* if this is an stp2220: */
305 if (TME_STP222X_IS_2220(stp222x)) {
306
307 /* only the upper half of our UPA address space is mapped to the
308 SBus address space: */
309 region_size_m1 = 0xffffffff;
310 aspace_i
311 = (address <= region_size_m1
312 ? TME_STP222X_ASPACE_NULL
313 : TME_STP2220_ASPACE_SBUS);
314 }
315
316 /* otherwise, this is an stp2222: */
317 else {
318
319 /* get bits 16..47 of the UPA address: */
320 address_16_47 = (address >> 16);
321 assert (address_16_47 == (address >> 16));
322
323 /* if this is a PCI bus memory space: */
324 if (address_16_47 >= 0x10000) {
325 assert (address_16_47 <= 0x1ffff);
326 region_size_m1 = 0x7fffffff;
327 aspace_i
328 = TME_STP2222_ASPACE_PCI_MEMORY(((address_16_47 & 0x8000) == 0)
329 == !TME_STP2222_BOOT_BUS(stp222x));
330 }
331
332 /* otherwise, if this is a PCI bus I/O space: */
333 else if ((address_16_47 | 1) == 0x00201) {
334 region_size_m1 = 0xffff;
335 aspace_i = TME_STP2222_ASPACE_PCI_IO(address_16_47 & 1);
336 }
337
338 /* otherwise, if this is PCI configuration space: */
339 else if (address_16_47 == 0x00100) {
340 region_size_m1 = 0xffffff;
341 aspace_i = TME_STP2222_ASPACE_PCI_CONFIGURATION;
342 }
343
344 /* otherwise, this address is in the register space: */
345 else {
346 region_size_m1 = 0xffff;
347 aspace_i = TME_STP222X_ASPACE_NULL;
348 }
349 }
350
351 /* return the region size and address space: */
352 *_region_size_m1 = region_size_m1;
353 return (aspace_i);
354 }
355
356 /* the 0x00 register group register handler: */
357 static void
_tme_stp222x_reg00_regs(struct tme_stp222x * stp222x,struct tme_stp222x_reg * reg)358 _tme_stp222x_reg00_regs(struct tme_stp222x *stp222x,
359 struct tme_stp222x_reg *reg)
360 {
361
362 /* if this is a write: */
363 if (reg->tme_stp222x_reg_write) {
364
365 /* dispatch on the register: */
366 switch (TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address)) {
367 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_CONFIG):
368 stp222x->tme_stp222x_upa_port_config
369 = (reg->tme_stp222x_reg_value
370 & TME_UPA_PORT_CONFIG_SCIQ0);
371 break;
372 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CSR):
373 stp222x->tme_stp222x_csr
374 = ((stp222x->tme_stp222x_csr | ~TME_STP222X_CSR_APCKEN)
375 & (reg->tme_stp222x_reg_value ^ TME_STP222X_CSR_APCKEN));
376 tme_stp222x_mdu_ign_update(stp222x,
377 TME_FIELD_MASK_EXTRACTU(stp222x->tme_stp222x_csr,
378 TME_STP222X_CSR_IGN));
379 break;
380 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_ECC_CONTROL):
381 stp222x->tme_stp222x_ecc_control = (reg->tme_stp222x_reg_value >> 61);
382 break;
383 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_ID):
384 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFSR):
385 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFAR):
386 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFSR):
387 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFAR):
388 break;
389 default:
390 return;
391 }
392 }
393
394 /* otherwise, this is a read: */
395 else {
396
397 /* dispatch on the register: */
398 switch (TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address)) {
399 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_ID):
400 reg->tme_stp222x_reg_value
401 = (TME_UPA_PORT_ID_COOKIE
402 + !TME_UPA_PORT_ID_ECC_NOT_VALID
403 + !TME_UPA_PORT_ID_ONEREAD
404 + !TME_UPA_PORT_ID_PINT_RDQ
405 + (8 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_PREQ_DQ))
406 + (2 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_PREQ_RQ))
407 + ((TME_UPA_UPACAP_MASTER
408 + !TME_UPA_UPACAP_CACHEMASTER
409 + !TME_UPA_UPACAP_SLAVE_INT_L
410 + TME_UPA_UPACAP_INTERRUPTMASTER
411 + !TME_UPA_UPACAP_HANDLERSLAVE)
412 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_UPACAP))
413 + ((TME_STP222X_IS_2220(stp222x)
414 ? 0xef07
415 : 0x1954)
416 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_ID)));
417 break;
418 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_CONFIG):
419 reg->tme_stp222x_reg_value = stp222x->tme_stp222x_upa_port_config;
420 break;
421 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CSR):
422 reg->tme_stp222x_reg_value
423 = ((stp222x->tme_stp222x_csr
424 & (TME_STP222X_CSR_MID
425 | TME_STP222X_CSR_IGN
426 | TME_STP222X_CSR_APCKEN
427 | TME_STP222X_CSR_APERR
428 | TME_STP222X_CSR_IAP
429 | TME_STP222X_CSR_MODE))
430 + (TME_STP222X_IS_2220(stp222x)
431 ? ((0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_IMPL))
432 + (0x1 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_VER)))
433 : ((0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_IMPL))
434 + (0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_VER)))));
435 break;
436 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_ECC_CONTROL):
437 reg->tme_stp222x_reg_value
438 = (((tme_uint64_t) stp222x->tme_stp222x_ecc_control)
439 << 61);
440 break;
441 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFSR):
442 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFAR):
443 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFSR):
444 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFAR):
445 reg->tme_stp222x_reg_value = 0;
446 break;
447 default:
448 return;
449 }
450 }
451
452 /* this register access has been completed: */
453 reg->tme_stp222x_reg_completed = TRUE;
454 }
455
456 /* the stp2220 SBus register handler: */
457 static void
_tme_stp2220_sbus_regs(struct tme_stp222x * stp222x,struct tme_stp222x_reg * reg)458 _tme_stp2220_sbus_regs(struct tme_stp222x *stp222x,
459 struct tme_stp222x_reg *reg)
460 {
461 tme_uint64_t mask_w;
462 tme_uint64_t mask_ro;
463 tme_uint64_t zero;
464 tme_uint64_t *_value;
465
466 /* assume that all bits of the register are writable: */
467 mask_w = 0 - (tme_uint64_t) 1;
468
469 /* assume that all read-only bits of the register are zero: */
470 mask_ro = 0;
471
472 /* make a dummy zero register: */
473 zero = 0;
474
475 /* if this is the SBus control/status register: */
476 if (reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_CSR) {
477 _value = &stp222x->tme_stp2220_sbus_csr;
478 mask_w
479 = (TME_BIT(10) /* shortens PIO access latency */
480 + TME_BIT(8) /* enables interrupts for SBus errors */
481 + TME_BIT(5) /* enables DVMA for slot 15 */
482 + TME_BIT(4) /* enables DVMA for slot 14 */
483 + 0xf); /* enables DVMA for slots 0..3 */
484 }
485
486 /* otherwise, if this is the SBus AFSR or AFAR: */
487 else if (reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_AFSR
488 || reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_AFAR) {
489 _value = &zero;
490 }
491
492 /* otherwise, if this is an SBus slot configuration register: */
493 else if ((reg->tme_stp222x_reg_address
494 >= TME_STP2220_REG20_SBUS_CONFIG(0))
495 && (reg->tme_stp222x_reg_address
496 <= TME_STP2220_REG20_SBUS_CONFIG(TME_STP2220_SLOTS_CARD + TME_STP2220_SLOTS_OBIO - 1))) {
497 _value
498 = (&stp222x->tme_stp2220_sbus_config_card
499 [(reg->tme_stp222x_reg_address
500 - TME_STP2220_REG20_SBUS_CONFIG(0))
501 / TME_STP222X_REG_SIZE]);
502 mask_w
503 = (TME_BIT(14) /* enables extended transfers */
504 + TME_BIT(4) /* enables 64-byte bursts */
505 + TME_BIT(3) /* enables 32-byte bursts */
506 + TME_BIT(2) /* enables 16-byte bursts */
507 + TME_BIT(1) /* enables 8-byte bursts */
508 );
509 }
510
511 /* otherwise, this is an unknown register: */
512 else {
513 return;
514 }
515
516 /* if this is a write: */
517 if (reg->tme_stp222x_reg_write) {
518 *_value = reg->tme_stp222x_reg_value & mask_w;
519 }
520
521 /* otherwise, this is a read: */
522 else {
523 reg->tme_stp222x_reg_value = *_value | mask_ro;
524 }
525
526 /* this register access has been completed: */
527 reg->tme_stp222x_reg_completed = TRUE;
528 }
529
530 /* this completes a bus operation between master and slave: */
531 #define _tme_stp222x_complete_master tme_stp22xx_complete_master
532
533 /* this completes a reset assertion or negation: */
534 static void
_tme_stp222x_complete_reset(struct tme_stp22xx * stp22xx,struct tme_completion * completion,void * arg)535 _tme_stp222x_complete_reset(struct tme_stp22xx *stp22xx,
536 struct tme_completion *completion,
537 void *arg)
538 {
539 struct tme_stp222x *stp222x;
540 tme_uint32_t reset_state;
541
542 /* recover our data structure: */
543 stp222x = (struct tme_stp222x *) stp22xx;
544
545 /* get the next reset state: */
546 reset_state = stp222x->tme_stp222x_reset_state - 1;
547
548 /* if we have finished asserting RESET on the I/O bus, and
549 the UPA bus reset signal is negated: */
550 if (reset_state == TME_STP222X_RESET_STATE_ASSERTED
551 && stp222x->tme_stp222x_reset_level == TME_BUS_SIGNAL_LEVEL_NEGATED) {
552
553 /* start negating RESET on the I/O bus: */
554 reset_state = TME_STP222X_RESET_STATE_NEGATING;
555 }
556
557 /* update the reset state: */
558 stp222x->tme_stp222x_reset_state = reset_state;
559
560 /* unused: */
561 completion = 0;
562 arg = 0;
563 }
564
565 /* this completes a bus request assertion or negation: */
566 static void
_tme_stp222x_complete_br(struct tme_stp22xx * stp22xx,struct tme_completion * completion,void * arg)567 _tme_stp222x_complete_br(struct tme_stp22xx *stp22xx,
568 struct tme_completion *completion,
569 void *arg)
570 {
571 struct tme_stp222x *stp222x;
572
573 /* recover our data structure: */
574 stp222x = (struct tme_stp222x *) stp22xx;
575
576 /* our bus request has been flipped: */
577 stp222x->tme_stp222x_br = !stp222x->tme_stp222x_br;
578
579 /* unused: */
580 completion = 0;
581 arg = 0;
582 }
583
584 /* this completes a bus grant: */
585 #define _tme_stp222x_complete_bg tme_stp22xx_complete_bg
586
587 /* this calls out a bus signal to a connection: */
588 #define _tme_stp222x_callout_signal(stp222x, conn_index, signal, completion_handler) \
589 tme_stp22xx_callout_signal(&(stp222x)->tme_stp222x, conn_index, signal, completion_handler)
590
591 /* the run function: */
592 static void
_tme_stp222x_run(struct tme_stp22xx * stp22xx)593 _tme_stp222x_run(struct tme_stp22xx *stp22xx)
594 {
595 struct tme_stp222x *stp222x;
596 unsigned int reset_state;
597 unsigned int io_conn_index;
598 unsigned int master_conn_index;
599 tme_uint32_t io_brs;
600
601 /* recover our data structure: */
602 stp222x = (struct tme_stp222x *) stp22xx;
603
604 /* loop forever: */
605 for (;;) {
606
607 /* if we need to assert reset to another I/O connection: */
608 reset_state = stp222x->tme_stp222x_reset_state;
609 if (reset_state > TME_STP222X_RESET_STATE_ASSERTED) {
610
611 /* assert reset to the next I/O connection: */
612 io_conn_index = reset_state - (TME_STP222X_RESET_STATE_ASSERTED + 1);
613 _tme_stp222x_callout_signal(stp222x,
614 io_conn_index,
615 (TME_BUS_SIGNAL_RESET
616 | TME_BUS_SIGNAL_EDGE
617 | TME_BUS_SIGNAL_LEVEL_ASSERTED),
618 _tme_stp222x_complete_reset);
619 continue;
620 }
621
622 /* if there is a current master: */
623 master_conn_index = stp222x->tme_stp222x_master_conn_index;
624 if (master_conn_index != TME_STP222X_CONN_NULL) {
625 assert (master_conn_index < TME_STP222X_CONN_SLAVE0);
626
627 /* if the current master is still requesting the bus: */
628 if (stp222x->tme_stp222x_io_brs & (1 << master_conn_index)) {
629
630 /* stop now. we can't do anything else until the current
631 master releases the bus: */
632 break;
633 }
634
635 /* there should be no master completion pending: */
636 assert (stp222x->tme_stp222x.tme_stp22xx_master_completion == NULL);
637
638 /* there is no current master: */
639 stp222x->tme_stp222x_master_conn_index = TME_STP222X_CONN_NULL;
640
641 /* negate bus grant to the former master: */
642 _tme_stp222x_callout_signal(stp222x,
643 master_conn_index,
644 (TME_BUS_SIGNAL_BG
645 | TME_BUS_SIGNAL_EDGE
646 | TME_BUS_SIGNAL_LEVEL_NEGATED),
647 tme_stp22xx_complete_nop);
648 continue;
649 }
650
651 /* we need the UPA bus if an I/O connection is requesting the bus,
652 or if we have an interrupt to dispatch, or if we have a
653 streaming cache to flush. if our UPA bus request line doesn't
654 reflect whether we need the UPA bus: */
655 if (!stp222x->tme_stp222x_br
656 == (stp222x->tme_stp222x_io_brs != 0
657 #if TME_STP222X_MDU_BUFFER_COUNT != 2
658 #error "TME_STP222X_MDU_BUFFER_COUNT changed"
659 #endif
660 || (stp222x->tme_stp222x_mdu_dispatch_imr[0] != 0 /* !TME_STP222X_MDU_IMR_V */
661 && stp222x->tme_stp222x_mdu_dispatch_state[0] == 0) /* TME_STP222X_MDU_DISPATCH_NOW */
662 || (stp222x->tme_stp222x_mdu_dispatch_imr[1] != 0 /* !TME_STP222X_MDU_IMR_V */
663 && stp222x->tme_stp222x_mdu_dispatch_state[1] == 0) /* TME_STP222X_MDU_DISPATCH_NOW */
664 #if TME_STP222X_STC_COUNT != 2
665 #error "TME_STP222X_STC_COUNT changed"
666 #endif
667 || stp222x->tme_stp222x_stcs[0].tme_stp222x_stc_pgflush
668 || stp222x->tme_stp222x_stcs[1].tme_stp222x_stc_pgflush
669 )) {
670
671 /* assert or negate our bus request on the UPA bus: */
672 _tme_stp222x_callout_signal(stp222x,
673 TME_STP222X_CONN_UPA,
674 (TME_BUS_SIGNAL_BR
675 | TME_BUS_SIGNAL_EDGE
676 | (stp222x->tme_stp222x_br
677 ? TME_BUS_SIGNAL_LEVEL_NEGATED
678 : TME_BUS_SIGNAL_LEVEL_ASSERTED)),
679 _tme_stp222x_complete_br);
680 continue;
681 }
682
683 /* if we need to negate reset to another I/O connection: */
684 reset_state = stp222x->tme_stp222x_reset_state;
685 if (reset_state > TME_STP222X_RESET_STATE_NEGATED
686 && reset_state < TME_STP222X_RESET_STATE_ASSERTED) {
687
688 /* negate reset to the next I/O connection: */
689 io_conn_index = reset_state - (TME_STP222X_RESET_STATE_NEGATED + 1);
690 _tme_stp222x_callout_signal(stp222x,
691 io_conn_index,
692 (TME_BUS_SIGNAL_RESET
693 | TME_BUS_SIGNAL_EDGE
694 | TME_BUS_SIGNAL_LEVEL_NEGATED),
695 _tme_stp222x_complete_reset);
696 continue;
697 }
698
699 /* if we don't own the UPA bus: */
700 if (!stp222x->tme_stp222x_bg) {
701
702 /* stop now. we can't do anything else until we own the UPA
703 bus: */
704 break;
705 }
706
707 /* dispatch any interrupt: */
708 if (tme_stp222x_mdu_dispatch(stp222x)) {
709 continue;
710 }
711
712 /* flush any streaming cache: */
713 if (tme_stp222x_stc_flush(stp222x)) {
714 continue;
715 }
716
717 /* if one or more I/O connections are requesting the bus: */
718 io_brs = stp222x->tme_stp222x_io_brs;
719 if (io_brs != 0) {
720
721 /* get the connection index for the next master: */
722 /* XXX FIXME - should we do something fair here? */
723 for (master_conn_index = 0;
724 (io_brs & 1) == 0;
725 io_brs >>= 1, master_conn_index++);
726
727 /* set the pending master: */
728 stp222x->tme_stp222x_master_conn_index_pending = master_conn_index;
729
730 /* assert bus grant to the current master: */
731 _tme_stp222x_callout_signal(stp222x,
732 master_conn_index,
733 (TME_BUS_SIGNAL_BG
734 | TME_BUS_SIGNAL_EDGE
735 | TME_BUS_SIGNAL_LEVEL_ASSERTED),
736 _tme_stp222x_complete_bg);
737 continue;
738 }
739
740 /* no other callouts are needed: */
741 break;
742 }
743 }
744
745 /* this handles a bus signal: */
746 static void
_tme_stp222x_signal(struct tme_bus_connection * conn_bus,unsigned int signal,struct tme_completion * completion)747 _tme_stp222x_signal(struct tme_bus_connection *conn_bus,
748 unsigned int signal,
749 struct tme_completion *completion)
750 {
751 struct tme_stp222x *stp222x;
752 tme_uint32_t level;
753 tme_uint32_t io_conn_index;
754 tme_uint32_t br_mask;
755 tme_uint32_t idi;
756
757 /* enter: */
758 stp222x = tme_stp222x_enter_bus(conn_bus);
759
760 /* get the level. this must be an edge: */
761 assert (signal & TME_BUS_SIGNAL_EDGE);
762 level = signal - TME_BUS_SIGNAL_EDGE;
763 signal = TME_BUS_SIGNAL_WHICH(signal);
764 level ^= signal;
765
766 /* if this bus signal is on the UPA connection: */
767 if (conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus) {
768
769 /* if this is the bus grant signal: */
770 if (signal == TME_BUS_SIGNAL_BG) {
771
772 /* mark our bus grant as either asserted or negated: */
773 assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED
774 || level == TME_BUS_SIGNAL_LEVEL_ASSERTED);
775 stp222x->tme_stp222x_bg = (level == TME_BUS_SIGNAL_LEVEL_ASSERTED);
776 }
777
778 /* otherwise, this must be reset signal: */
779 else {
780 assert (signal == TME_BUS_SIGNAL_RESET);
781
782 /* update the level of the UPA reset signal: */
783 stp222x->tme_stp222x_reset_level = level;
784
785 /* if the UPA reset signal is asserted: */
786 if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
787
788 /* start asserting RESET on the I/O bus: */
789 stp222x->tme_stp222x_reset_state = TME_STP222X_RESET_STATE_ASSERTING;
790 }
791
792 /* otherwise, the UPA reset signal must be negated: */
793 else {
794 assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED);
795
796 /* if RESET is currently asserted on the I/O bus, start
797 negating it: */
798 assert (stp222x->tme_stp222x_reset_state >= TME_STP222X_RESET_STATE_ASSERTED);
799 if (stp222x->tme_stp222x_reset_state == TME_STP222X_RESET_STATE_ASSERTED) {
800 stp222x->tme_stp222x_reset_state = TME_STP222X_RESET_STATE_NEGATING;
801 }
802 }
803 }
804 }
805
806 /* otherwise, this bus signal is on an I/O connection: */
807 else {
808
809 /* if this is the bus request signal: */
810 if (signal == TME_BUS_SIGNAL_BR) {
811
812 /* get this I/O connection's bus request mask: */
813 io_conn_index = _tme_stp222x_io_conn_index(stp222x, conn_bus);
814 assert (io_conn_index < TME_STP222X_CONN_SLAVE0);
815 br_mask = (1 << io_conn_index);
816
817 /* mark this caller's bus request line as either asserted or
818 negated: */
819 assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED
820 || level == TME_BUS_SIGNAL_LEVEL_ASSERTED);
821 stp222x->tme_stp222x_io_brs
822 = ((stp222x->tme_stp222x_io_brs
823 | br_mask)
824 & (level == TME_BUS_SIGNAL_LEVEL_ASSERTED
825 ? 0
826 : ~br_mask));
827 }
828
829 /* otherwise, this must be an interrupt signal: */
830 else {
831 assert (signal == TME_BUS_SIGNAL_INT_UNSPEC
832 || TME_BUS_SIGNAL_IS_INT(signal));
833
834 /* get the IDI: */
835 idi = _tme_stp222x_io_idi(stp222x, conn_bus, signal);
836
837 /* update the interrupt concentrator: */
838 tme_stp222x_mdu_intcon(stp222x, idi, level);
839 }
840 }
841
842 /* leave: */
843 tme_stp222x_completion_validate(stp222x, completion);
844 tme_stp222x_leave(stp222x);
845 }
846
847 /* this handles a bus cycle: */
848 static void
_tme_stp222x_cycle(struct tme_bus_connection * master_conn_bus,struct tme_bus_cycle * master_cycle,tme_uint32_t * _master_fast_cycle_types,struct tme_completion * master_completion)849 _tme_stp222x_cycle(struct tme_bus_connection *master_conn_bus,
850 struct tme_bus_cycle *master_cycle,
851 tme_uint32_t *_master_fast_cycle_types,
852 struct tme_completion *master_completion)
853 {
854 struct tme_stp222x *stp222x;
855 tme_bus_addr64_t slave_address;
856 tme_uint32_t aspace_i;
857 unsigned int slave_conn_index;
858 tme_bus_addr32_t region_size_m1;
859 struct tme_stp222x_reg reg;
860 tme_uint32_t reggroup;
861
862 /* enter: */
863 stp222x = tme_stp222x_enter_master_bus(master_conn_bus);
864
865 /* convert the master's address into an address space, slave
866 connection index and address: */
867 slave_address = master_cycle->tme_bus_cycle_address;
868 aspace_i
869 = _tme_stp222x_lookup_address(stp222x,
870 slave_address,
871 ®ion_size_m1);
872 slave_address &= region_size_m1;
873 slave_conn_index
874 = (aspace_i == TME_STP222X_ASPACE_NULL
875 ? TME_STP222X_CONN_NULL
876 : tme_stp222x_aspace_lookup(stp222x,
877 aspace_i,
878 &slave_address));
879 master_cycle->tme_bus_cycle_address = slave_address;
880
881 /* dispatch on the address space: */
882 switch (aspace_i) {
883
884 case TME_STP2222_ASPACE_PCI_CONFIGURATION:
885 assert (!TME_STP222X_IS_2220(stp222x));
886 #if 0
887 master_cycle->tme_bus_cycle_type |= TME_PCI_CYCLE_CONFIGURATION;
888 #endif
889 abort();
890
891 case TME_STP2222_ASPACE_PCI_IO(0):
892 case TME_STP2222_ASPACE_PCI_IO(1):
893 assert (!TME_STP222X_IS_2220(stp222x));
894 #if 0
895 master_cycle->tme_bus_cycle_type |= TME_PCI_CYCLE_IO;
896 #endif
897 abort();
898
899 case TME_STP2220_ASPACE_SBUS:
900 assert (TME_STP222X_IS_2220(stp222x));
901 break;
902
903 default:
904 assert (!TME_STP222X_IS_2220(stp222x));
905 assert (aspace_i == TME_STP2222_ASPACE_PCI_MEMORY(0)
906 || aspace_i == TME_STP2222_ASPACE_PCI_MEMORY(1));
907 abort();
908
909 case TME_STP222X_ASPACE_NULL:
910
911 /* if this isn't an aligned 64-bit access: */
912 if (__tme_predict_false((slave_address % TME_STP222X_REG_SIZE) != 0
913 || master_cycle->tme_bus_cycle_size != TME_STP222X_REG_SIZE)) {
914 abort();
915 }
916
917 /* NB: read the _tme_stp103x_bus_port() comment about bus routing
918 information coming out of the CPU: */
919 /* replace the bus cycle routing information: */
920 assert (TME_STP222X_REG_SIZE == (1 << TME_BUS64_LOG2));
921 master_cycle->tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS64_LOG2);
922 master_cycle->tme_bus_cycle_lane_routing
923 = (_tme_stp222x_bus_router_regs
924 - TME_BUS_ROUTER_INDEX(TME_BUS64_LOG2, TME_BUS64_LOG2, 0));
925
926 /* set the register address, poisoning it if it's too big for the
927 structure: */
928 reg.tme_stp222x_reg_address = slave_address;
929 if (reg.tme_stp222x_reg_address != slave_address) {
930 reg.tme_stp222x_reg_address = 0xffff;
931 }
932
933 /* if this is a write: */
934 reg.tme_stp222x_reg_write = (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
935 if (reg.tme_stp222x_reg_write) {
936
937 /* get value being written: */
938 tme_bus_cycle_xfer_memory(master_cycle,
939 ((tme_uint8_t *) ®.tme_stp222x_reg_value) - slave_address,
940 slave_address + sizeof(tme_uint64_t) - 1);
941 reg.tme_stp222x_reg_value = tme_betoh_u64(reg.tme_stp222x_reg_value);
942 }
943
944 /* otherwise, this must be a read: */
945 else if (__tme_predict_false(master_cycle->tme_bus_cycle_type != TME_BUS_CYCLE_READ)) {
946 abort();
947 }
948
949 /* assume that this register access won't be completed: */
950 reg.tme_stp222x_reg_completed = FALSE;
951
952 /* dispatch on the register group: */
953 reggroup = TME_STP222X_REGGROUP_WHICH(reg.tme_stp222x_reg_address);
954 switch (reggroup) {
955
956 case 0x00:
957 _tme_stp222x_reg00_regs(stp222x, ®);
958 break;
959
960 case 0x01:
961 switch (TME_STP222X_REGGROUP_INDEX(reg.tme_stp222x_reg_address)) {
962 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG01_PM_CR):
963 abort();
964 case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG01_PM_COUNT):
965 abort();
966 default:
967 break;
968 }
969 break;
970
971 case 0x24:
972 case 0x02:
973 if (reggroup
974 == (TME_STP222X_IS_2220(stp222x)
975 ? 0x24
976 : 0x02)) {
977 tme_stp222x_iommu_regs(stp222x, ®);
978 }
979 break;
980
981 case 0x2c:
982 case 0x0c:
983 case 0x30:
984 case 0x10:
985 case 0x1a:
986 case 0x60:
987 case 0x80:
988 tme_stp222x_mdu_regs_imr_retry(stp222x, ®);
989 break;
990
991 case 0x20:
992 if (TME_STP222X_IS_2220(stp222x)) {
993 _tme_stp2220_sbus_regs(stp222x, ®);
994 }
995 break;
996
997 case 0x34:
998 case 0x14:
999 case 0x38:
1000 case 0x18:
1001 tme_stp222x_mdu_regs_clear(stp222x, ®);
1002 break;
1003
1004 case 0x3c:
1005 case 0x1c:
1006 if ((reggroup < 0x30) == !TME_STP222X_IS_2220(stp222x)) {
1007 tme_stp222x_timer_regs(stp222x, ®);
1008 }
1009 break;
1010
1011 case 0x28:
1012 tme_stp222x_stc_regs(stp222x, 0, ®);
1013 break;
1014
1015 case 0x40:
1016 abort();
1017
1018 case 0x48:
1019 if (TME_STP222X_IS_2220(stp222x)) {
1020 tme_stp222x_mdu_regs_diag(stp222x, ®);
1021 }
1022 else {
1023 tme_stp222x_stc_regs(stp222x, 1, ®);
1024 }
1025 break;
1026
1027 case 0xa0:
1028 abort();
1029
1030 case 0x44:
1031 case 0x45:
1032 case 0x46:
1033 case 0xa4:
1034 case 0xa5:
1035 case 0xa6:
1036 if ((reggroup >= 0xa0) == !TME_STP222X_IS_2220(stp222x)) {
1037 tme_stp222x_iommu_regs_diag(stp222x, ®);
1038 }
1039 break;
1040
1041 case 0xa8:
1042 if (!TME_STP222X_IS_2220(stp222x)) {
1043 tme_stp222x_mdu_regs_diag(stp222x, ®);
1044 }
1045 break;
1046
1047 default:
1048 if (TME_STP222X_IS_2220(stp222x)
1049 ? (reggroup >= 0x50
1050 && reggroup <= 0x59)
1051 : (reggroup >= 0xb0
1052 && reggroup <= 0xb9)) {
1053 tme_stp222x_stc_regs_diag(stp222x, 0, ®);
1054 }
1055 else if (!TME_STP222X_IS_2220(stp222x)
1056 && reggroup >= 0xc0
1057 && reggroup <= 0xc9) {
1058 tme_stp222x_stc_regs_diag(stp222x, 1, ®);
1059 }
1060 break;
1061 }
1062
1063 /* if this register access was not completed: */
1064 if (__tme_predict_false(!reg.tme_stp222x_reg_completed)) {
1065
1066 tme_log(TME_STP222X_LOG_HANDLE(stp222x), 100, TME_OK,
1067 (TME_STP222X_LOG_HANDLE(stp222x),
1068 _("unknown[0x%04x] %s 0x%" TME_PRIx64),
1069 reg.tme_stp222x_reg_address,
1070 (reg.tme_stp222x_reg_write
1071 ? "<-"
1072 : "->"),
1073 reg.tme_stp222x_reg_value));
1074 }
1075
1076 /* if this was a read: */
1077 if (!reg.tme_stp222x_reg_write) {
1078
1079 /* return the value: */
1080 reg.tme_stp222x_reg_value = tme_htobe_u64(reg.tme_stp222x_reg_value);
1081 tme_bus_cycle_xfer_memory(master_cycle,
1082 ((tme_uint8_t *) ®.tme_stp222x_reg_value) - slave_address,
1083 slave_address + sizeof(tme_uint64_t) - 1);
1084 }
1085
1086 /* complete the cycle: */
1087 master_completion->tme_completion_error = TME_OK;
1088 tme_stp222x_completion_validate(stp222x, master_completion);
1089 master_completion = NULL;
1090 *_master_fast_cycle_types = 0;
1091 break;
1092 }
1093
1094 /* if we didn't complete the cycle ourselves: */
1095 if (master_completion != NULL) {
1096
1097 /* start this cycle: */
1098 assert (stp222x->tme_stp222x_master_completion == NULL);
1099 stp222x->tme_stp222x_master_completion = &master_completion;
1100
1101 /* run the slave bus cycle: */
1102 tme_stp22xx_slave_cycle(master_conn_bus,
1103 slave_conn_index,
1104 master_cycle,
1105 _master_fast_cycle_types,
1106 &master_completion);
1107 }
1108
1109 /* leave: */
1110 tme_stp222x_leave(stp222x);
1111 }
1112
1113 /* this receives an interrupt: */
1114 static void
_tme_stp222x_interrupt(struct tme_upa_bus_connection * master_conn_upa,tme_uint32_t slave_mid,const tme_uint64_t * data,struct tme_completion * master_completion)1115 _tme_stp222x_interrupt(struct tme_upa_bus_connection *master_conn_upa,
1116 tme_uint32_t slave_mid,
1117 const tme_uint64_t *data,
1118 struct tme_completion *master_completion)
1119 {
1120 abort();
1121 }
1122
1123 /* this fills a TLB entry: */
1124 static void
_tme_stp222x_tlb_fill(struct tme_bus_connection * agent_conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t agent_address_wider,unsigned int cycle_type)1125 _tme_stp222x_tlb_fill(struct tme_bus_connection *agent_conn_bus,
1126 struct tme_bus_tlb *tlb,
1127 tme_bus_addr_t agent_address_wider,
1128 unsigned int cycle_type)
1129 {
1130 struct tme_stp222x *stp222x;
1131 tme_bus_addr64_t slave_address;
1132 tme_uint32_t aspace_i;
1133 tme_uint32_t slave_conn_index;
1134 tme_bus_addr32_t region_size_m1;
1135 tme_bus_addr64_t agent_address;
1136 struct tme_bus_tlb tlb_mapping;
1137
1138 /* enter: */
1139 stp222x = tme_stp222x_enter_bus(agent_conn_bus);
1140
1141 /* convert the agent's address into an address space, slave
1142 connection index and address: */
1143 slave_address = agent_address_wider;
1144 aspace_i
1145 = _tme_stp222x_lookup_address(stp222x,
1146 agent_address_wider,
1147 ®ion_size_m1);
1148 slave_address &= region_size_m1;
1149 slave_conn_index
1150 = (aspace_i == TME_STP222X_ASPACE_NULL
1151 ? TME_STP222X_CONN_NULL
1152 : tme_stp222x_aspace_lookup(stp222x,
1153 aspace_i,
1154 &slave_address));
1155
1156 /* fill this TLB entry: */
1157 tme_stp22xx_tlb_fill(agent_conn_bus,
1158 tlb,
1159 slave_conn_index,
1160 slave_address,
1161 cycle_type);
1162
1163 /* leave: */
1164 tme_stp222x_leave(stp222x);
1165
1166 /* map the filled TLB entry: */
1167 agent_address = ~ (tme_bus_addr64_t) region_size_m1;
1168 agent_address &= agent_address_wider;
1169 tlb_mapping.tme_bus_tlb_addr_first = agent_address;
1170 agent_address |= region_size_m1;
1171 tlb_mapping.tme_bus_tlb_addr_last = agent_address;
1172 #if TME_STP22XX_BUS_TRANSITION
1173 tlb_mapping.tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE);
1174 #endif /* TME_STP22XX_BUS_TRANSITION */
1175 tme_bus_tlb_map(tlb, slave_address, &tlb_mapping, agent_address_wider);
1176 }
1177
1178 #if TME_STP22XX_BUS_TRANSITION
1179
1180 /* this is the bus signal transition glue: */
1181 static int
_tme_stp222x_signal_transition(struct tme_bus_connection * conn_bus,unsigned int signal)1182 _tme_stp222x_signal_transition(struct tme_bus_connection *conn_bus,
1183 unsigned int signal)
1184 {
1185 struct tme_completion completion_buffer;
1186 tme_completion_init(&completion_buffer);
1187 _tme_stp222x_signal(conn_bus,
1188 signal,
1189 &completion_buffer);
1190 return (TME_OK);
1191 }
1192 #define _tme_stp222x_signal _tme_stp222x_signal_transition
1193
1194 /* this is the bus cycle transition glue: */
1195 static int
_tme_stp222x_cycle_transition(void * _master_conn_bus,struct tme_bus_cycle * master_cycle)1196 _tme_stp222x_cycle_transition(void *_master_conn_bus,
1197 struct tme_bus_cycle *master_cycle)
1198 {
1199 struct tme_completion completion_buffer;
1200 struct tme_stp222x *stp222x;
1201 struct tme_bus_connection *master_conn_bus;
1202 tme_uint32_t master_fast_cycle_types;
1203
1204 tme_completion_init(&completion_buffer);
1205
1206 master_conn_bus = (struct tme_bus_connection *) _master_conn_bus;
1207 stp222x = (struct tme_stp222x *) master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
1208 (master_conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus
1209 ? _tme_stp222x_cycle
1210 : tme_stp222x_iommu_cycle)
1211 (master_conn_bus,
1212 master_cycle,
1213 &master_fast_cycle_types,
1214 &completion_buffer);
1215 return (completion_buffer.tme_completion_error);
1216 }
1217
1218 /* the bus TLB fill transition glue: */
1219 static int
_tme_stp222x_tlb_fill_transition(struct tme_bus_connection * agent_conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t agent_address_wider,unsigned int cycle_type)1220 _tme_stp222x_tlb_fill_transition(struct tme_bus_connection *agent_conn_bus,
1221 struct tme_bus_tlb *tlb,
1222 tme_bus_addr_t agent_address_wider,
1223 unsigned int cycle_type)
1224 {
1225 struct tme_stp222x *stp222x;
1226
1227 stp222x = (struct tme_stp222x *) agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
1228 (agent_conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus
1229 ? _tme_stp222x_tlb_fill
1230 : tme_stp222x_iommu_tlb_fill)
1231 (agent_conn_bus,
1232 tlb,
1233 agent_address_wider,
1234 cycle_type);
1235
1236 /* we always handle any slow cycles: */
1237 tlb->tme_bus_tlb_cycles_ok |= cycle_type;
1238 tlb->tme_bus_tlb_addr_offset = 0;
1239 tlb->tme_bus_tlb_addr_shift = 0;
1240 tlb->tme_bus_tlb_cycle = _tme_stp222x_cycle_transition;
1241 tlb->tme_bus_tlb_cycle_private = agent_conn_bus;
1242 assert (tlb->tme_bus_tlb_fault_handler_count == 0);
1243
1244 return (TME_OK);
1245 }
1246 #define _tme_stp222x_tlb_fill _tme_stp222x_tlb_fill_transition
1247 #define tme_stp222x_iommu_tlb_fill _tme_stp222x_tlb_fill_transition
1248
1249 #endif /* TME_STP22XX_BUS_TRANSITION */
1250
1251 /* the connection scorer: */
1252 static int
_tme_stp222x_connection_score(struct tme_connection * conn,unsigned int * _score)1253 _tme_stp222x_connection_score(struct tme_connection *conn,
1254 unsigned int *_score)
1255 {
1256 struct tme_bus_connection *conn_bus;
1257 struct tme_stp222x *stp222x;
1258 unsigned int score;
1259 struct tme_upa_bus_connection *conn_upa_other;
1260 struct tme_bus_connection *conn_bus_other;
1261
1262 /* recover the bus connection: */
1263 conn_bus = (struct tme_bus_connection *) conn;
1264
1265 /* enter: */
1266 stp222x = tme_stp222x_enter_bus(conn_bus);
1267
1268 /* assume that this connection is useless: */
1269 score = 0;
1270
1271 /* dispatch on the connection type: */
1272 conn_upa_other = (struct tme_upa_bus_connection *) conn->tme_connection_other;
1273 conn_bus_other = (struct tme_bus_connection *) conn->tme_connection_other;
1274 switch (conn->tme_connection_type) {
1275
1276 /* this must be a UPA controller, and not another agent: */
1277 case TME_CONNECTION_BUS_UPA:
1278 if (conn_upa_other->tme_upa_bus_connection.tme_bus_tlb_set_add != NULL
1279 && conn_upa_other->tme_upa_bus_interrupt != NULL) {
1280 score = 10;
1281 }
1282 break;
1283
1284 /* this must be a bus device: */
1285 case TME_CONNECTION_BUS_GENERIC:
1286 if (conn_bus_other->tme_bus_tlb_set_add == NULL) {
1287 score = 1;
1288 }
1289 break;
1290
1291 default: abort();
1292 }
1293
1294 /* leave: */
1295 tme_stp222x_leave(stp222x);
1296 *_score = score;
1297 return (TME_OK);
1298 }
1299
1300 /* this makes a new connection: */
1301 static int
_tme_stp222x_connection_make(struct tme_connection * conn,unsigned int state)1302 _tme_stp222x_connection_make(struct tme_connection *conn, unsigned int state)
1303 {
1304 struct tme_upa_bus_connection *conn_upa;
1305 struct tme_bus_connection *conn_bus;
1306 struct tme_stp222x *stp222x;
1307 unsigned int conn_index;
1308 tme_uint32_t slot;
1309 tme_bus_addr32_t offset;
1310 int slaveonly;
1311 tme_uint32_t connid;
1312 unsigned int obio_i;
1313
1314 /* ignore a half-connection: */
1315 if (state == TME_CONNECTION_HALF) {
1316 return (TME_OK);
1317 }
1318
1319 /* recover the bus connection: */
1320 conn_upa = (struct tme_upa_bus_connection *) conn;
1321 conn_bus = (struct tme_bus_connection *) conn;
1322
1323 /* enter: */
1324 stp222x = tme_stp222x_enter_bus(conn_bus);
1325
1326 /* if this is the UPA bus connection: */
1327 if (conn->tme_connection_type == TME_CONNECTION_BUS_UPA) {
1328
1329 /* save the UPA bus connection: */
1330 stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_upa = conn_upa;
1331 }
1332
1333 /* otherwise, this is a device bus connection: */
1334 else {
1335
1336 /* if this is an stp2220: */
1337 if (TME_STP222X_IS_2220(stp222x)) {
1338
1339 /* split the temporary connection id into the slot, offset, and
1340 slaveonly flag: */
1341 offset = conn->tme_connection_id;
1342 slot = (offset / TME_STP2220_SLOT_SIZE);
1343 offset %= TME_STP2220_SLOT_SIZE;
1344 slaveonly
1345 = (slot > TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1)
1346 && slot < TME_STP2220_SLOT_OBIO(0));
1347 if (slaveonly) {
1348 slot ^= TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD);
1349 }
1350
1351 /* if this is a card: */
1352 if (slot >= TME_STP2220_SLOT_CARD(0)
1353 && slot <= TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1)) {
1354
1355 /* start the card connection ID: */
1356 connid = TME_STP222X_CONNID_TYPE_CARD;
1357 TME_FIELD_MASK_DEPOSITU(connid,
1358 TME_STP2220_CONNID_CARD_WHICH,
1359 (slot - TME_STP2220_SLOT_CARD(0)));
1360 TME_FIELD_MASK_DEPOSITU(connid,
1361 TME_STP2220_CONNID_CARD_OFFSET,
1362 offset);
1363
1364 /* if this is a slave connection: */
1365 if (slaveonly) {
1366
1367 /* this connection will use the next slave connection index,
1368 which is an alternate connection index: */
1369 conn_index = stp222x->tme_stp222x_slave_conn_index_next++;
1370 connid |= TME_STP2220_CONNID_CARD_ALTERNATE;
1371 }
1372
1373 else {
1374
1375 /* assume that this is the first master connection for this
1376 card, which will use the card's primary master connection
1377 index: */
1378 conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP2220_CONNID_CARD_WHICH);
1379
1380 /* if this is not the first master connection for this card: */
1381 if (stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL) {
1382
1383 /* this connection will use an alternate master connection
1384 index: */
1385 connid |= TME_STP2220_CONNID_CARD_ALTERNATE;
1386
1387 /* starting from the first alternate master connection
1388 index for this card and moving forward, search the
1389 remaining master connection indices for a free one: */
1390 /* NB: this means if you have an SBus card with a lot of
1391 different masters on it, you should put it in the last
1392 card slot, to save the preferred alternate master
1393 connection indices for the other card slots: */
1394 conn_index
1395 = (TME_STP2220_SLOTS_CARD
1396 + (connid & TME_STP2220_CONNID_CARD_WHICH));
1397 for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL;) {
1398 if (++conn_index == TME_STP222X_CONN_SLAVE0) {
1399 abort();
1400 }
1401 }
1402 }
1403 }
1404 }
1405
1406 /* otherwise, this is an obio device: */
1407 else {
1408
1409 /* if this is the slave I/O slot, force slaveonly: */
1410 if (slot == TME_STP2220_SLOT_SLAVIO) {
1411 slaveonly = TRUE;
1412 }
1413
1414 /* if this is a slave connection: */
1415 if (slaveonly) {
1416
1417 /* this connection will use the next slave connection index: */
1418 conn_index = stp222x->tme_stp222x_slave_conn_index_next++;
1419 }
1420
1421 /* otherwise, this is a master connection: */
1422 else {
1423
1424 /* starting from the last master connection index and
1425 moving backwards, search for a free one: */
1426 conn_index = TME_STP222X_CONN_SLAVE0 - 1;
1427 for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL;) {
1428 if (conn_index-- == 0) {
1429 abort();
1430 }
1431 }
1432 }
1433
1434 /* assume that this is not a known obio connection, and make
1435 the obio long connection id: */
1436 connid
1437 = (TME_STP222X_CONNID_TYPE_OBIO
1438 | TME_STP222X_CONNID_OBIO_TYPE_LONG);
1439 TME_FIELD_MASK_DEPOSITU(connid,
1440 TME_STP222X_CONNID_OBIO_LONG_WHICH,
1441 (slot - TME_STP2220_SLOT_OBIO(0)));
1442 TME_FIELD_MASK_DEPOSITU(connid,
1443 TME_STP222X_CONNID_OBIO_LONG_OFFSET,
1444 offset);
1445
1446 /* if this is a known obio connection: */
1447 for (obio_i = 0; obio_i < TME_ARRAY_ELS(_tme_stp2220_obios); obio_i++) {
1448 if (_tme_stp2220_obios[obio_i]._tme_stp2220_obio_slot == slot
1449 && _tme_stp2220_obios[obio_i]._tme_stp2220_obio_offset == offset) {
1450
1451 /* make the obio short connection id: */
1452 connid
1453 = (TME_STP222X_CONNID_TYPE_OBIO
1454 | TME_STP222X_CONNID_OBIO_TYPE_SHORT);
1455 TME_FIELD_MASK_DEPOSITU(connid,
1456 TME_STP222X_CONNID_OBIO_SHORT_IDI,
1457 _tme_stp2220_obios[obio_i]._tme_stp2220_obio_idi);
1458 TME_FIELD_MASK_DEPOSITU(connid,
1459 TME_STP222X_CONNID_OBIO_SHORT_CONN_WHICH,
1460 conn_index);
1461 break;
1462 }
1463 }
1464 }
1465
1466 /* save the SBus offset for this connection: */
1467 assert (conn_index < TME_STP222X_CONN_NULL);
1468 stp222x->tme_stp2220_conn_offset[conn_index] = TME_STP2220_SBUS_ADDRESS(slot, offset);
1469 }
1470
1471 /* otherwise, this is an stp222x: */
1472 else {
1473 abort();
1474 }
1475
1476 /* update this connection's id: */
1477 conn->tme_connection_id = connid;
1478
1479 /* add this connection to the list: */
1480 assert (conn_index < TME_STP222X_CONN_NULL);
1481 if (conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC) {
1482 assert (TME_STP222X_IS_2220(stp222x));
1483 stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus = conn_bus;
1484 }
1485 else {
1486 assert (FALSE);
1487 }
1488
1489 /* rebuild the address spaces: */
1490 if (tme_stp222x_aspaces_rebuild(stp222x)) {
1491 abort();
1492 }
1493 }
1494
1495 /* leave: */
1496 tme_stp222x_leave(stp222x);
1497 return (TME_OK);
1498 }
1499
1500 /* this breaks a connection: */
1501 static int
_tme_stp222x_connection_break(struct tme_connection * conn,unsigned int state)1502 _tme_stp222x_connection_break(struct tme_connection *conn, unsigned int state)
1503 {
1504 abort();
1505 }
1506
1507 /* this makes new connection sides: */
1508 static int
_tme_stp222x_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)1509 _tme_stp222x_connections_new(struct tme_element *element,
1510 const char * const *args,
1511 struct tme_connection **_conns,
1512 char **_output)
1513 {
1514 int rc;
1515 struct tme_stp222x *stp222x;
1516 struct tme_upa_bus_connection *conn_upa;
1517 struct tme_bus_connection *conn_bus;
1518 struct tme_connection *conn;
1519 tme_bus_addr_t slot_wider;
1520 tme_bus_addr_t offset_wider;
1521 int slaveonly;
1522
1523 /* assume that we will succeed: */
1524 rc = TME_OK;
1525
1526 /* recover our data structure: */
1527 stp222x = (struct tme_stp222x *) element->tme_element_private;
1528
1529 /* lock the mutex: */
1530 tme_mutex_lock(&stp222x->tme_stp222x.tme_stp22xx_mutex);
1531
1532 /* if we have no arguments, this is the UPA connection: */
1533 if (args[1] == NULL) {
1534
1535 /* if we already have the UPA connection: */
1536 if (stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_upa != NULL) {
1537 rc = EEXIST;
1538 }
1539
1540 /* otherwise, we don't have a UPA connection yet: */
1541 else {
1542
1543 /* create a UPA connection: */
1544 conn_upa = tme_new0(struct tme_upa_bus_connection, 1);
1545 conn_upa->tme_upa_bus_connection.tme_bus_connection.tme_connection_type = TME_CONNECTION_BUS_UPA;
1546 conn_upa->tme_upa_bus_interrupt = _tme_stp222x_interrupt;
1547
1548 /* fill in the generic bus connection: */
1549 conn_bus = &conn_upa->tme_upa_bus_connection;
1550 conn_bus->tme_bus_signals_add = NULL;
1551 conn_bus->tme_bus_signal = _tme_stp222x_signal;
1552 conn_bus->tme_bus_intack = NULL;
1553 conn_bus->tme_bus_tlb_set_add = NULL;
1554 conn_bus->tme_bus_tlb_fill = _tme_stp222x_tlb_fill;
1555
1556 /* fill in the generic connection: */
1557 conn = &conn_bus->tme_bus_connection;
1558 conn->tme_connection_score = _tme_stp222x_connection_score;
1559 conn->tme_connection_make = _tme_stp222x_connection_make;
1560 conn->tme_connection_break = _tme_stp222x_connection_break;
1561
1562 /* add in this connection side possibility: */
1563 conn->tme_connection_next = *_conns;
1564 *_conns = conn;
1565 }
1566 }
1567
1568 /* otherwise, if this is an stp2220 and we have "slot" and "offset"
1569 arguments, and an optional "slaveonly" argument, this is an SBus
1570 connection: */
1571 else if (TME_STP222X_IS_2220(stp222x)
1572 && TME_ARG_IS(args[1], "slot")
1573 && args[2] != NULL
1574 && TME_ARG_IS(args[3], "offset")
1575 && args[4] != NULL
1576 && (((slaveonly = TME_ARG_IS(args[5], "slaveonly"))
1577 && args[6] == NULL)
1578 || args[5] == NULL)) {
1579
1580 /* convert the slot and base offset: */
1581 slot_wider = tme_bus_addr_parse(args[2], TME_STP2220_SLOT_OBIO(TME_STP2220_SLOTS_OBIO));
1582 offset_wider = tme_bus_addr_parse(args[4], TME_STP2220_SLOT_SIZE);
1583
1584 /* if this is a bad slot: */
1585 if ((slot_wider < TME_STP2220_SLOT_CARD(0)
1586 || slot_wider > TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1))
1587 && (slot_wider < TME_STP2220_SLOT_OBIO(0)
1588 || slot_wider > TME_STP2220_SLOT_OBIO(TME_STP2220_SLOTS_OBIO - 1))) {
1589 tme_output_append_error(_output,
1590 "%s %s",
1591 _("bad slot"),
1592 args[2]);
1593 rc = EINVAL;
1594 }
1595
1596 /* if this is a bad offset: */
1597 else if (offset_wider >= TME_STP2220_SLOT_SIZE) {
1598 tme_output_append_error(_output,
1599 "%s %s",
1600 _("bad offset"),
1601 args[4]);
1602 rc = EINVAL;
1603 }
1604
1605 /* otherwise, the arguments are ok: */
1606 else {
1607
1608 /* create a generic bus connection: */
1609 conn_bus = tme_new0(struct tme_bus_connection, 1);
1610 conn_bus->tme_bus_connection.tme_connection_type = TME_CONNECTION_BUS_GENERIC;
1611
1612 /* fill in the generic bus connection: */
1613 conn_bus->tme_bus_signals_add = NULL;
1614 conn_bus->tme_bus_signal = _tme_stp222x_signal;
1615 conn_bus->tme_bus_intack = NULL;
1616 conn_bus->tme_bus_tlb_set_add = tme_stp22xx_tlb_set_add;
1617 conn_bus->tme_bus_tlb_fill = tme_stp222x_iommu_tlb_fill;
1618
1619 /* fill in the generic connection: */
1620 /* NB: this connection's temporary id is the SBus address, with
1621 the slot exclusive-ORed with the maximum number of cards if
1622 the "slaveonly" flag was given: */
1623 conn = &conn_bus->tme_bus_connection;
1624 conn->tme_connection_id
1625 = TME_STP2220_SBUS_ADDRESS((slot_wider
1626 ^ (slaveonly
1627 ? TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD)
1628 : 0)),
1629 offset_wider);
1630 conn->tme_connection_score = _tme_stp222x_connection_score;
1631 conn->tme_connection_make = _tme_stp222x_connection_make;
1632 conn->tme_connection_break = _tme_stp222x_connection_break;
1633
1634 /* add in this connection side possibility: */
1635 conn->tme_connection_next = *_conns;
1636 *_conns = conn;
1637 }
1638 }
1639
1640 /* otherwise, the arguments are unknown: */
1641 else {
1642 if (TME_STP222X_IS_2220(stp222x)) {
1643 tme_output_append_error(_output,
1644 "%s %s [ slot %s offset %s [ slaveonly ] ]",
1645 _("usage:"),
1646 args[0],
1647 _("SLOT"),
1648 _("OFFSET"));
1649 }
1650 rc = EINVAL;
1651 }
1652
1653 /* unlock the mutex: */
1654 tme_mutex_unlock(&stp222x->tme_stp222x.tme_stp22xx_mutex);
1655
1656 return (rc);
1657 }
1658
1659 /* this creates a new stp222x element: */
1660 static int
_tme_stp222x_new(struct tme_element * element,const char * const * args,const void * extra,char ** _output,unsigned int is_2220)1661 _tme_stp222x_new(struct tme_element *element,
1662 const char * const *args,
1663 const void *extra,
1664 char **_output,
1665 unsigned int is_2220)
1666 {
1667 struct tme_stp222x *stp222x;
1668 int arg_i;
1669 int usage;
1670
1671 /* check our arguments: */
1672 usage = 0;
1673 arg_i = 1;
1674 for (;;) {
1675
1676 if (0) {
1677 }
1678
1679 /* if we ran out of arguments: */
1680 else if (args[arg_i] == NULL) {
1681
1682 break;
1683 }
1684
1685 /* otherwise this is a bad argument: */
1686 else {
1687 tme_output_append_error(_output,
1688 "%s %s, ",
1689 args[arg_i],
1690 _("unexpected"));
1691 usage = TRUE;
1692 break;
1693 }
1694 }
1695
1696 if (usage) {
1697 tme_output_append_error(_output,
1698 "%s %s",
1699 _("usage:"),
1700 args[0]);
1701 return (EINVAL);
1702 }
1703
1704 /* start the stp222x structure: */
1705 stp222x = tme_new0(struct tme_stp222x, 1);
1706 stp222x->tme_stp222x.tme_stp22xx_element = element;
1707 stp222x->tme_stp222x.tme_stp22xx_run = _tme_stp222x_run;
1708 tme_stp22xx_init(&stp222x->tme_stp222x,
1709 sizeof(struct tme_stp222x),
1710 TME_STP222X_CONN_NULL);
1711
1712 /* set the type: */
1713 stp222x->tme_stp222x_is_2220 = is_2220;
1714 if (TME_STP222X_IS_2220(stp222x) != is_2220) {
1715 tme_free(stp222x);
1716 return (ENXIO);
1717 }
1718
1719 /* the UPA bus reset signal is initially negated: */
1720 stp222x->tme_stp222x_reset_level = TME_BUS_SIGNAL_LEVEL_NEGATED;
1721
1722 /* initialize the CSR: */
1723 stp222x->tme_stp222x_csr
1724 = (0x1f * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_MID));
1725
1726 /* initialize the miscellaneous registers: */
1727 stp222x->tme_stp222x_upa_port_config = 1;
1728
1729 /* initialize the connections: */
1730 stp222x->tme_stp222x_slave_conn_index_next = TME_STP222X_CONN_SLAVE0;
1731
1732 /* initialize the timers: */
1733 tme_stp222x_timer_init(stp222x, &stp222x->tme_stp222x_timers[0]);
1734 tme_stp222x_timer_init(stp222x, &stp222x->tme_stp222x_timers[1]);
1735
1736 /* initialize the MDU: */
1737 tme_stp222x_mdu_init(stp222x);
1738
1739 /* initialize the IOMMU: */
1740 tme_stp222x_iommu_init(stp222x);
1741
1742 /* initialize the streaming caches: */
1743 tme_stp222x_stc_init(&stp222x->tme_stp222x_stcs[0]);
1744 tme_stp222x_stc_init(&stp222x->tme_stp222x_stcs[1]);
1745
1746 /* fill the element: */
1747 element->tme_element_private = stp222x;
1748 element->tme_element_connections_new = _tme_stp222x_connections_new;
1749
1750 return (TME_OK);
1751 }
1752
1753 /* this creates a new stp2220 element: */
TME_ELEMENT_X_NEW_DECL(tme_ic_,stp22xx,stp2220)1754 TME_ELEMENT_X_NEW_DECL(tme_ic_,stp22xx,stp2220) {
1755 return (_tme_stp222x_new(element, args, extra, _output, TRUE));
1756 }
1757