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