11772Sjl139090 /*
21772Sjl139090 * CDDL HEADER START
31772Sjl139090 *
41772Sjl139090 * The contents of this file are subject to the terms of the
51772Sjl139090 * Common Development and Distribution License (the "License").
61772Sjl139090 * You may not use this file except in compliance with the License.
71772Sjl139090 *
81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090 * or http://www.opensolaris.org/os/licensing.
101772Sjl139090 * See the License for the specific language governing permissions
111772Sjl139090 * and limitations under the License.
121772Sjl139090 *
131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090 *
191772Sjl139090 * CDDL HEADER END
201772Sjl139090 */
211772Sjl139090 /*
221772Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
231772Sjl139090 * Use is subject to license terms.
241772Sjl139090 */
251772Sjl139090
261772Sjl139090 #pragma ident "%Z%%M% %I% %E% SMI"
271772Sjl139090
281772Sjl139090 #include <stdio.h>
291772Sjl139090 #include <stdlib.h>
301772Sjl139090 #include <strings.h>
311772Sjl139090
321772Sjl139090 #include <fcode/private.h>
331772Sjl139090 #include <fcode/log.h>
341772Sjl139090
351772Sjl139090 #include <fcdriver/fcdriver.h>
361772Sjl139090
371772Sjl139090 #include <sys/opl_cfg.h>
381772Sjl139090
391772Sjl139090 /* VA for HardWare Descriptor */
401772Sjl139090 static hwd_cmu_chan_t hwd_va_cmu;
411772Sjl139090 static hwd_leaf_t hwd_va_pci;
421772Sjl139090
431772Sjl139090 /* Macro to get I/O portid */
441772Sjl139090 #define DO_GET_IO_PORTID(env, lo, hi, portid) \
451772Sjl139090 PUSH(DS, lo); \
461772Sjl139090 PUSH(DS, hi); \
471772Sjl139090 do_get_io_portid(env); \
481772Sjl139090 portid = (uint32_t)POP(DS)
491772Sjl139090
501772Sjl139090 fstack_t
mem_map_in(fcode_env_t * env,fstack_t hi,fstack_t lo,fstack_t len)511772Sjl139090 mem_map_in(fcode_env_t *env, fstack_t hi, fstack_t lo, fstack_t len)
521772Sjl139090 {
531772Sjl139090 private_data_t *pdp = DEVICE_PRIVATE(env);
541772Sjl139090 fc_cell_t virt;
551772Sjl139090 fstack_t mcookie = NULL;
561772Sjl139090 char *service = "map-in";
571772Sjl139090 int error;
581772Sjl139090 int offset = 0;
591772Sjl139090
601772Sjl139090 /*
611772Sjl139090 * The calculation of the offset, lo and len are left here
621772Sjl139090 * due to historical precedence.
631772Sjl139090 */
641772Sjl139090
651772Sjl139090 offset = lo & PAGEOFFSET;
661772Sjl139090 lo &= PAGEMASK;
671772Sjl139090 len = (len + offset + PAGEOFFSET) & PAGEMASK;
681772Sjl139090
691772Sjl139090 error = fc_run_priv(pdp->common, service, 3, 1, fc_size2cell(len),
701772Sjl139090 fc_uint32_t2cell(hi), fc_uint32_t2cell(lo), &virt);
711772Sjl139090
721772Sjl139090 if (error)
731772Sjl139090 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
741772Sjl139090
751772Sjl139090 mcookie = mapping_to_mcookie(virt, len, NULL, NULL);
761772Sjl139090
771772Sjl139090 if (mcookie == NULL)
781772Sjl139090 throw_from_fclib(env, 1,
791772Sjl139090 "jupiter:%s: mapping_to_mcookie failed\n", service);
801772Sjl139090
811772Sjl139090 mcookie += offset;
821772Sjl139090
831772Sjl139090 debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %llx -> %x\n", service,
841772Sjl139090 (long long)virt, (uint32_t)mcookie);
851772Sjl139090
861772Sjl139090 return (mcookie);
871772Sjl139090 }
881772Sjl139090
891772Sjl139090 static void
mem_map_out(fcode_env_t * env,fstack_t mcookie,fstack_t len)901772Sjl139090 mem_map_out(fcode_env_t *env, fstack_t mcookie, fstack_t len)
911772Sjl139090 {
921772Sjl139090 private_data_t *pdp = DEVICE_PRIVATE(env);
931772Sjl139090 fc_cell_t virt;
941772Sjl139090 char *service = "map-out";
951772Sjl139090 int error;
961772Sjl139090 int offset;
971772Sjl139090
981772Sjl139090 /*
991772Sjl139090 * The calculation of the offset, lo and len are left here
1001772Sjl139090 * due to historical precedence.
1011772Sjl139090 */
1021772Sjl139090
1031772Sjl139090 offset = mcookie & PAGEOFFSET;
1041772Sjl139090 mcookie &= PAGEMASK;
1051772Sjl139090 len = (len + offset + PAGEOFFSET) & PAGEMASK;
1061772Sjl139090
1071772Sjl139090 if (!is_mcookie(mcookie)) {
1081772Sjl139090 log_message(MSG_ERROR, "jupiter:%s: %x not an mcookie!\n",
1091772Sjl139090 service, (int)mcookie);
1101772Sjl139090 virt = mcookie;
1111772Sjl139090 } else {
1121772Sjl139090 virt = mcookie_to_addr(mcookie);
1131772Sjl139090 debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %x -> %llx\n",
1141772Sjl139090 service, (int)mcookie, (long long)virt);
1151772Sjl139090 delete_mapping(mcookie);
1161772Sjl139090 }
1171772Sjl139090
1181772Sjl139090 error = fc_run_priv(pdp->common, service, 2, 0,
1191772Sjl139090 fc_size2cell(len), virt);
1201772Sjl139090 if (error)
1211772Sjl139090 log_message(MSG_ERROR, "jupiter:%s: failed\n", service);
1221772Sjl139090 }
1231772Sjl139090
1241772Sjl139090 static void
do_map_in(fcode_env_t * env)1251772Sjl139090 do_map_in(fcode_env_t *env)
1261772Sjl139090 {
1271772Sjl139090 fstack_t phi, plo, len, addr;
1281772Sjl139090
1291772Sjl139090 CHECK_DEPTH(env, 3, "jupiter:map-in");
1301772Sjl139090 len = POP(DS);
1311772Sjl139090 phi = POP(DS);
1321772Sjl139090 plo = POP(DS);
1331772Sjl139090 addr = mem_map_in(env, phi, plo, len);
1341772Sjl139090 PUSH(DS, addr);
1351772Sjl139090 }
1361772Sjl139090
1371772Sjl139090 static void
do_map_out(fcode_env_t * env)1381772Sjl139090 do_map_out(fcode_env_t *env)
1391772Sjl139090 {
1401772Sjl139090 fstack_t addr, len;
1411772Sjl139090
1421772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:map-out");
1431772Sjl139090 len = POP(DS);
1441772Sjl139090 addr = POP(DS);
1451772Sjl139090 mem_map_out(env, addr, len);
1461772Sjl139090 }
1471772Sjl139090
1481772Sjl139090 static void
do_get_io_portid(fcode_env_t * env)1491772Sjl139090 do_get_io_portid(fcode_env_t *env)
1501772Sjl139090 {
1511772Sjl139090 fstack_t phi, plo;
1521772Sjl139090 unsigned int portid, lsb, ch, leaf;
1531772Sjl139090
1541772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:get-portid");
1551772Sjl139090
1561772Sjl139090 phi = POP(DS);
1571772Sjl139090 plo = POP(DS);
1581772Sjl139090
1591772Sjl139090 lsb = OPL_ADDR_TO_LSB(phi);
1601772Sjl139090 ch = OPL_ADDR_TO_CHANNEL(phi);
1611772Sjl139090 leaf = OPL_ADDR_TO_LEAF(phi, plo);
1621772Sjl139090
1631772Sjl139090 portid = OPL_IO_PORTID(lsb, ch, leaf);
1641772Sjl139090
1651772Sjl139090 debug_msg(DEBUG_REG_ACCESS, "jupiter:get-portid ( %x %x ) -> %x\n",
1661772Sjl139090 (int)phi, (int)plo, (int)portid);
1671772Sjl139090 PUSH(DS, portid);
1681772Sjl139090 }
1691772Sjl139090
1701772Sjl139090 static void
do_encode_unit(fcode_env_t * env)1711772Sjl139090 do_encode_unit(fcode_env_t *env)
1721772Sjl139090 {
1731772Sjl139090 char enc_buf[64];
1741772Sjl139090 fstack_t hi, lo;
1751772Sjl139090 uint32_t id;
1761772Sjl139090 long long off;
1771772Sjl139090
1781772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:encode-unit");
1791772Sjl139090
1801772Sjl139090 hi = POP(DS);
1811772Sjl139090 lo = POP(DS);
1821772Sjl139090 off = (long long)(((hi & 0x1F) << 32) | lo);
1831772Sjl139090
1841772Sjl139090 /* Convert physical address to portid */
1851772Sjl139090 DO_GET_IO_PORTID(env, lo, hi, id);
1861772Sjl139090
1871772Sjl139090 if (off) {
1881772Sjl139090 (void) sprintf(enc_buf, "%x,%llx", id, off);
1891772Sjl139090 } else {
1901772Sjl139090 (void) sprintf(enc_buf, "%x", id);
1911772Sjl139090 }
1921772Sjl139090
1931772Sjl139090 debug_msg(DEBUG_REG_ACCESS, "jupiter:encode_unit ( %x %x ) -> '%s'\n",
1941772Sjl139090 (uint32_t)hi, (uint32_t)lo, enc_buf);
1951772Sjl139090
1961772Sjl139090 push_a_string(env, STRDUP(enc_buf));
1971772Sjl139090 }
1981772Sjl139090
1991772Sjl139090 static void
do_decode_unit(fcode_env_t * env)2001772Sjl139090 do_decode_unit(fcode_env_t *env)
2011772Sjl139090 {
2021772Sjl139090 uint32_t hi;
2031772Sjl139090 long long lo;
2041772Sjl139090 unsigned int portid, lsb, ch;
2051772Sjl139090 char *buf;
2061772Sjl139090
2071772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:decode-unit");
2081772Sjl139090
2091772Sjl139090 buf = pop_a_string(env, NULL);
2101772Sjl139090 if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) {
2111772Sjl139090 if (sscanf(buf, "%x", &portid) != 1) {
2121772Sjl139090 throw_from_fclib(env, 1, "jupiter:decode_unit:%s",
2131772Sjl139090 buf);
2141772Sjl139090 }
2151772Sjl139090 lo = 0;
2161772Sjl139090 }
2171772Sjl139090
2181772Sjl139090 lsb = OPL_IO_PORTID_TO_LSB(portid);
2191772Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid);
2201772Sjl139090 hi = OPL_ADDR_HI(lsb, ch);
2211772Sjl139090
2221772Sjl139090 debug_msg(DEBUG_REG_ACCESS,
2231772Sjl139090 "jupiter:decode_unit ( '%s' ) -> %x %llx\n", buf, hi, lo);
2241772Sjl139090
2251772Sjl139090 PUSH(DS, (fstack_t)lo);
2261772Sjl139090 PUSH(DS, (fstack_t)hi);
2271772Sjl139090 }
2281772Sjl139090
2291772Sjl139090 static void
do_device_id(fcode_env_t * env)2301772Sjl139090 do_device_id(fcode_env_t *env)
2311772Sjl139090 {
2321772Sjl139090 common_data_t *cdp = COMMON_PRIVATE(env);
2331772Sjl139090 char *buf = NULL;
2341772Sjl139090 uint32_t hi;
2351772Sjl139090 long long lo;
2361772Sjl139090 uint32_t portid, ch, leaf;
2371772Sjl139090
2381772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:device-id");
2391772Sjl139090
2401772Sjl139090 hi = POP(DS);
2411772Sjl139090 lo = POP(DS);
2421772Sjl139090
2431772Sjl139090 portid = 0;
2441772Sjl139090 if (cdp && cdp->fc.unit_address &&
2451772Sjl139090 ((buf = strdup(cdp->fc.unit_address)) != NULL)) {
2461772Sjl139090 /*
2471772Sjl139090 * Get portid number from unit_address
2481772Sjl139090 * Because of no leaf information in physical address
2491772Sjl139090 */
2501772Sjl139090 if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) {
2511772Sjl139090 if (sscanf(buf, "%x", &portid) != 1) {
2521772Sjl139090 throw_from_fclib(env, 1,
2531772Sjl139090 "jupiter:do_device_id: invalid %s", buf);
2541772Sjl139090 }
2551772Sjl139090 }
2561772Sjl139090 } else {
2571772Sjl139090 /*
2581772Sjl139090 * Non existence unit_address case.
2591772Sjl139090 * Convert physical address to portid.
2601772Sjl139090 */
2611772Sjl139090 throw_from_fclib(env, 1,
2621772Sjl139090 "jupiter:do_device_id: failed unit address");
2631772Sjl139090 DO_GET_IO_PORTID(env, lo, hi, portid);
2641772Sjl139090 }
2651772Sjl139090
2661772Sjl139090 debug_msg(DEBUG_FIND_FCODE,
2671772Sjl139090 "jupiter:do_device_id:(%x,%llx)\n", portid, lo);
2681772Sjl139090
2691772Sjl139090 /* Pick up each ID from portid */
2701772Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid);
2711772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid);
2721772Sjl139090
2731772Sjl139090 if (ch == OPL_CMU_CHANNEL) {
2741772Sjl139090 /*
2751772Sjl139090 * CMU-CH: PCICMU CHANNEL
2761772Sjl139090 */
2771772Sjl139090 debug_msg(DEBUG_FIND_FCODE,
2781772Sjl139090 "jupiter:do_device_id:cmu-ch\n");
2791772Sjl139090 push_a_string(env, "cmu-ch");
2801772Sjl139090 } else if (OPL_OBERON_CHANNEL(ch) && OPL_VALID_LEAF(leaf)) {
2811772Sjl139090 /*
2821772Sjl139090 * PCI-CH: Oberon Leaves CHANNEL
2831772Sjl139090 */
2841772Sjl139090 if (leaf) {
2851772Sjl139090 /* Leaf B */
2861772Sjl139090 debug_msg(DEBUG_FIND_FCODE,
2871772Sjl139090 "jupiter:do_device_id:jup-oberon-pci1\n");
2881772Sjl139090 push_a_string(env, "jup-oberon-pci1");
2891772Sjl139090 } else {
2901772Sjl139090 /* Leaf A */
2911772Sjl139090 debug_msg(DEBUG_FIND_FCODE,
2921772Sjl139090 "jupiter:do_device_id:jup-oberon-pci0\n");
2931772Sjl139090 push_a_string(env, "jup-oberon-pci0");
2941772Sjl139090 }
2951772Sjl139090 } else {
2961772Sjl139090 /* Not matched to any channels */
2971772Sjl139090 throw_from_fclib(env, 1,
2981772Sjl139090 "jupiter:do_device_id: invalid portid %x", portid);
2991772Sjl139090 push_a_string(env, "");
3001772Sjl139090 }
3011772Sjl139090
3021772Sjl139090 /* Free the duplicated buf */
3031772Sjl139090 if (buf != NULL)
3041772Sjl139090 free(buf);
3051772Sjl139090 }
3061772Sjl139090
3071772Sjl139090 static void
do_get_hwd_va(fcode_env_t * env)3081772Sjl139090 do_get_hwd_va(fcode_env_t *env)
3091772Sjl139090 {
3101772Sjl139090 private_data_t *pdp = DEVICE_PRIVATE(env);
3111772Sjl139090 char *service = "get-hwd-va";
3121772Sjl139090 char *buf;
3131772Sjl139090 uint32_t portid = 0;
3141772Sjl139090 int ch;
3151772Sjl139090 int error;
3161772Sjl139090 fc_cell_t status;
3171772Sjl139090 void *hwd_va;
3181772Sjl139090
3191772Sjl139090 CHECK_DEPTH(env, 2, "jupiter:get-hwd-va");
3201772Sjl139090
3211772Sjl139090 /* Get a portid with string format */
3221772Sjl139090 buf = pop_a_string(env, NULL);
3231772Sjl139090
3241772Sjl139090 /* Convert to the integer from the string */
3251772Sjl139090 if (sscanf(buf, "%x", &portid) != 1) {
3261772Sjl139090 throw_from_fclib(env, 1, "jupiter:%s: invalid portid",
3271772Sjl139090 service);
3281772Sjl139090 }
3291772Sjl139090
3301772Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid);
3311772Sjl139090 if (!OPL_VALID_CHANNEL(ch)) {
3321772Sjl139090 throw_from_fclib(env, 1, "jupiter:%s: invalid poritd",
3331772Sjl139090 service);
3341772Sjl139090 hwd_va = 0;
3351772Sjl139090 goto out;
3361772Sjl139090 }
3371772Sjl139090
3381772Sjl139090 if (ch == OPL_CMU_CHANNEL) {
3391772Sjl139090 hwd_va = (void *)&hwd_va_cmu;
3401772Sjl139090 } else {
3411772Sjl139090 hwd_va = (void *)&hwd_va_pci;
3421772Sjl139090 }
3431772Sjl139090
3441772Sjl139090 /*
3451772Sjl139090 * Get the virtual address of hwd specified with portid.
3461772Sjl139090 */
3471772Sjl139090 error = fc_run_priv(pdp->common, service, 2, 1,
3481772Sjl139090 fc_uint32_t2cell(portid), fc_ptr2cell(hwd_va), &status);
3491772Sjl139090
3501772Sjl139090 if (error || !status)
3511772Sjl139090 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
3521772Sjl139090
3531772Sjl139090 out:
3541772Sjl139090 PUSH(DS, (fstack_t)hwd_va);
3551772Sjl139090 }
3561772Sjl139090
3571772Sjl139090 static void
do_get_intrp_name(fcode_env_t * env)3581772Sjl139090 do_get_intrp_name(fcode_env_t *env)
3591772Sjl139090 {
3601772Sjl139090 /*
3611772Sjl139090 * Just pass the "eFCode" string.
3621772Sjl139090 */
3631772Sjl139090
3641772Sjl139090 debug_msg(DEBUG_FIND_FCODE,
3651772Sjl139090 "jupiter: do_get_intrp_name: eFCode\n");
3661772Sjl139090
3671772Sjl139090 push_a_string(env, "eFCode");
3681772Sjl139090 }
3691772Sjl139090
3701772Sjl139090 static void
do_master_interrupt(fcode_env_t * env)3711772Sjl139090 do_master_interrupt(fcode_env_t *env)
3721772Sjl139090 {
373*1982Smv143129 private_data_t *pdp = DEVICE_PRIVATE(env);
374*1982Smv143129 char *service = "master-interrupt";
375*1982Smv143129 int portid;
376*1982Smv143129 token_t xt;
377*1982Smv143129 int error;
378*1982Smv143129 fc_cell_t status;
3791772Sjl139090
380*1982Smv143129 CHECK_DEPTH(env, 2, "jupiter:master-interrupt");
3811772Sjl139090 portid = POP(DS);
3821772Sjl139090 xt = POP(DS);
3831772Sjl139090
384*1982Smv143129 /*
385*1982Smv143129 * Install the master interrupt handler for this port id.
386*1982Smv143129 */
387*1982Smv143129 error = fc_run_priv(pdp->common, service, 2, 1,
388*1982Smv143129 fc_uint32_t2cell(portid), fc_uint32_t2cell(xt), &status);
389*1982Smv143129
390*1982Smv143129 if (error || !status)
391*1982Smv143129 throw_from_fclib(env, 1, "jupiter:%s: failed\n", service);
392*1982Smv143129
3931772Sjl139090 PUSH(DS, FALSE);
394*1982Smv143129
3951772Sjl139090 debug_msg(DEBUG_REG_ACCESS,
3961772Sjl139090 "jupiter:master-interrupt ( %x %x ) -> %x\n",
3971772Sjl139090 portid, xt, (int)FALSE);
3981772Sjl139090 }
3991772Sjl139090
4001772Sjl139090 static void
do_register_vector_entry(fcode_env_t * env)4011772Sjl139090 do_register_vector_entry(fcode_env_t *env)
4021772Sjl139090 {
4031772Sjl139090 int ign, ino, level;
4041772Sjl139090
4051772Sjl139090 CHECK_DEPTH(env, 3, "jupiter:register-vector-entry");
4061772Sjl139090 ign = POP(DS);
4071772Sjl139090 ino = POP(DS);
4081772Sjl139090 level = POP(DS);
4091772Sjl139090
4101772Sjl139090 PUSH(DS, FALSE);
4111772Sjl139090 debug_msg(DEBUG_REG_ACCESS,
4121772Sjl139090 "jupiter:register-vector-entry ( %x %x %x ) -> %x\n",
4131772Sjl139090 ign, ino, level, (int)FALSE);
4141772Sjl139090 }
4151772Sjl139090
4161772Sjl139090 static void
do_get_interrupt_target(fcode_env_t * env)4171772Sjl139090 do_get_interrupt_target(fcode_env_t *env)
4181772Sjl139090 {
4191772Sjl139090 int mid = -1;
4201772Sjl139090
4211772Sjl139090 PUSH(DS, mid);
4221772Sjl139090 debug_msg(DEBUG_REG_ACCESS,
4231772Sjl139090 "jupiter:get-interrupt-target ( ) -> %x\n", mid);
4241772Sjl139090 }
4251772Sjl139090
4261772Sjl139090
4271772Sjl139090 #pragma init(_init)
4281772Sjl139090
4291772Sjl139090 static void
_init(void)4301772Sjl139090 _init(void)
4311772Sjl139090 {
4321772Sjl139090 fcode_env_t *env = initial_env;
4331772Sjl139090
4341772Sjl139090 ASSERT(env);
4351772Sjl139090 ASSERT(env->current_device);
4361772Sjl139090 NOTICE;
4371772Sjl139090
4381772Sjl139090 create_int_prop(env, "#address-cells", 2);
4391772Sjl139090
4401772Sjl139090 FORTH(0, "map-in", do_map_in);
4411772Sjl139090 FORTH(0, "map-out", do_map_out);
4421772Sjl139090 FORTH(0, "get-portid", do_get_io_portid);
4431772Sjl139090 FORTH(0, "decode-unit", do_decode_unit);
4441772Sjl139090 FORTH(0, "encode-unit", do_encode_unit);
4451772Sjl139090 FORTH(0, "device-id", do_device_id);
4461772Sjl139090 FORTH(0, "get-hwd-va", do_get_hwd_va);
4471772Sjl139090 FORTH(0, "get-fcinterp-name", do_get_intrp_name);
4481772Sjl139090 FORTH(0, "master-interrupt", do_master_interrupt);
4491772Sjl139090 FORTH(0, "register-vector-entry", do_register_vector_entry);
4501772Sjl139090 FORTH(0, "get-interrupt-target", do_get_interrupt_target);
4511772Sjl139090 }
452