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 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 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 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 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