|
|
1.1 root 1: /* $Id: stp222x-stc.c,v 1.4 2010/06/05 18:59:29 fredette Exp $ */
2:
3: /* ic/stp222x-stc.c - emulation of the STC of the UPA to SBus
4: interface controller (STP2220) and the UPA to PCI interface
5: controller (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-stc.c,v 1.4 2010/06/05 18:59:29 fredette Exp $");
40:
41: /* includes: */
42: #include "stp222x-impl.h"
43:
44: /* macros: */
45:
46: /* streaming buffer register offsets: */
47: #define TME_STP222X_STC_REGGROUP_INDEX_CR TME_STP222X_REGGROUP_INDEX(0x00)
48: #define TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH TME_STP222X_REGGROUP_INDEX(0x08)
49: #define TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC TME_STP222X_REGGROUP_INDEX(0x10)
50:
51: /* an STC control register: */
52: #define TME_STP222X_STC_CR_LPTR ((2 << 7) - (1 << 4))
53: #define TME_STP222X_STC_CR_LE (1 << 3)
54: #define TME_STP222X_STC_CR_RR_DIS (1 << 2)
55: #define TME_STP222X_STC_CR_DE (1 << 1)
56: #define TME_STP222X_STC_CR_SB_EN (1 << 0)
57:
58: /* the size of the stp222x flush blocks: */
59: #define TME_STP2220_STC_FLUSHSYNC_SIZE ((tme_uint64_t) 4)
60: #define TME_STP2222_STC_FLUSHSYNC_SIZE ((tme_uint64_t) 64)
61:
62: /* the number of entries in each streaming buffer: */
63: #define TME_STP222X_STC_ENTRY_COUNT (16)
64:
65: /* this flushes a streaming cache: */
66: int
67: tme_stp222x_stc_flush(struct tme_stp222x *stp222x)
68: {
69: struct tme_stp222x_stc *stc;
70: tme_uint64_t address;
71: struct tme_bus_tlb *tlb;
72: struct tme_bus_connection *slave_conn_bus;
73: struct tme_bus_connection *slave_conn_bus_other;
74: #if TME_STP22XX_BUS_TRANSITION
75: int rc;
76: #endif /* TME_STP22XX_BUS_TRANSITION */
77: tme_shared tme_uint8_t *memory;
78:
79: stc = &stp222x->tme_stp222x_stcs[0];
80: if (!stc->tme_stp222x_stc_pgflush) {
81: stc = &stp222x->tme_stp222x_stcs[1];
82: if (!stc->tme_stp222x_stc_pgflush) {
83: return (FALSE);
84: }
85: }
86:
87: /* get the flushsync address: */
88: address
89: = (stc->tme_stp222x_stc_flushsync
90: & (TME_STP222X_IS_2220(stp222x)
91: ? ((((tme_uint64_t) 2) << 40)
92: - TME_STP2220_STC_FLUSHSYNC_SIZE)
93: : ((((tme_uint64_t) 2) << 40)
94: - TME_STP2222_STC_FLUSHSYNC_SIZE)));
95:
96: /* busy the flushsync TLB: */
97: tlb = &stc->tme_stp222x_stc_flushsync_tlb;
98: tme_bus_tlb_busy(tlb);
99:
100: /* if the flushsync TLB is invalid or doesn't apply: */
101: if (tme_bus_tlb_is_invalid(tlb)
102: || address < (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_first
103: || address > (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_last) {
104:
105: /* unbusy the flushsync TLB for filling: */
106: tme_bus_tlb_unbusy_fill(tlb);
107:
108: /* busy the UPA connection: */
109: slave_conn_bus = tme_stp222x_slave_busy_bus(stp222x, TME_STP222X_CONN_UPA);
110:
111: /* leave: */
112: tme_stp222x_leave(stp222x);
113:
114: /* fill the TLB entry: */
115: slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
116: #if TME_STP22XX_BUS_TRANSITION
117: rc =
118: #endif /* TME_STP22XX_BUS_TRANSITION */
119: (*slave_conn_bus_other->tme_bus_tlb_fill)
120: (slave_conn_bus_other,
121: tlb,
122: address,
123: TME_BUS_CYCLE_WRITE);
124: #if TME_STP22XX_BUS_TRANSITION
125: assert (rc == TME_OK);
126: #endif /* TME_STP22XX_BUS_TRANSITION */
127:
128: /* reenter: */
129: stp222x = tme_stp222x_enter_bus(slave_conn_bus);
130:
131: /* unbusy the UPA connection: */
132: tme_stp222x_slave_unbusy(stp222x);
133:
134: return (TRUE);
135: }
136:
137: /* the flushsync TLB must allow fast writing of the entire block: */
138: memory = tlb->tme_bus_tlb_emulator_off_write;
139: assert (memory != TME_EMULATOR_OFF_UNDEF
140: && ((address
141: + (TME_STP222X_IS_2220(stp222x)
142: ? TME_STP2220_STC_FLUSHSYNC_SIZE
143: : TME_STP2222_STC_FLUSHSYNC_SIZE)
144: - 1)
145: <= (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_last));
146:
147: /* write the flush doublewords: */
148: memory += address;
149:
150: /* if this is an stp2220: */
151: if (TME_STP222X_IS_2220(stp222x)) {
152:
153: /* the stp2220 only writes four bytes: */
154: tme_memory_atomic_write32(((tme_shared tme_uint32_t *) memory) + 0,
155: tme_htobe_u32(1),
156: tlb->tme_bus_tlb_rwlock,
157: sizeof(tme_uint32_t));
158: }
159:
160: /* otherwise, this is an stp2222: */
161: else {
162:
163: /* the stp2222 writes 64 bytes: */
164:
165: /* XXX FIXME - all of these doublewords are actually written as
166: one atomic transaction. the best we can do is either 64- or
167: 128-bit atomic writes: */
168: #ifdef tme_memory_atomic_write128
169: tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 0,
170: tme_htobe_u128(((tme_uint128_t) 1) << (128 - 32)),
171: tlb->tme_bus_tlb_rwlock,
172: sizeof(tme_uint128_t));
173: tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 1,
174: 0,
175: tlb->tme_bus_tlb_rwlock,
176: sizeof(tme_uint128_t));
177: tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 2,
178: 0,
179: tlb->tme_bus_tlb_rwlock,
180: sizeof(tme_uint128_t));
181: tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 3,
182: 0,
183: tlb->tme_bus_tlb_rwlock,
184: sizeof(tme_uint128_t));
185: #else /* !tme_memory_atomic_write128 */
186: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 0,
187: tme_htobe_u64(((tme_uint64_t) 1) << (64 - 32)),
188: tlb->tme_bus_tlb_rwlock,
189: sizeof(tme_uint64_t));
190: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 1,
191: 0,
192: tlb->tme_bus_tlb_rwlock,
193: sizeof(tme_uint64_t));
194: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 2,
195: 0,
196: tlb->tme_bus_tlb_rwlock,
197: sizeof(tme_uint64_t));
198: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 3,
199: 0,
200: tlb->tme_bus_tlb_rwlock,
201: sizeof(tme_uint64_t));
202: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 4,
203: 0,
204: tlb->tme_bus_tlb_rwlock,
205: sizeof(tme_uint64_t));
206: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 5,
207: 0,
208: tlb->tme_bus_tlb_rwlock,
209: sizeof(tme_uint64_t));
210: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 6,
211: 0,
212: tlb->tme_bus_tlb_rwlock,
213: sizeof(tme_uint64_t));
214: tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 7,
215: 0,
216: tlb->tme_bus_tlb_rwlock,
217: sizeof(tme_uint64_t));
218: #endif /* !tme_memory_atomic_write128 */
219: }
220:
221: /* unbusy the flushsync TLB: */
222: tme_bus_tlb_unbusy(tlb);
223:
224: /* the flush has been done: */
225: stc->tme_stp222x_stc_pgflush = FALSE;
226:
227: return (TRUE);
228: }
229:
230: /* the STC register handler: */
231: void
232: tme_stp222x_stc_regs(struct tme_stp222x *stp222x,
233: unsigned long stc_i,
234: struct tme_stp222x_reg *reg)
235: {
236: struct tme_stp222x_stc *stc;
237: tme_uint32_t reggroup_index;
238: const char *name;
239:
240: /* get the streaming cache: */
241: stc = &stp222x->tme_stp222x_stcs[stc_i];
242:
243: /* get the register: */
244: reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
245:
246: /* if this is a write: */
247: if (reg->tme_stp222x_reg_write) {
248:
249: /* dispatch on the register: */
250: switch (reggroup_index) {
251:
252: case TME_STP222X_STC_REGGROUP_INDEX_CR:
253: stc->tme_stp222x_stc_cr
254: = (reg->tme_stp222x_reg_value
255: & (TME_STP222X_STC_CR_LPTR
256: | TME_STP222X_STC_CR_LE
257: | TME_STP222X_STC_CR_RR_DIS
258: | TME_STP222X_STC_CR_DE
259: | TME_STP222X_STC_CR_SB_EN));
260: name = "CR";
261: break;
262:
263: case TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH:
264: name = "PGFLUSH";
265: break;
266:
267: case TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC:
268: stc->tme_stp222x_stc_flushsync = reg->tme_stp222x_reg_value;
269: stc->tme_stp222x_stc_pgflush = TRUE;
270: name = "FLUSHSYNC";
271: break;
272:
273: default:
274: return;
275: }
276: }
277:
278: /* otherwise, this is a read: */
279: else {
280:
281: /* dispatch on the register: */
282: switch (reggroup_index) {
283: case TME_STP222X_STC_REGGROUP_INDEX_CR:
284: reg->tme_stp222x_reg_value = stc->tme_stp222x_stc_cr;
285: name = "CR";
286: break;
287: case TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH:
288: case TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC:
289: reg->tme_stp222x_reg_completed = TRUE;
290: return;
291: default:
292: return;
293: }
294: }
295:
296: tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
297: (TME_STP222X_LOG_HANDLE(stp222x),
298: _("STC%lu %s %s 0x%" TME_PRIx64),
299: stc_i,
300: name,
301: (reg->tme_stp222x_reg_write
302: ? "<-"
303: : "->"),
304: reg->tme_stp222x_reg_value));
305:
306: /* this register access has been completed: */
307: reg->tme_stp222x_reg_completed = TRUE;
308: }
309:
310: /* the STC diagnostic register handler: */
311: void
312: tme_stp222x_stc_regs_diag(struct tme_stp222x *stp222x,
313: unsigned long stc_i,
314: struct tme_stp222x_reg *reg)
315: {
316: struct tme_stp222x_stc *stc;
317: tme_uint32_t reggroup_0_3;
318: tme_uint32_t reggroup_index;
319:
320: /* get the streaming cache: */
321: stc = &stp222x->tme_stp222x_stcs[stc_i];
322:
323: /* get the register: */
324: reggroup_0_3 = TME_STP222X_REGGROUP_WHICH(reg->tme_stp222x_reg_address) & 0xf;
325: reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
326:
327: /* if this is a write: */
328: if (reg->tme_stp222x_reg_write) {
329:
330: abort();
331: }
332:
333: /* otherwise, this is a read: */
334: else {
335:
336: switch (reggroup_0_3) {
337: case 0x8: /* STP2220 0x58, STP2222 0xb4 or 0xc4 */
338: if (__tme_predict_false(reggroup_index >= TME_STP222X_STC_ENTRY_COUNT)) {
339: abort();
340: }
341: reg->tme_stp222x_reg_value = 0;
342: break;
343: default:
344: abort();
345: }
346: }
347:
348: /* this register access has been completed: */
349: reg->tme_stp222x_reg_completed = TRUE;
350: }
351:
352: /* this initializes a streaming cache: */
353: void
354: tme_stp222x_stc_init(struct tme_stp222x_stc *stc)
355: {
356:
357: /* initialize the flushsync TLB: */
358: tme_token_init(&stc->tme_stp222x_stc_flushsync_tlb_token);
359: stc->tme_stp222x_stc_flushsync_tlb.tme_bus_tlb_token = &stc->tme_stp222x_stc_flushsync_tlb_token;
360: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.