diff options
Diffstat (limited to 'usr/src/lib/efcode/jupiter/jupiter.c')
-rw-r--r-- | usr/src/lib/efcode/jupiter/jupiter.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/jupiter/jupiter.c b/usr/src/lib/efcode/jupiter/jupiter.c new file mode 100644 index 0000000000..2fc159bc20 --- /dev/null +++ b/usr/src/lib/efcode/jupiter/jupiter.c @@ -0,0 +1,437 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +#include <sys/opl_cfg.h> + +/* VA for HardWare Descriptor */ +static hwd_cmu_chan_t hwd_va_cmu; +static hwd_leaf_t hwd_va_pci; + +/* Macro to get I/O portid */ +#define DO_GET_IO_PORTID(env, lo, hi, portid) \ + PUSH(DS, lo); \ + PUSH(DS, hi); \ + do_get_io_portid(env); \ + portid = (uint32_t)POP(DS) + +fstack_t +mem_map_in(fcode_env_t *env, fstack_t hi, fstack_t lo, fstack_t len) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + fc_cell_t virt; + fstack_t mcookie = NULL; + char *service = "map-in"; + int error; + int offset = 0; + + /* + * The calculation of the offset, lo and len are left here + * due to historical precedence. + */ + + offset = lo & PAGEOFFSET; + lo &= PAGEMASK; + len = (len + offset + PAGEOFFSET) & PAGEMASK; + + error = fc_run_priv(pdp->common, service, 3, 1, fc_size2cell(len), + fc_uint32_t2cell(hi), fc_uint32_t2cell(lo), &virt); + + if (error) + throw_from_fclib(env, 1, "jupiter:%s: failed\n", service); + + mcookie = mapping_to_mcookie(virt, len, NULL, NULL); + + if (mcookie == NULL) + throw_from_fclib(env, 1, + "jupiter:%s: mapping_to_mcookie failed\n", service); + + mcookie += offset; + + debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %llx -> %x\n", service, + (long long)virt, (uint32_t)mcookie); + + return (mcookie); +} + +static void +mem_map_out(fcode_env_t *env, fstack_t mcookie, fstack_t len) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + fc_cell_t virt; + char *service = "map-out"; + int error; + int offset; + + /* + * The calculation of the offset, lo and len are left here + * due to historical precedence. + */ + + offset = mcookie & PAGEOFFSET; + mcookie &= PAGEMASK; + len = (len + offset + PAGEOFFSET) & PAGEMASK; + + if (!is_mcookie(mcookie)) { + log_message(MSG_ERROR, "jupiter:%s: %x not an mcookie!\n", + service, (int)mcookie); + virt = mcookie; + } else { + virt = mcookie_to_addr(mcookie); + debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %x -> %llx\n", + service, (int)mcookie, (long long)virt); + delete_mapping(mcookie); + } + + error = fc_run_priv(pdp->common, service, 2, 0, + fc_size2cell(len), virt); + if (error) + log_message(MSG_ERROR, "jupiter:%s: failed\n", service); +} + +static void +do_map_in(fcode_env_t *env) +{ + fstack_t phi, plo, len, addr; + + CHECK_DEPTH(env, 3, "jupiter:map-in"); + len = POP(DS); + phi = POP(DS); + plo = POP(DS); + addr = mem_map_in(env, phi, plo, len); + PUSH(DS, addr); +} + +static void +do_map_out(fcode_env_t *env) +{ + fstack_t addr, len; + + CHECK_DEPTH(env, 2, "jupiter:map-out"); + len = POP(DS); + addr = POP(DS); + mem_map_out(env, addr, len); +} + +static void +do_get_io_portid(fcode_env_t *env) +{ + fstack_t phi, plo; + unsigned int portid, lsb, ch, leaf; + + CHECK_DEPTH(env, 2, "jupiter:get-portid"); + + phi = POP(DS); + plo = POP(DS); + + lsb = OPL_ADDR_TO_LSB(phi); + ch = OPL_ADDR_TO_CHANNEL(phi); + leaf = OPL_ADDR_TO_LEAF(phi, plo); + + portid = OPL_IO_PORTID(lsb, ch, leaf); + + debug_msg(DEBUG_REG_ACCESS, "jupiter:get-portid ( %x %x ) -> %x\n", + (int)phi, (int)plo, (int)portid); + PUSH(DS, portid); +} + +static void +do_encode_unit(fcode_env_t *env) +{ + char enc_buf[64]; + fstack_t hi, lo; + uint32_t id; + long long off; + + CHECK_DEPTH(env, 2, "jupiter:encode-unit"); + + hi = POP(DS); + lo = POP(DS); + off = (long long)(((hi & 0x1F) << 32) | lo); + + /* Convert physical address to portid */ + DO_GET_IO_PORTID(env, lo, hi, id); + + if (off) { + (void) sprintf(enc_buf, "%x,%llx", id, off); + } else { + (void) sprintf(enc_buf, "%x", id); + } + + debug_msg(DEBUG_REG_ACCESS, "jupiter:encode_unit ( %x %x ) -> '%s'\n", + (uint32_t)hi, (uint32_t)lo, enc_buf); + + push_a_string(env, STRDUP(enc_buf)); +} + +static void +do_decode_unit(fcode_env_t *env) +{ + uint32_t hi; + long long lo; + unsigned int portid, lsb, ch; + char *buf; + + CHECK_DEPTH(env, 2, "jupiter:decode-unit"); + + buf = pop_a_string(env, NULL); + if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) { + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, "jupiter:decode_unit:%s", + buf); + } + lo = 0; + } + + lsb = OPL_IO_PORTID_TO_LSB(portid); + ch = OPL_PORTID_TO_CHANNEL(portid); + hi = OPL_ADDR_HI(lsb, ch); + + debug_msg(DEBUG_REG_ACCESS, + "jupiter:decode_unit ( '%s' ) -> %x %llx\n", buf, hi, lo); + + PUSH(DS, (fstack_t)lo); + PUSH(DS, (fstack_t)hi); +} + +static void +do_device_id(fcode_env_t *env) +{ + common_data_t *cdp = COMMON_PRIVATE(env); + char *buf = NULL; + uint32_t hi; + long long lo; + uint32_t portid, ch, leaf; + + CHECK_DEPTH(env, 2, "jupiter:device-id"); + + hi = POP(DS); + lo = POP(DS); + + portid = 0; + if (cdp && cdp->fc.unit_address && + ((buf = strdup(cdp->fc.unit_address)) != NULL)) { + /* + * Get portid number from unit_address + * Because of no leaf information in physical address + */ + if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) { + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, + "jupiter:do_device_id: invalid %s", buf); + } + } + } else { + /* + * Non existence unit_address case. + * Convert physical address to portid. + */ + throw_from_fclib(env, 1, + "jupiter:do_device_id: failed unit address"); + DO_GET_IO_PORTID(env, lo, hi, portid); + } + + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:(%x,%llx)\n", portid, lo); + + /* Pick up each ID from portid */ + ch = OPL_PORTID_TO_CHANNEL(portid); + leaf = OPL_PORTID_TO_LEAF(portid); + + if (ch == OPL_CMU_CHANNEL) { + /* + * CMU-CH: PCICMU CHANNEL + */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:cmu-ch\n"); + push_a_string(env, "cmu-ch"); + } else if (OPL_OBERON_CHANNEL(ch) && OPL_VALID_LEAF(leaf)) { + /* + * PCI-CH: Oberon Leaves CHANNEL + */ + if (leaf) { + /* Leaf B */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:jup-oberon-pci1\n"); + push_a_string(env, "jup-oberon-pci1"); + } else { + /* Leaf A */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:jup-oberon-pci0\n"); + push_a_string(env, "jup-oberon-pci0"); + } + } else { + /* Not matched to any channels */ + throw_from_fclib(env, 1, + "jupiter:do_device_id: invalid portid %x", portid); + push_a_string(env, ""); + } + + /* Free the duplicated buf */ + if (buf != NULL) + free(buf); +} + +static void +do_get_hwd_va(fcode_env_t *env) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + char *service = "get-hwd-va"; + char *buf; + uint32_t portid = 0; + int ch; + int error; + fc_cell_t status; + void *hwd_va; + + CHECK_DEPTH(env, 2, "jupiter:get-hwd-va"); + + /* Get a portid with string format */ + buf = pop_a_string(env, NULL); + + /* Convert to the integer from the string */ + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, "jupiter:%s: invalid portid", + service); + } + + ch = OPL_PORTID_TO_CHANNEL(portid); + if (!OPL_VALID_CHANNEL(ch)) { + throw_from_fclib(env, 1, "jupiter:%s: invalid poritd", + service); + hwd_va = 0; + goto out; + } + + if (ch == OPL_CMU_CHANNEL) { + hwd_va = (void *)&hwd_va_cmu; + } else { + hwd_va = (void *)&hwd_va_pci; + } + + /* + * Get the virtual address of hwd specified with portid. + */ + error = fc_run_priv(pdp->common, service, 2, 1, + fc_uint32_t2cell(portid), fc_ptr2cell(hwd_va), &status); + + if (error || !status) + throw_from_fclib(env, 1, "jupiter:%s: failed\n", service); + +out: + PUSH(DS, (fstack_t)hwd_va); +} + +static void +do_get_intrp_name(fcode_env_t *env) +{ + /* + * Just pass the "eFCode" string. + */ + + debug_msg(DEBUG_FIND_FCODE, + "jupiter: do_get_intrp_name: eFCode\n"); + + push_a_string(env, "eFCode"); +} + +static void +do_master_interrupt(fcode_env_t *env) +{ + int portid; + token_t xt; + + CHECK_DEPTH(env, 2, "jupiter:master-interrput"); + portid = POP(DS); + xt = POP(DS); + + PUSH(DS, FALSE); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:master-interrupt ( %x %x ) -> %x\n", + portid, xt, (int)FALSE); +} + +static void +do_register_vector_entry(fcode_env_t *env) +{ + int ign, ino, level; + + CHECK_DEPTH(env, 3, "jupiter:register-vector-entry"); + ign = POP(DS); + ino = POP(DS); + level = POP(DS); + + PUSH(DS, FALSE); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:register-vector-entry ( %x %x %x ) -> %x\n", + ign, ino, level, (int)FALSE); +} + +static void +do_get_interrupt_target(fcode_env_t *env) +{ + int mid = -1; + + PUSH(DS, mid); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:get-interrupt-target ( ) -> %x\n", mid); +} + + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + ASSERT(env->current_device); + NOTICE; + + create_int_prop(env, "#address-cells", 2); + + FORTH(0, "map-in", do_map_in); + FORTH(0, "map-out", do_map_out); + FORTH(0, "get-portid", do_get_io_portid); + FORTH(0, "decode-unit", do_decode_unit); + FORTH(0, "encode-unit", do_encode_unit); + FORTH(0, "device-id", do_device_id); + FORTH(0, "get-hwd-va", do_get_hwd_va); + FORTH(0, "get-fcinterp-name", do_get_intrp_name); + FORTH(0, "master-interrupt", do_master_interrupt); + FORTH(0, "register-vector-entry", do_register_vector_entry); + FORTH(0, "get-interrupt-target", do_get_interrupt_target); +} |