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
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
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
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
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
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
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
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
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
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
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
371 do_master_interrupt(fcode_env_t *env)
372 {
373 	int	portid;
374 	token_t	xt;
375 
376 	CHECK_DEPTH(env, 2, "jupiter:master-interrput");
377 	portid	= POP(DS);
378 	xt	= POP(DS);
379 
380 	PUSH(DS, FALSE);
381 	debug_msg(DEBUG_REG_ACCESS,
382 	    "jupiter:master-interrupt ( %x %x ) -> %x\n",
383 	    portid, xt, (int)FALSE);
384 }
385 
386 static void
387 do_register_vector_entry(fcode_env_t *env)
388 {
389 	int	ign, ino, level;
390 
391 	CHECK_DEPTH(env, 3, "jupiter:register-vector-entry");
392 	ign   = POP(DS);
393 	ino   = POP(DS);
394 	level = POP(DS);
395 
396 	PUSH(DS, FALSE);
397 	debug_msg(DEBUG_REG_ACCESS,
398 	    "jupiter:register-vector-entry ( %x %x %x ) -> %x\n",
399 	    ign, ino, level, (int)FALSE);
400 }
401 
402 static void
403 do_get_interrupt_target(fcode_env_t *env)
404 {
405 	int	mid = -1;
406 
407 	PUSH(DS, mid);
408 	debug_msg(DEBUG_REG_ACCESS,
409 		"jupiter:get-interrupt-target ( ) -> %x\n", mid);
410 }
411 
412 
413 #pragma init(_init)
414 
415 static void
416 _init(void)
417 {
418 	fcode_env_t *env = initial_env;
419 
420 	ASSERT(env);
421 	ASSERT(env->current_device);
422 	NOTICE;
423 
424 	create_int_prop(env, "#address-cells", 2);
425 
426 	FORTH(0,	"map-in",		do_map_in);
427 	FORTH(0,	"map-out",		do_map_out);
428 	FORTH(0,	"get-portid",		do_get_io_portid);
429 	FORTH(0,	"decode-unit",		do_decode_unit);
430 	FORTH(0,	"encode-unit",		do_encode_unit);
431 	FORTH(0,	"device-id",		do_device_id);
432 	FORTH(0,	"get-hwd-va",		do_get_hwd_va);
433 	FORTH(0,	"get-fcinterp-name",	do_get_intrp_name);
434 	FORTH(0,	"master-interrupt",	do_master_interrupt);
435 	FORTH(0,	"register-vector-entry", do_register_vector_entry);
436 	FORTH(0,	"get-interrupt-target",	do_get_interrupt_target);
437 }
438