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