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 				  &region_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 *) &reg.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, &reg);
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, &reg);
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, &reg);
989       break;
990 
991     case 0x20:
992       if (TME_STP222X_IS_2220(stp222x)) {
993 	_tme_stp2220_sbus_regs(stp222x, &reg);
994       }
995       break;
996 
997     case 0x34:
998     case 0x14:
999     case 0x38:
1000     case 0x18:
1001       tme_stp222x_mdu_regs_clear(stp222x, &reg);
1002       break;
1003 
1004     case 0x3c:
1005     case 0x1c:
1006       if ((reggroup < 0x30) == !TME_STP222X_IS_2220(stp222x)) {
1007 	tme_stp222x_timer_regs(stp222x, &reg);
1008       }
1009       break;
1010 
1011     case 0x28:
1012       tme_stp222x_stc_regs(stp222x, 0, &reg);
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, &reg);
1021       }
1022       else {
1023 	tme_stp222x_stc_regs(stp222x, 1, &reg);
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, &reg);
1038       }
1039       break;
1040 
1041     case 0xa8:
1042       if (!TME_STP222X_IS_2220(stp222x)) {
1043 	tme_stp222x_mdu_regs_diag(stp222x, &reg);
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, &reg);
1054       }
1055       else if (!TME_STP222X_IS_2220(stp222x)
1056 	       && reggroup >= 0xc0
1057 	       && reggroup <= 0xc9) {
1058 	tme_stp222x_stc_regs_diag(stp222x, 1, &reg);
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 *) &reg.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 				  &region_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