ppb_msq.c revision 330897
1163953Srrs/*- 2169382Srrs * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3163953Srrs * 4163953Srrs * Copyright (c) 1998, 1999 Nicolas Souchu 5163953Srrs * All rights reserved. 6163953Srrs * 7163953Srrs * Redistribution and use in source and binary forms, with or without 8163953Srrs * modification, are permitted provided that the following conditions 9163953Srrs * are met: 10163953Srrs * 1. Redistributions of source code must retain the above copyright 11163953Srrs * notice, this list of conditions and the following disclaimer. 12163953Srrs * 2. Redistributions in binary form must reproduce the above copyright 13163953Srrs * notice, this list of conditions and the following disclaimer in the 14163953Srrs * documentation and/or other materials provided with the distribution. 15163953Srrs * 16163953Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26163953Srrs * SUCH DAMAGE. 27163953Srrs * 28163953Srrs * 29163953Srrs */ 30163953Srrs 31163953Srrs#include <sys/cdefs.h> 32163953Srrs__FBSDID("$FreeBSD: stable/11/sys/dev/ppbus/ppb_msq.c 330897 2018-03-14 03:19:51Z eadler $"); 33163953Srrs#include <machine/stdarg.h> 34163953Srrs 35163953Srrs#include <sys/param.h> 36163953Srrs#include <sys/lock.h> 37163953Srrs#include <sys/mutex.h> 38163953Srrs#include <sys/systm.h> 39163953Srrs#include <sys/bus.h> 40163953Srrs 41163953Srrs#include <dev/ppbus/ppbconf.h> 42163953Srrs#include <dev/ppbus/ppb_msq.h> 43163953Srrs 44170606Srrs#include "ppbus_if.h" 45163953Srrs 46163953Srrs/* msq index (see PPB_MAX_XFER) 47163953Srrs * These are device modes 48163953Srrs */ 49163953Srrs#define COMPAT_MSQ 0x0 50163953Srrs#define NIBBLE_MSQ 0x1 51170606Srrs#define PS2_MSQ 0x2 52163953Srrs#define EPP17_MSQ 0x3 53167598Srrs#define EPP19_MSQ 0x4 54167598Srrs#define ECP_MSQ 0x5 55167598Srrs 56163953Srrs/* 57163953Srrs * Device mode to submsq conversion 58167598Srrs */ 59170606Srrsstatic struct ppb_xfer * 60163953Srrsmode2xfer(device_t bus, struct ppb_device *ppbdev, int opcode) 61163953Srrs{ 62163953Srrs int index, epp, mode; 63163953Srrs struct ppb_xfer *table; 64163953Srrs 65163953Srrs switch (opcode) { 66163953Srrs case MS_OP_GET: 67167598Srrs table = ppbdev->get_xfer; 68163953Srrs break; 69163953Srrs 70163953Srrs case MS_OP_PUT: 71167598Srrs table = ppbdev->put_xfer; 72170606Srrs break; 73163953Srrs 74169208Srrs default: 75169208Srrs panic("%s: unknown opcode (%d)", __func__, opcode); 76169208Srrs } 77169208Srrs 78169208Srrs /* retrieve the device operating mode */ 79163953Srrs mode = ppb_get_mode(bus); 80163953Srrs switch (mode) { 81163953Srrs case PPB_COMPATIBLE: 82167598Srrs index = COMPAT_MSQ; 83167598Srrs break; 84170606Srrs case PPB_NIBBLE: 85163953Srrs index = NIBBLE_MSQ; 86163953Srrs break; 87163953Srrs case PPB_PS2: 88163953Srrs index = PS2_MSQ; 89170606Srrs break; 90163953Srrs case PPB_EPP: 91163953Srrs switch ((epp = ppb_get_epp_protocol(bus))) { 92163953Srrs case EPP_1_7: 93163953Srrs index = EPP17_MSQ; 94163953Srrs break; 95163953Srrs case EPP_1_9: 96163953Srrs index = EPP19_MSQ; 97163953Srrs break; 98163953Srrs default: 99163953Srrs panic("%s: unknown EPP protocol (0x%x)!", __func__, 100163953Srrs epp); 101163953Srrs } 102163953Srrs break; 103170606Srrs case PPB_ECP: 104163953Srrs index = ECP_MSQ; 105163953Srrs break; 106163953Srrs default: 107163953Srrs panic("%s: unknown mode (%d)", __func__, mode); 108163953Srrs } 109163953Srrs 110170606Srrs return (&table[index]); 111163953Srrs} 112163953Srrs 113163953Srrs/* 114163953Srrs * ppb_MS_init() 115163953Srrs * 116163953Srrs * Initialize device dependent submicrosequence of the current mode 117170606Srrs * 118163953Srrs */ 119163953Srrsint 120163953Srrsppb_MS_init(device_t bus, device_t dev, struct ppb_microseq *loop, int opcode) 121163953Srrs{ 122170606Srrs struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 123163953Srrs struct ppb_xfer *xfer = mode2xfer(bus, ppbdev, opcode); 124163953Srrs 125163953Srrs ppb_assert_locked(bus); 126163953Srrs xfer->loop = loop; 127170606Srrs 128163953Srrs return (0); 129169208Srrs} 130169208Srrs 131163953Srrs/* 132163953Srrs * ppb_MS_exec() 133163953Srrs * 134170606Srrs * Execute any microsequence opcode - expensive 135163953Srrs * 136163953Srrs */ 137163953Srrsint 138163953Srrsppb_MS_exec(device_t bus, device_t dev, int opcode, union ppb_insarg param1, 139163953Srrs union ppb_insarg param2, union ppb_insarg param3, int *ret) 140170606Srrs{ 141163953Srrs struct ppb_microseq msq[] = { 142163953Srrs { MS_UNKNOWN, { { MS_UNKNOWN }, { MS_UNKNOWN }, { MS_UNKNOWN } } }, 143163953Srrs MS_RET(0) 144163953Srrs }; 145163953Srrs 146163953Srrs /* initialize the corresponding microseq */ 147163953Srrs msq[0].opcode = opcode; 148163953Srrs msq[0].arg[0] = param1; 149163953Srrs msq[0].arg[1] = param2; 150163953Srrs msq[0].arg[2] = param3; 151163953Srrs 152170606Srrs /* execute the microseq */ 153163953Srrs return (ppb_MS_microseq(bus, dev, msq, ret)); 154163953Srrs} 155163953Srrs 156163953Srrs/* 157170606Srrs * ppb_MS_loop() 158163953Srrs * 159163953Srrs * Execute a microseq loop 160163953Srrs * 161163953Srrs */ 162163953Srrsint 163163953Srrsppb_MS_loop(device_t bus, device_t dev, struct ppb_microseq *prolog, 164163953Srrs struct ppb_microseq *body, struct ppb_microseq *epilog, 165163953Srrs int iter, int *ret) 166163953Srrs{ 167163953Srrs struct ppb_microseq loop_microseq[] = { 168163953Srrs MS_CALL(0), /* execute prolog */ 169163953Srrs 170163953Srrs MS_SET(MS_UNKNOWN), /* set size of transfer */ 171170606Srrs /* loop: */ 172163953Srrs MS_CALL(0), /* execute body */ 173167598Srrs MS_DBRA(-1 /* loop: */), 174167598Srrs 175170606Srrs MS_CALL(0), /* execute epilog */ 176163953Srrs MS_RET(0) 177163953Srrs }; 178167598Srrs 179170606Srrs /* initialize the structure */ 180163953Srrs loop_microseq[0].arg[0].p = (void *)prolog; 181163953Srrs loop_microseq[1].arg[0].i = iter; 182170606Srrs loop_microseq[2].arg[0].p = (void *)body; 183163953Srrs loop_microseq[4].arg[0].p = (void *)epilog; 184163953Srrs 185170606Srrs /* execute the loop */ 186163953Srrs return (ppb_MS_microseq(bus, dev, loop_microseq, ret)); 187167598Srrs} 188163953Srrs 189167598Srrs/* 190163953Srrs * ppb_MS_init_msq() 191163953Srrs * 192170606Srrs * Initialize a microsequence - see macros in ppb_msq.h 193163953Srrs * 194163953Srrs */ 195163953Srrsint 196163953Srrsppb_MS_init_msq(struct ppb_microseq *msq, int nbparam, ...) 197163953Srrs{ 198163953Srrs int i; 199170606Srrs int param, ins, arg, type; 200163953Srrs va_list p_list; 201163953Srrs 202170606Srrs va_start(p_list, nbparam); 203163953Srrs 204163953Srrs for (i=0; i<nbparam; i++) { 205163953Srrs /* retrieve the parameter descriptor */ 206163953Srrs param = va_arg(p_list, int); 207170606Srrs 208163953Srrs ins = MS_INS(param); 209163953Srrs arg = MS_ARG(param); 210163953Srrs type = MS_TYP(param); 211163953Srrs 212163953Srrs /* check the instruction position */ 213163953Srrs if (arg >= PPB_MS_MAXARGS) 214163953Srrs panic("%s: parameter out of range (0x%x)!", 215163953Srrs __func__, param); 216163953Srrs 217163953Srrs#if 0 218163953Srrs printf("%s: param = %d, ins = %d, arg = %d, type = %d\n", 219170606Srrs __func__, param, ins, arg, type); 220163953Srrs#endif 221163953Srrs 222163953Srrs /* properly cast the parameter */ 223163953Srrs switch (type) { 224163953Srrs case MS_TYP_INT: 225163953Srrs msq[ins].arg[arg].i = va_arg(p_list, int); 226170606Srrs break; 227163953Srrs 228163953Srrs case MS_TYP_CHA: 229163953Srrs msq[ins].arg[arg].i = (int)va_arg(p_list, int); 230163953Srrs break; 231163953Srrs 232170606Srrs case MS_TYP_PTR: 233163953Srrs msq[ins].arg[arg].p = va_arg(p_list, void *); 234163953Srrs break; 235163953Srrs 236163953Srrs case MS_TYP_FUN: 237170606Srrs msq[ins].arg[arg].f = va_arg(p_list, void *); 238163953Srrs break; 239163953Srrs 240163953Srrs default: 241163953Srrs panic("%s: unknown parameter (0x%x)!", __func__, 242170606Srrs param); 243163953Srrs } 244163953Srrs } 245163953Srrs 246163953Srrs va_end(p_list); 247163953Srrs return (0); 248163953Srrs} 249163953Srrs 250163953Srrs/* 251163953Srrs * ppb_MS_microseq() 252163953Srrs * 253163953Srrs * Interprete a microsequence. Some microinstructions are executed at adapter 254170606Srrs * level to avoid function call overhead between ppbus and the adapter 255163953Srrs */ 256163953Srrsint 257163953Srrsppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret) 258163953Srrs{ 259163953Srrs struct ppb_data *ppb = (struct ppb_data *)device_get_softc(bus); 260163953Srrs struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 261163953Srrs 262163953Srrs struct ppb_microseq *mi; /* current microinstruction */ 263170606Srrs int error; 264163953Srrs 265163953Srrs struct ppb_xfer *xfer; 266163953Srrs 267163953Srrs /* microsequence executed to initialize the transfer */ 268170606Srrs struct ppb_microseq initxfer[] = { 269163953Srrs MS_PTR(MS_UNKNOWN), /* set ptr to buffer */ 270163953Srrs MS_SET(MS_UNKNOWN), /* set transfer size */ 271163953Srrs MS_RET(0) 272163953Srrs }; 273163953Srrs 274170606Srrs mtx_assert(ppb->ppc_lock, MA_OWNED); 275163953Srrs if (ppb->ppb_owner != dev) 276163953Srrs return (EACCES); 277163953Srrs 278163953Srrs#define INCR_PC (mi ++) 279170606Srrs 280163953Srrs mi = msq; 281163953Srrs for (;;) { 282163953Srrs switch (mi->opcode) { 283163953Srrs case MS_OP_PUT: 284163953Srrs case MS_OP_GET: 285163953Srrs 286163953Srrs /* attempt to choose the best mode for the device */ 287163953Srrs xfer = mode2xfer(bus, ppbdev, mi->opcode); 288163953Srrs 289163953Srrs /* figure out if we should use ieee1284 code */ 290170606Srrs if (!xfer->loop) { 291163953Srrs if (mi->opcode == MS_OP_PUT) { 292163953Srrs if ((error = PPBUS_WRITE( 293163953Srrs device_get_parent(bus), 294163953Srrs (char *)mi->arg[0].p, 295170606Srrs mi->arg[1].i, 0))) 296163953Srrs goto error; 297163953Srrs 298163953Srrs INCR_PC; 299163953Srrs goto next; 300163953Srrs } else 301163953Srrs panic("%s: IEEE1284 read not supported", __func__); 302170606Srrs } 303163953Srrs 304163953Srrs /* XXX should use ppb_MS_init_msq() */ 305163953Srrs initxfer[0].arg[0].p = mi->arg[0].p; 306163953Srrs initxfer[1].arg[0].i = mi->arg[1].i; 307163953Srrs 308170606Srrs /* initialize transfer */ 309163953Srrs ppb_MS_microseq(bus, dev, initxfer, &error); 310163953Srrs 311163953Srrs if (error) 312163953Srrs goto error; 313163953Srrs 314163953Srrs /* the xfer microsequence should not contain any 315170606Srrs * MS_OP_PUT or MS_OP_GET! 316163953Srrs */ 317163953Srrs ppb_MS_microseq(bus, dev, xfer->loop, &error); 318163953Srrs 319163953Srrs if (error) 320163953Srrs goto error; 321163953Srrs 322170606Srrs INCR_PC; 323163953Srrs break; 324163953Srrs 325163953Srrs case MS_OP_RET: 326163953Srrs if (ret) 327170606Srrs *ret = mi->arg[0].i; /* return code */ 328163953Srrs return (0); 329163953Srrs 330163953Srrs default: 331163953Srrs /* executing microinstructions at ppc level is 332163953Srrs * faster. This is the default if the microinstr 333170606Srrs * is unknown here 334163953Srrs */ 335163953Srrs if ((error = PPBUS_EXEC_MICROSEQ( 336163953Srrs device_get_parent(bus), &mi))) 337163953Srrs goto error; 338163953Srrs break; 339170606Srrs } 340163953Srrs next: 341163953Srrs continue; 342163953Srrs } 343163953Srrserror: 344170606Srrs return (error); 345163953Srrs} 346163953Srrs 347163953Srrs