1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h>
29
30 #include <fcode/private.h>
31 #include <fcode/log.h>
32
33 #include <fcdriver/fcdriver.h>
34
35 #include <sys/opl_cfg.h>
36
37 /* VA for HardWare Descriptor */
38 static hwd_cmu_chan_t hwd_va_cmu;
39 static hwd_leaf_t hwd_va_pci;
40
41 /* Macro to get I/O portid */
42 #define DO_GET_IO_PORTID(env, lo, hi, portid) \
43 PUSH(DS, lo); \
44 PUSH(DS, hi); \
45 do_get_io_portid(env); \
46 portid = (uint32_t)POP(DS)
47
48 fstack_t
mem_map_in(fcode_env_t * env,fstack_t hi,fstack_t lo,fstack_t len)49 mem_map_in(fcode_env_t *env, fstack_t hi, fstack_t lo, fstack_t len)
50 {
51 private_data_t *pdp = DEVICE_PRIVATE(env);
52 fc_cell_t virt;
53 fstack_t mcookie = 0;
54 char *service = "map-in";
55 int error;
56 int offset = 0;
57
58 /*
59 * The calculation of the offset, lo and len are left here
60 * due to historical precedence.
61 */
62
63 offset = lo & PAGEOFFSET;
64 lo &= PAGEMASK;
65 len = (len + offset + PAGEOFFSET) & PAGEMASK;
66
67 error = fc_run_priv(pdp->common, service, 3, 1, fc_size2cell(len),
68 fc_uint32_t2cell(hi), fc_uint32_t2cell(lo), &virt);
69
70 if (error)
71 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
72
73 mcookie = mapping_to_mcookie(virt, len, 0, 0);
74
75 if (mcookie == 0)
76 throw_from_fclib(env, 1,
77 "jupiter:%s: mapping_to_mcookie failed\n", service);
78
79 mcookie += offset;
80
81 debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %llx -> %x\n", service,
82 (long long)virt, (uint32_t)mcookie);
83
84 return (mcookie);
85 }
86
87 static void
mem_map_out(fcode_env_t * env,fstack_t mcookie,fstack_t len)88 mem_map_out(fcode_env_t *env, fstack_t mcookie, fstack_t len)
89 {
90 private_data_t *pdp = DEVICE_PRIVATE(env);
91 fc_cell_t virt;
92 char *service = "map-out";
93 int error;
94 int offset;
95
96 /*
97 * The calculation of the offset, lo and len are left here
98 * due to historical precedence.
99 */
100
101 offset = mcookie & PAGEOFFSET;
102 mcookie &= PAGEMASK;
103 len = (len + offset + PAGEOFFSET) & PAGEMASK;
104
105 if (!is_mcookie(mcookie)) {
106 log_message(MSG_ERROR, "jupiter:%s: %x not an mcookie!\n",
107 service, (int)mcookie);
108 virt = mcookie;
109 } else {
110 virt = mcookie_to_addr(mcookie);
111 debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %x -> %llx\n",
112 service, (int)mcookie, (long long)virt);
113 delete_mapping(mcookie);
114 }
115
116 error = fc_run_priv(pdp->common, service, 2, 0,
117 fc_size2cell(len), virt);
118 if (error)
119 log_message(MSG_ERROR, "jupiter:%s: failed\n", service);
120 }
121
122 static void
do_map_in(fcode_env_t * env)123 do_map_in(fcode_env_t *env)
124 {
125 fstack_t phi, plo, len, addr;
126
127 CHECK_DEPTH(env, 3, "jupiter:map-in");
128 len = POP(DS);
129 phi = POP(DS);
130 plo = POP(DS);
131 addr = mem_map_in(env, phi, plo, len);
132 PUSH(DS, addr);
133 }
134
135 static void
do_map_out(fcode_env_t * env)136 do_map_out(fcode_env_t *env)
137 {
138 fstack_t addr, len;
139
140 CHECK_DEPTH(env, 2, "jupiter:map-out");
141 len = POP(DS);
142 addr = POP(DS);
143 mem_map_out(env, addr, len);
144 }
145
146 static void
do_get_io_portid(fcode_env_t * env)147 do_get_io_portid(fcode_env_t *env)
148 {
149 fstack_t phi, plo;
150 unsigned int portid, lsb, ch, leaf;
151
152 CHECK_DEPTH(env, 2, "jupiter:get-portid");
153
154 phi = POP(DS);
155 plo = POP(DS);
156
157 lsb = OPL_ADDR_TO_LSB(phi);
158 ch = OPL_ADDR_TO_CHANNEL(phi);
159 leaf = OPL_ADDR_TO_LEAF(phi, plo);
160
161 portid = OPL_IO_PORTID(lsb, ch, leaf);
162
163 debug_msg(DEBUG_REG_ACCESS, "jupiter:get-portid ( %x %x ) -> %x\n",
164 (int)phi, (int)plo, (int)portid);
165 PUSH(DS, portid);
166 }
167
168 static void
do_encode_unit(fcode_env_t * env)169 do_encode_unit(fcode_env_t *env)
170 {
171 char enc_buf[64];
172 fstack_t hi, lo;
173 uint32_t id;
174 long long off;
175
176 CHECK_DEPTH(env, 2, "jupiter:encode-unit");
177
178 hi = POP(DS);
179 lo = POP(DS);
180 off = (long long)(((hi & 0x1F) << 32) | lo);
181
182 /* Convert physical address to portid */
183 DO_GET_IO_PORTID(env, lo, hi, id);
184
185 if (off) {
186 (void) sprintf(enc_buf, "%x,%llx", id, off);
187 } else {
188 (void) sprintf(enc_buf, "%x", id);
189 }
190
191 debug_msg(DEBUG_REG_ACCESS, "jupiter:encode_unit ( %x %x ) -> '%s'\n",
192 (uint32_t)hi, (uint32_t)lo, enc_buf);
193
194 push_a_string(env, STRDUP(enc_buf));
195 }
196
197 static void
do_decode_unit(fcode_env_t * env)198 do_decode_unit(fcode_env_t *env)
199 {
200 uint32_t hi;
201 long long lo;
202 unsigned int portid, lsb, ch;
203 char *buf;
204
205 CHECK_DEPTH(env, 2, "jupiter:decode-unit");
206
207 buf = pop_a_string(env, NULL);
208 if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) {
209 if (sscanf(buf, "%x", &portid) != 1) {
210 throw_from_fclib(env, 1, "jupiter:decode_unit:%s",
211 buf);
212 }
213 lo = 0;
214 }
215
216 lsb = OPL_IO_PORTID_TO_LSB(portid);
217 ch = OPL_PORTID_TO_CHANNEL(portid);
218 hi = OPL_ADDR_HI(lsb, ch);
219
220 debug_msg(DEBUG_REG_ACCESS,
221 "jupiter:decode_unit ( '%s' ) -> %x %llx\n", buf, hi, lo);
222
223 PUSH(DS, (fstack_t)lo);
224 PUSH(DS, (fstack_t)hi);
225 }
226
227 static void
do_device_id(fcode_env_t * env)228 do_device_id(fcode_env_t *env)
229 {
230 common_data_t *cdp = COMMON_PRIVATE(env);
231 char *buf = NULL;
232 uint32_t hi;
233 long long lo;
234 uint32_t portid, ch, leaf;
235
236 CHECK_DEPTH(env, 2, "jupiter:device-id");
237
238 hi = POP(DS);
239 lo = POP(DS);
240
241 portid = 0;
242 if (cdp != NULL && *cdp->fc.unit_address != '\0' &&
243 ((buf = strdup(cdp->fc.unit_address)) != NULL)) {
244 /*
245 * Get portid number from unit_address
246 * Because of no leaf information in physical address
247 */
248 if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) {
249 if (sscanf(buf, "%x", &portid) != 1) {
250 throw_from_fclib(env, 1,
251 "jupiter:do_device_id: invalid %s", buf);
252 }
253 }
254 } else {
255 /*
256 * Non existence unit_address case.
257 * Convert physical address to portid.
258 */
259 throw_from_fclib(env, 1,
260 "jupiter:do_device_id: failed unit address");
261 DO_GET_IO_PORTID(env, lo, hi, portid);
262 }
263
264 debug_msg(DEBUG_FIND_FCODE,
265 "jupiter:do_device_id:(%x,%llx)\n", portid, lo);
266
267 /* Pick up each ID from portid */
268 ch = OPL_PORTID_TO_CHANNEL(portid);
269 leaf = OPL_PORTID_TO_LEAF(portid);
270
271 if (ch == OPL_CMU_CHANNEL) {
272 /*
273 * CMU-CH: PCICMU CHANNEL
274 */
275 debug_msg(DEBUG_FIND_FCODE,
276 "jupiter:do_device_id:cmu-ch\n");
277 push_a_string(env, "cmu-ch");
278 } else if (OPL_OBERON_CHANNEL(ch) && OPL_VALID_LEAF(leaf)) {
279 /*
280 * PCI-CH: Oberon Leaves CHANNEL
281 */
282 if (leaf) {
283 /* Leaf B */
284 debug_msg(DEBUG_FIND_FCODE,
285 "jupiter:do_device_id:jup-oberon-pci1\n");
286 push_a_string(env, "jup-oberon-pci1");
287 } else {
288 /* Leaf A */
289 debug_msg(DEBUG_FIND_FCODE,
290 "jupiter:do_device_id:jup-oberon-pci0\n");
291 push_a_string(env, "jup-oberon-pci0");
292 }
293 } else {
294 /* Not matched to any channels */
295 throw_from_fclib(env, 1,
296 "jupiter:do_device_id: invalid portid %x", portid);
297 push_a_string(env, "");
298 }
299
300 /* Free the duplicated buf */
301 if (buf != NULL)
302 free(buf);
303 }
304
305 static void
do_get_hwd_va(fcode_env_t * env)306 do_get_hwd_va(fcode_env_t *env)
307 {
308 private_data_t *pdp = DEVICE_PRIVATE(env);
309 char *service = "get-hwd-va";
310 char *buf;
311 uint32_t portid = 0;
312 int ch;
313 int error;
314 fc_cell_t status;
315 void *hwd_va;
316
317 CHECK_DEPTH(env, 2, "jupiter:get-hwd-va");
318
319 /* Get a portid with string format */
320 buf = pop_a_string(env, NULL);
321
322 /* Convert to the integer from the string */
323 if (sscanf(buf, "%x", &portid) != 1) {
324 throw_from_fclib(env, 1, "jupiter:%s: invalid portid",
325 service);
326 }
327
328 ch = OPL_PORTID_TO_CHANNEL(portid);
329 if (!OPL_VALID_CHANNEL(ch)) {
330 throw_from_fclib(env, 1, "jupiter:%s: invalid poritd",
331 service);
332 hwd_va = 0;
333 goto out;
334 }
335
336 if (ch == OPL_CMU_CHANNEL) {
337 hwd_va = (void *)&hwd_va_cmu;
338 } else {
339 hwd_va = (void *)&hwd_va_pci;
340 }
341
342 /*
343 * Get the virtual address of hwd specified with portid.
344 */
345 error = fc_run_priv(pdp->common, service, 2, 1,
346 fc_uint32_t2cell(portid), fc_ptr2cell(hwd_va), &status);
347
348 if (error || !status)
349 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
350
351 out:
352 PUSH(DS, (fstack_t)hwd_va);
353 }
354
355 static void
do_get_intrp_name(fcode_env_t * env)356 do_get_intrp_name(fcode_env_t *env)
357 {
358 /*
359 * Just pass the "eFCode" string.
360 */
361
362 debug_msg(DEBUG_FIND_FCODE,
363 "jupiter: do_get_intrp_name: eFCode\n");
364
365 push_a_string(env, "eFCode");
366 }
367
368 static void
do_master_interrupt(fcode_env_t * env)369 do_master_interrupt(fcode_env_t *env)
370 {
371 private_data_t *pdp = DEVICE_PRIVATE(env);
372 char *service = "master-interrupt";
373 int portid;
374 token_t xt;
375 int error;
376 fc_cell_t status;
377
378 CHECK_DEPTH(env, 2, "jupiter:master-interrupt");
379 portid = POP(DS);
380 xt = POP(DS);
381
382 /*
383 * Install the master interrupt handler for this port id.
384 */
385 error = fc_run_priv(pdp->common, service, 2, 1,
386 fc_uint32_t2cell(portid), fc_uint32_t2cell(xt), &status);
387
388 if (error || !status)
389 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
390
391 PUSH(DS, FALSE);
392
393 debug_msg(DEBUG_REG_ACCESS,
394 "jupiter:master-interrupt ( %x %x ) -> %x\n",
395 portid, xt, (int)FALSE);
396 }
397
398 static void
do_register_vector_entry(fcode_env_t * env)399 do_register_vector_entry(fcode_env_t *env)
400 {
401 int ign, ino, level;
402
403 CHECK_DEPTH(env, 3, "jupiter:register-vector-entry");
404 ign = POP(DS);
405 ino = POP(DS);
406 level = POP(DS);
407
408 PUSH(DS, FALSE);
409 debug_msg(DEBUG_REG_ACCESS,
410 "jupiter:register-vector-entry ( %x %x %x ) -> %x\n",
411 ign, ino, level, (int)FALSE);
412 }
413
414 static void
do_get_interrupt_target(fcode_env_t * env)415 do_get_interrupt_target(fcode_env_t *env)
416 {
417 int mid = -1;
418
419 PUSH(DS, mid);
420 debug_msg(DEBUG_REG_ACCESS,
421 "jupiter:get-interrupt-target ( ) -> %x\n", mid);
422 }
423
424
425 #pragma init(_init)
426
427 static void
_init(void)428 _init(void)
429 {
430 fcode_env_t *env = initial_env;
431
432 ASSERT(env);
433 ASSERT(env->current_device);
434 NOTICE;
435
436 create_int_prop(env, "#address-cells", 2);
437
438 FORTH(0, "map-in", do_map_in);
439 FORTH(0, "map-out", do_map_out);
440 FORTH(0, "get-portid", do_get_io_portid);
441 FORTH(0, "decode-unit", do_decode_unit);
442 FORTH(0, "encode-unit", do_encode_unit);
443 FORTH(0, "device-id", do_device_id);
444 FORTH(0, "get-hwd-va", do_get_hwd_va);
445 FORTH(0, "get-fcinterp-name", do_get_intrp_name);
446 FORTH(0, "master-interrupt", do_master_interrupt);
447 FORTH(0, "register-vector-entry", do_register_vector_entry);
448 FORTH(0, "get-interrupt-target", do_get_interrupt_target);
449 }
450