1c42de6d020629af774dd9e9fc81be3f3ed9398egd * CDDL HEADER START
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The contents of this file are subject to the terms of the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Common Development and Distribution License (the "License").
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * You may not use this file except in compliance with the License.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * See the License for the specific language governing permissions
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * and limitations under the License.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * When distributing Covered Code, include this CDDL HEADER in each
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If applicable, add the following below this CDDL HEADER, with the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * fields enclosed by brackets "[]" replaced with your own identifying
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * information: Portions Copyright [yyyy] [name of copyright owner]
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * CDDL HEADER END
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Use is subject to license terms.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The "bscbus" driver provides access to the LOMlite2 virtual registers,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * so that its clients (children) need not be concerned with the details
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * of the access mechanism, which in this case is implemented via a
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * packet-based protocol over a Xbus (similar to ebus) parallel link to the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * H8 host interface registers.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * On the other hand, this driver doesn't generally know what the virtual
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * registers signify - only the clients need this information.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#if defined(__sparc)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Compiling for Solaris 10+ with access handle enhancements
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Compatibility definitions for backport to Solaris 8/9
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define HANDLE_PRIVATE(hdlp) (hdlp->ahi_common.ah_bus_private)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define ddi_driver_major(dip) ddi_name_to_major(ddi_binding_name(dip))
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* NDI_ACC_HDL_V2 */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Local definitions
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define ADDR_TO_OFFSET(a, hdlp) ((caddr_t)(a) - HANDLE_ADDR(hdlp))
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define ADDR_TO_VREG(a) ((caddr_t)(a) - BSCBUS_DUMMY_ADDRESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* DEBUG */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSC command logging routines.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Record the data passing to and from the BSC
1c42de6d020629af774dd9e9fc81be3f3ed9398egdtypedef enum {
1c42de6d020629af774dd9e9fc81be3f3ed9398egdtypedef struct {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The following definitions are taken from the Hardware Manual for
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the Hitachi H8S/2148 in conjunction with the hardware specification
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * for the Stiletto blade.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Each instance of the host interface has 3 registers on the H8:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * IDRn - Input Data Register - write-only for Solaris.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * writes to this can be done via two
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * addresses - control and data.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The H8 can determine which address was
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * written by examining the C/D bit in
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the status register.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * ODRn - Output Data Register - read-only for Solaris.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * A read has the side effect of acknowledging
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * interrupts.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * STRn - Status Register - read-only for Solaris.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * In terms of host access to this the Input and Output data registers are
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * mapped at the same address.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define H8_STR_IDRC 0x08 /* last write to IDR was to IDRC */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* 0=data, 1=command */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define H8_STR_TOKENPROTOCOL 0x80 /* token-passing protocol */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Packet format ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_PARAM 0x00 /* Parameter byte: 0b0xxxxxxx */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_CMD_XADDR 0x04 /* Extended (2-byte) addressing */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_STATUS_ASYNC 0x04 /* Asynchronous event pending */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_STATUS_ERR 0x02 /* Error in command processing */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_CHANNEL_TO_OFFSET(chno) ((chno) * 2) /* Register offset */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Time periods, in nanoseconds
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Note that LOMBUS_ONE_SEC and some other time
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * periods are defined in <sys/lombus.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Local datatypes
1c42de6d020629af774dd9e9fc81be3f3ed9398egd BSCBUS_CMDSTATE_CLEARING, /* Clearing firmware busy status */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd BSCBUS_CMDSTATE_SENDING, /* Waiting to send data to f/w */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd BSCBUS_CMDSTATE_WAITING, /* Waiting for status from f/w */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd BSCBUS_CMDSTATE_READY, /* Status received/command done */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Changes to these are protected by the instance ch_mutex mutex */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_acc_handle_t ch_handle; /* per channel access handle */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd unsigned int map_count; /* Number of mappings to channel */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Flag to indicate that we've incurred a hardware fault on
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * accesses to the H8; once this is set, we fake all further
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * accesses in order not to provoke additional bus errors.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Data protected by the dog_mutex: the watchdog-patting
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * protocol data (since the dog can be patted from a high-level
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * cyclic), and the interrupt-enabled flag.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Serial protocol state data, protected by lo_mutex
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * (which is initialised using <lo_iblk>)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#define BSCBUS_TX_PENDING(csp) ((csp)->cmdp > (csp)->cmdbuf)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This driver's soft-state structure
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Configuration data, set during attach
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Parameters derived from .conf properties
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Flag to indicate that we are using per channel
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * mapping of the register sets and interrupts.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reg set 0 is chan 0
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reg set 1 is chan 1 ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Interrupts are specified in that order but later
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * channels may not have interrupts.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * channel state data, protected by ch_mutex
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * channel claim/release requests are protected by this mutex.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd struct bscbus_channel_state channel[BSCBUS_MAX_CHANNELS];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Command logging buffer for recording transactions with the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSC. This is useful for debugging failed transactions and other
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * such funnies.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The auxiliary structure attached to each child
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * (the child's parent-private-data points to this).
1c42de6d020629af774dd9e9fc81be3f3ed9398egdvoid bscbus_cmd_log(struct bscbus_channel_state *, bsc_cmd_stamp_t,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#else /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Local data
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * General utility routines ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_trace(struct bscbus_channel_state *csp, char code, const char *caller,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd const char *fmt, ...)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#else /* DEBUG */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* DEBUG */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic struct bscbus_state *
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_getstate(dev_info_t *dip, int instance, const char *caller)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Use the instance number from the <dip>; also,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * check that it really corresponds to this driver
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "%s: major number mismatch (%d vs. %d) in %s(),"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "probably due to child misconfiguration",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "%s: devinfo mismatch (%p vs. %p) in %s(), "
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "probably due to child misconfiguration",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Lowest-level I/O register read/write
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_put_reg(struct bscbus_channel_state *csp, uint_t reg, uint8_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_get_reg(struct bscbus_channel_state *csp, uint_t reg)
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_check_fault_status(struct bscbus_channel_state *csp)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_check_acc_handle(csp->ch_handle) != DDI_SUCCESS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Write data into h8 registers
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_pat_dog(struct bscbus_channel_state *csp, uint8_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Previous attempts to contact BSC have failed.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Do not bother waiting for it to eat previous
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Pat anyway just in case the BSC is really alive
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * and the IBF bit is lying.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "retry count exceeded");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (--doglimit == 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* The BSC is not responding - give up */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Pat anyway just in case the BSC is really alive */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "poll limit exceeded");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * State diagrams for how bscbus_process works.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_IDLE No transaction in progress
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_BUSY Setting up command
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_CLEARING Clearing firmware busy status
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_SENDING Waiting to send data to f/w
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_PENDING Waiting for ack from f/w
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_WAITING Waiting for status from f/w
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_READY Status received/command done
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSCBUS_CMDSTATE_ERROR Command failed with error
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | (0/1) | abnormal
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ state
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | \ detected
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | \------>------+ +----<---+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * bsc | | | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * is | V V |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * ready| +----------+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | | CLEARING | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | | (2) | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | +----------+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | cleared / | \ | more to clear
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | / | \-->--+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | +-------<-------/ V
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * V V |timeout
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ timeout |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | |------>---------+--------+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | SENDING | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | (3) |------<-------+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ | V
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * sent| \ send ^ack |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * last| \ next |received |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | \ +----------+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | \ | | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | \------>| PENDING |-->-+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | | (4) | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | +----------+ |timeout
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | +---<----+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | WAITING | ^ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | (5) | | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | | |more | |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | V |required| |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * done| | +--->----+ |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | +--->--------------+ +---<---+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ +----------+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | READY | | ERROR |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * | (7) | | (6) |
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +----------+ +----------+
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * +------>---+---<------+
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_process_sending(struct bscbus_channel_state *csp, uint8_t status)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * When we get here we actually expect H8_STR_IBF to
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * be clear but we check just in case of problems.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "state %d; val $%x",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* No more pending - move to waiting state */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "moving to waiting");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Extend deadline because time has moved on */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Wait for ack of this byte */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "moving to pending");
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We only enter this state if H8_STR_BUSY was set when
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * we started the transaction. We just ignore all received
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * data until we see OBF set AND BUSY cleared.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * It is not good enough to see BUSY clear on its own
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Throw away any data received up until now */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "busy cleared");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Send the next byte immediately.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * At this stage we should clear the OBF flag because that
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * data has been used. IBF is still valid so do not clear that.
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_process_pending(struct bscbus_channel_state *csp, uint8_t status)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* We are waiting for an acknowledgement of a byte */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "moving to sending");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Send the next byte immediately.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * At this stage we should clear the OBF flag because that
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * data has been used. IBF is still valid so do not clear that.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (rcvd == 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * No bytes received this time through (though there
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * might be a partial packet sitting in the buffer).
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* EMPTY */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Buffer overflow; discard the data & treat as an error
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * (even if the last byte read did claim to terminate a
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * packet, it can't be a valid one 'cos it's too long!)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Packet not yet complete; leave the partial packet in
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the buffer for later ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Invalid "status" byte - maybe an echo of the command? */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Wrong sequence number! Flag this as an error */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Finally, we know that's it's a valid reply to our
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * last command. Update the ASYNC status, derive the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reply parameter (if any), and check the ERROR bit
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * to find out what the parameter means.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Note that not all the values read/assigned here
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * are meaningful, but it doesn't matter; the waiting
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * thread will know which one(s) it should check.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tmp = ((data & BSCBUS_STATUS_MSB) ? 0x80 : 0) | csp->reply[0];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Packet receive handler
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This routine should be called from the low-level softint,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * or bscbus_cmd() (for polled operation), with the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * low-level mutex already held.
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "state %d; error $%x",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Nothing to do */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check for timeouts - but only if the command has not yet
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * completed (ready is true when command completes in this
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * call to bscbus_process OR cmdstate is READY or ERROR if
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * this is a spurious call to bscbus_process i.e. a spurious
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * interrupt)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "timeout previous state %d; error $%x",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Move onto sending because busy might be stuck */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Extend timeout relative to original start time */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((status & H8_STR_OBF) || (status & H8_STR_IBF) || ready) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "last $%02x; state %d; error $%x; ready %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Read the registers to ensure that the interrupt is cleared.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Status must be read first because reading data changes the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We always read the data because that clears the interrupt down.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This is horrible hardware semantics but we have to do it!
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This routine is only called if we timeout in userland
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * waiting for an interrupt. This generally means that we have
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * lost interrupt capabilities or that something has gone
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * wrong. In this case we are allowed to access the hardware
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * and read the data register if necessary.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If interrupts return then recovery actions should mend us!
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Should look for data to receive */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* There is data available */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Serial protocol
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This routine builds a command and sets it in progress.
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * First of all, wait for the interface to be available.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * NOTE: we blow through all the mutex/cv/state checking and
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * preempt any command in progress if the system is panicking!
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (csp->cmdstate != BSCBUS_CMDSTATE_IDLE && !ddi_in_panic())
1c42de6d020629af774dd9e9fc81be3f3ed9398egd csp->sequence = (csp->sequence + BSCBUS_SEQ_LSB) & BSCBUS_SEQ;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We have exclusive ownership, so assemble the command (backwards):
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * [byte 0] Command: modified by XADDR and/or WMSB bits
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * [Optional] Parameter: Value to write (low 7 bits)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * [Optional] Parameter: Register number (high 7 bits)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * [Optional] Parameter: Register number (low 7 bits)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*FALLTHRU*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*FALLTHRU*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check and update the H8 h/w fault status before accessing
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the chip registers. If there's a (new or previous) fault,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * we'll run through the protocol but won't really touch the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * hardware and all commands will timeout. If a previously
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * discovered fault has now gone away (!), then we can (try to)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * proceed with the new command (probably a probe).
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Prepare for the command (to be processed by the interrupt
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * handler and/or polling loop below), and wait for a response
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * or timeout.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd csp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Must ensure that the busy state has cleared before
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * sending the command
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* It is clear to send the command immediately */
193974072f41a843678abf5f61979c748687e66bSherry Moore BSCBUS_CMD_POLLNOINTS : BSCBUS_CMD_POLL) / 1000);
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni if ((cv_reltimedwait(csp->lo_cv, csp->lo_mutex,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The return value may not be meaningful but retrieve it anyway
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Some problem here ... transfer the error code from
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the per-instance state to the per-handle fault flag.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The error code shouldn't be zero!
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * All done now!
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Space 0 - LOM virtual register access
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Only 8-bit accesses are supported.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping originally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Derive the virtual register number and run the command
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (bscbus_cmd(hdlp, ADDR_TO_VREG(addr), 0, BSCBUS_CMD_READ));
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping originally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Derive the virtual register number and run the command
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) bscbus_cmd(hdlp, ADDR_TO_VREG(addr), val, BSCBUS_CMD_WRITE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Space 1 - LOM watchdog pat register access
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Only 8-bit accesses are supported.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Reads have no effect and return 0.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * way of zeroing the destination area ;-) and still won't pat the dog.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * only count as a single pat, no matter how many bytes the caller
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * says to write, as the inter-pat time is VERY long compared with
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the time it will take to read the memory source area.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping originally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping originally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Space 2 - LOM async event flag register access
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Only 16-bit accesses are supported.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping orignally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Return the value of the asynchronous-event-pending flag
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * as passed back by the LOM at the end of the last command.
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Check the offset that the caller has added to the base address
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * against the length of the mapping originally requested.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The user can't overwrite the asynchronous-event-pending flag!
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * All spaces - access handle fault information
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Only 32-bit accesses are supported.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Derive the offset that the caller has added to the base
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * address originally returned, and use it to determine
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * which meta-register is to be accessed ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (offset) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This meta-register provides a code for the most
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * recent virtual register access fault, if any.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Reading this meta-register clears any existing fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * (at the virtual, not the hardware access layer), then
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * runs a NOP command and returns the fault code from that.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Obsolescent - but still supported for backwards
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * compatibility. This is an alias for the newer
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * LOMBUS_EVENT_REG, but doesn't require a separate
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * "reg" entry and ddi_regs_map_setup() call.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * It returns the value of the asynchronous-event-pending
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * flag as passed back by the BSC at the end of the last
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * completed command.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Derive the offset that the caller has added to the base
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * address originally returned, and use it to determine
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * which meta-register is to be accessed ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (offset) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This meta-register contains a code for the most
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * recent virtual register access fault, if any.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * It can be cleared simply by writing 0 to it.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Writing this meta-register clears any existing fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * (at the virtual, not the hardware acess layer), then
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * runs a NOP command. The caller can check the fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * code later if required.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Finally, some dummy functions for all unsupported access
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * space/size/mode combinations ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault and return a dummy value
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Invalid access - flag a fault
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Hardware setup - ensure that there are no pending transactions and
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * hence no pending interrupts. We do this be ensuring that the BSC is
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * not reporting a busy condition and that it does not have any data
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * pending in its output buffer.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This is important because if we have pending interrupts at attach
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * time Solaris will hang due to bugs in ddi_get_iblock_cookie.
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* No-one using this instance - no need to reset hardware */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Give the h8 time to complete a reply.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * In practice we should never worry about this
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * because whenever we get here it will have been
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * long enough for the h8 to complete a reply
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Reply should be completed by now. Try to clear busy status */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* We are done */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (timeout <= 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "clearing busy status");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We read ODR just in case there is a pending interrupt with
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * no data. This is potentially dangerous because we could get
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * out of sync due to race conditions BUT at this point the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * channel should be idle so it is safe.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Higher-level setup & teardown
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (nregs) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * regset 0 represents the H8 interface registers
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If no registers are defined, succeed vacuously;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * commands will be accepted, but we fake the accesses.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Remember that we are using the new register scheme.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reg set 0 is chan 0
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reg set 1 is chan 1 ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Interrupts are specified in that order but later
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * channels may not have interrupts.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We map the regs later on a per channel basis.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_claim_channel(struct bscbus_channel_state *csp, boolean_t map_dog)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "claim channel for channel %d, count %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* No-one is using this channel - initialise it */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "initialise channel %d, count %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Map appropriate register set for this channel */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &p, 0, 0, bscbus_dev_acc_attr, &h);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "mapped chno=%d ch_handle=%d ch_regs=%p",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * if using the old reg property scheme use the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * common mapping.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Ensure no interrupts pending prior to getting iblk cookie */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * we don't want lo_mutex to be initialised
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * with an iblock cookie if we are the wdog,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * because we don't use interrupts.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * check that there is an interrupt for this
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * this channel. If we fail to setup interrupts we
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * must unmap the registers and fail.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "no interrupt available for "
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "bscbus interrupts are high "
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "level - channel not usable.");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The channel is now live and may
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * receive interrupts
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "request conflicts with previous mapping. old %x, new %x.",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (1);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* unmap regs for failed channel */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* No-one is now using this channel - shutdown channel */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "shutdown channel %d, count %d",
193974072f41a843678abf5f61979c748687e66bSherry Moore ASSERT(!ddi_intr_hilevel(csp->ssp->dip, csp->chno));
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_remove_intr(csp->ssp->dip, csp->chno, csp->lo_iblk);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* unmap registers if using the new register scheme */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "release channel %d, count %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Nexus routines
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (op) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (space) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (op) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (space) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* NDI_ACC_HDL_V2 */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((ssp = bscbus_getstate(dip, -1, "bscbus_map")) == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Validate mapping request ...
193974072f41a843678abf5f61979c748687e66bSherry Moore &ssp->channel[LOMBUS_SPACE_TO_CHANNEL(rsp->lombus_space)],
193974072f41a843678abf5f61979c748687e66bSherry Moore mp->map_op, LOMBUS_SPACE_TO_REGSET(rsp->lombus_space),
193974072f41a843678abf5f61979c748687e66bSherry Moore VREG_TO_ADDR(rsp->lombus_base+off), len, mp->map_handlep, addrp));
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (op) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * First, look up and validate the "reg" property.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * It must be a non-empty integer array containing a set
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * of triples. Once we've verified that, we can treat it
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * as an array of type lombus_regspec_t[], which defines
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the meaning of the elements of each triple:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * + the first element of each triple must be a valid space
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * + the second and third elements (base, size) of each
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * triple must define a valid subrange of that space
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If it passes all the tests, we save it away for future
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reference in the child's parent-private-data field.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "child(%p): unknown reg space %d",
193974072f41a843678abf5f61979c748687e66bSherry Moore "%x,%x", rsp[0].lombus_space, rsp[0].lombus_base);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This nexus does not support passing interrupts to leaf drivers, so
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * all the intrspec-related operations just fail as cleanly as possible.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*ARGSUSED*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbscbus_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#if defined(__sparc)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Clean up on detach or failure of attach
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Autoconfiguration routines
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Allocate the soft-state structure
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ddi_soft_state_zalloc(bscbus_statep, instance) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((ssp = bscbus_getstate(dip, instance, "bscbus_attach")) == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Initialise devinfo-related fields
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Set various options from .conf properties
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Online the hardware ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Initialise state
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The hardware/interrupts are setup at map time to
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * avoid claiming hardware that OBP is using
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * All done, report success
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((ssp = bscbus_getstate(dip, instance, "bscbus_detach")) == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((ssp = bscbus_getstate(dip, -1, "bscbus_reset")) == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * System interface structures
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* get_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* add_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* remove_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* interrupt control */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_config */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_unconfig */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_init */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_fini */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_access_enter */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_access_exit */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_power */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* refcount */
193974072f41a843678abf5f61979c748687e66bSherry Moore "bscbus driver",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Dynamic loader interface code
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct bscbus_state), 0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdvoid bscbus_cmd_log(struct bscbus_channel_state *csp, bsc_cmd_stamp_t cat,
1a5e258f5471356ca102c7176637cdce45bac147Josef 'Jeff' Sipek idx = atomic_inc_32_nv(&ssp->cmd_log_idx);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* BSCBUS_LOGSTATUS */