/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* hci1394_s1394if.c
* The interface into the HAL from the services layer.
*/
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/1394/h1394.h>
#include <sys/1394/ixl1394.h>
#include <sys/1394/adapters/hci1394.h>
static void hci1394_s1394if_shutdown(void *hal_private);
static int hci1394_s1394if_phy(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_write(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_read(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_lock(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_write_response(void *hal_private,
cmd1394_cmd_t *cmd_id, h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_read_response(void *hal_private,
cmd1394_cmd_t *cmd_id, h1394_cmd_priv_t *cmd_private, int *result);
static int hci1394_s1394if_lock_response(void *hal_private,
cmd1394_cmd_t *cmd_id, h1394_cmd_priv_t *cmd_private, int *result);
static void hci1394_s1394if_response_complete(void *hal_private,
cmd1394_cmd_t *cmd_id, h1394_cmd_priv_t *cmd_private);
static int hci1394_s1394if_reset_bus(void *hal_private);
static int hci1394_s1394if_set_contender_bit(void *hal_private);
static int hci1394_s1394if_set_root_holdoff_bit(void *hal_private);
static int hci1394_s1394if_set_gap_count(void *hal_private, uint_t gap_count);
static int hci1394_s1394if_update_config_rom(void *hal_private,
void *local_buf, uint_t quadlet_count);
static int hci1394_s1394if_phy_filter_set(void *hal_private,
uint64_t mask, uint_t generation);
static int hci1394_s1394if_phy_filter_clr(void *hal_private,
uint64_t mask, uint_t generation);
static int hci1394_s1394if_short_bus_reset(void *hal_private);
static int hci1394_s1394if_csr_read(void *hal_private,
uint_t offset, uint32_t *data);
static int hci1394_s1394if_csr_write(void *hal_private,
uint_t offset, uint32_t data);
static int hci1394_s1394if_csr_cswap32(void *hal_private, uint_t generation,
uint_t offset, uint32_t compare, uint32_t swap, uint32_t *old);
static void hci1394_s1394if_power_state_change(void *hal_private,
h1394_node_pwr_flags_t nodeflags);
/* entry points into HAL from Services Layer */
h1394_evts_t hci1394_evts = {
H1394_EVTS_V1, /* hal_version */
0, /* reserved */
hci1394_s1394if_shutdown, /* shutdown */
hci1394_s1394if_phy, /* send_phy_config_pkt */
hci1394_s1394if_read, /* read */
hci1394_s1394if_read_response, /* read_response */
hci1394_s1394if_write, /* write */
hci1394_s1394if_write_response, /* write_response */
hci1394_s1394if_response_complete, /* response_complete */
hci1394_s1394if_lock, /* lock */
hci1394_s1394if_lock_response, /* lock_response */
hci1394_alloc_isoch_dma, /* allocate_isoch_dma */
hci1394_free_isoch_dma, /* free_isoch_dma */
hci1394_start_isoch_dma, /* start_isoch_dma */
hci1394_stop_isoch_dma, /* stop_isoch_dma */
hci1394_update_isoch_dma, /* update_isoch_dma */
hci1394_s1394if_update_config_rom, /* update_config_rom */
hci1394_s1394if_reset_bus, /* bus_reset */
hci1394_s1394if_short_bus_reset, /* short_bus_reset */
hci1394_s1394if_set_contender_bit, /* set_contender_bit */
hci1394_s1394if_set_root_holdoff_bit, /* set_root_holdoff_bit */
hci1394_s1394if_set_gap_count, /* set_gap_count */
hci1394_s1394if_csr_read, /* csr_read */
hci1394_s1394if_csr_write, /* csr_write */
hci1394_s1394if_csr_cswap32, /* csr_cswap32 */
hci1394_s1394if_phy_filter_set, /* phys_arreq_enable_set */
hci1394_s1394if_phy_filter_clr, /* phys_arreq_enable_clr */
hci1394_s1394if_power_state_change /* node_power_state_change */
};
/*
* hci1394_s1394if_shutdown()
* Shutdown the HAL. This is called when a critical error has been detected.
* This routine should shutdown the HAL so that it will no longer send or
* receive information to/from the 1394 bus. The purpose of this function is
* to try and keep the machine from crashing.
*/
static void
hci1394_s1394if_shutdown(void *hal_private)
{
hci1394_state_t *soft_state;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_shutdown_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
hci1394_shutdown(soft_state->drvinfo.di_dip);
TNF_PROBE_0_DEBUG(hci1394_s1394if_shutdown_exit,
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_s1394if_phy()
* write a phy packet out to the 1394 bus. A phy packet consists of one
* quadlet of data.
*/
static int
hci1394_s1394if_phy(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_phy(soft_state->async, cmd_id, cmd_private,
result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_phy_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_write()
* Perform a 1394 write operation. This can be either a quadlet or block
* write.
*/
static int
hci1394_s1394if_write(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_write(soft_state->async, cmd_id, cmd_private,
result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_write_fail, HCI1394_TNF_HAL_ERROR,
"");
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_read()
* Perform a 1394 read operation. This can be either a quadlet or block
* read.
*/
static int
hci1394_s1394if_read(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_read(soft_state->async, cmd_id, cmd_private,
result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_read_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_lock()
* Perform a 1394/1212 lock operation. This can be one of the following lock
* operations: (CMD1394_LOCK_MASK_SWAP, CMD1394_LOCK_COMPARE_SWAP
* CMD1394_LOCK_FETCH_ADD, CMD1394_LOCK_LITTLE_ADD, CMD1394_LOCK_BOUNDED_ADD
* CMD1394_LOCK_WRAP_ADD)
*/
static int
hci1394_s1394if_lock(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_lock(soft_state->async, cmd_id, cmd_private,
result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_lock_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_write_response()
* Send a response to a write request received off of the 1394 bus. This
* could have been with a quadlet or block write request.
*/
static int
hci1394_s1394if_write_response(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_response_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_write_response(soft_state->async, cmd_id,
cmd_private, result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_write_response_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_write_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_read_response()
* Send a response to a read request received off of the 1394 bus. This
* could have been with a quadlet or block read request.
*/
static int
hci1394_s1394if_read_response(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_response_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_read_response(soft_state->async, cmd_id,
cmd_private, result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_read_response_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_read_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_lock_response()
* Send a response to a lock request received off of the 1394 bus. This
* could have been one of the following lock operations:
* (CMD1394_LOCK_MASK_SWAP, CMD1394_LOCK_COMPARE_SWAP CMD1394_LOCK_FETCH_ADD,
* CMD1394_LOCK_LITTLE_ADD, CMD1394_LOCK_BOUNDED_ADD, CMD1394_LOCK_WRAP_ADD)
*/
static int
hci1394_s1394if_lock_response(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private, int *result)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_response_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not in a bus reset or shutdown */
if (hci1394_state(&soft_state->drvinfo) != HCI1394_NORMAL) {
if (hci1394_state(&soft_state->drvinfo) == HCI1394_BUS_RESET) {
*result = H1394_STATUS_INVALID_BUSGEN;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
}
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_async_lock_response(soft_state->async, cmd_id,
cmd_private, result);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_async_lock_response_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_lock_response_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_response_complete()
* This notifies the HAL that the services layer and target driver are done
* with a command that was received off of the 1394 bus. This will usually
* be called after the response to the command has been command_complete'd.
* The HAL is free to re-use the command or free up the memory from this
* command after this call has returned. This should only be called for
* ARREQ's.
*/
static void
hci1394_s1394if_response_complete(void *hal_private, cmd1394_cmd_t *cmd_id,
h1394_cmd_priv_t *cmd_private)
{
hci1394_state_t *soft_state;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_response_complete_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
hci1394_async_response_complete(soft_state->async, cmd_id, cmd_private);
TNF_PROBE_0_DEBUG(hci1394_s1394if_response_complete_exit,
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_s1394if_reset_bus()
* This routine resets the 1394 bus. It performs a "long" bus reset. It
* should work on all OpenHCI adapters.
*/
static int
hci1394_s1394if_reset_bus(void *hal_private)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_reset_bus_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_reset_bus_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_bus_reset(soft_state->ohci);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_reset_bus_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_reset_bus_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_reset_bus_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_set_contender_bit()
* This routine sets up the PHY so that the selfid contender bit will be set
* on subsequent bus resets. This routine will fail when we have a 1394-1995
* PHY since this PHY does not have a SW controllable contender bit.
*/
static int
hci1394_s1394if_set_contender_bit(void *hal_private)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_contender_bit_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_contender_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
if (soft_state->halinfo.phy == H1394_PHY_1995) {
TNF_PROBE_0(hci1394_s1394if_set_contender_bit_phyver_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_contender_enable(soft_state->ohci);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_set_contender_bit_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_contender_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_contender_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_set_root_holdoff_bit()
* This routine will set the root holdoff bit in the PHY. The Services Layer
* should send out a PHY configuration packet first to tell everyone which
* node to set the root holdoff bit on. If it is our root holdoff bit we
* are setting, the PHY will automatically set it unless we have an old
* (1394-1995) PHY. If we have a 1394-1995 PHY, the SL needs to call this
* routine after sending the PHY configuration packet. The SL also needs to
* call this if they want to perform a long bus reset and have the root
* holdoff bit set. We do this so that we do not have to do a read before
* the write. A PHY register write has less of a chance of failing.
*/
static int
hci1394_s1394if_set_root_holdoff_bit(void *hal_private)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_root_holdoff_enable(soft_state->ohci);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_set_root_holdoff_bit_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_set_gap_count()
* This routine will set the gap count bit in the PHY. The Services Layer
* should send out a PHY configuration packet first to tell everyone what
* gap count to use. Our PHY will automatically set the gap count unless we
* have an old (1394-1995) PHY. If we have a 1394-1995 PHY, the SL needs to
* call this routine after sending the PHY configuration packet and before
* generating a bus reset. The SL also needs to call before the they call to
* perform a long bus reset. We do this so that we do not have to do a PHY
* read before the write. A PHY register write has less of a chance of
* failing.
*/
static int
hci1394_s1394if_set_gap_count(void *hal_private, uint_t gap_count)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_gap_count_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_gap_count_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_gap_count_set(soft_state->ohci, gap_count);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_set_gap_count_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_gap_count_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_gap_count_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_phy_filter_set()
* reads/writes to physically mapped memory from devices on the bus are
* disabled by default. They can be enabled on a node by node basis. All
* physical accesses are disabled every bus reset so they must be re-enabled
* every bus reset (This is due to the fact the the node ids change every bus
* reset). A 64-bit mask is passed in to enable nodes to be able to rd/wr
* physically mapped memory over the 1394 bus. A bit = to 1 enables that
* node's physical accesses, a bit = to 0 does nothing (i.e. a bitwise or is
* performed). The LSB of the mask (bit 0), maps to node #0, bit #62, maps to
* node 62. The MSB (#63) is not used since the can only be 63 nodes
* (0 - 62) on the bus.
*
* hci1394_s1394if_phy_filter_clr() is used to disable access to physical
* memory. This is only required if the node had previously been enabled.
*
* generation is used to verify that we are have not gotten a bus reset since
* the mask was built.
*/
static int
hci1394_s1394if_phy_filter_set(void *hal_private,
uint64_t mask, uint_t generation)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_set_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_set_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_filter_set(soft_state->ohci, mask,
generation);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_phy_filter_set_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_set_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_set_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_phy_filter_clr()
* reads/writes to physically mapped memory from devices on the bus are
* disabled by default. They can be enabled/disabled on a node by node basis.
* All physical accesses are disabled every bus reset so they must be
* re-enabled every bus reset (This is due to the fact the the node ids
* change every bus reset). Only nodes which have been enabled and no longer
* need access to physical memory need to be disabled.
*
* A 64-bit mask is passed in to disable nodes from being able to rd/wr
* physically mapped memory over the 1394 bus. A bit = to 1 disables that
* node's physical accesses, a bit = to 0 does nothing (i.e. a bitwise or is
* performed). The LSB of the mask (bit 0), maps to node #0, bit #62, maps to
* node 62. The MSB (#63) is not used since there can only be 63 nodes
* (0 - 62) on the bus.
*
* hci1394_s1394if_phy_filter_set() is used to enable access to physical
* memory.
*
* generation is used to verify that we are have not gotten a bus reset since
* the mask was build.
*/
static int
hci1394_s1394if_phy_filter_clr(void *hal_private,
uint64_t mask, uint_t generation)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_clr_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_clr_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_filter_clr(soft_state->ohci, mask,
generation);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_phy_filter_clr_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_clr_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_phy_filter_clr_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_short_bus_reset()
* This routine resets the 1394 bus. It performs a "short" bus reset. It
* will only work on adapters with a 1394A or later PHY. Calling this routine
* when we have a 1394-1995 PHY is an error.
*/
static int
hci1394_s1394if_short_bus_reset(void *hal_private)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_short_bus_reset_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_short_bus_reset_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
if (soft_state->halinfo.phy == H1394_PHY_1995) {
TNF_PROBE_0(hci1394_s1394if_short_bus_reset_phyver_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_set_root_holdoff_bit_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
status = hci1394_ohci_bus_reset_short(soft_state->ohci);
if (status != DDI_SUCCESS) {
TNF_PROBE_0(hci1394_s1394if_short_bus_reset_fail,
HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_short_bus_reset_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_short_bus_reset_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_update_config_rom()
* This routine updates the configuration ROM. It copies "quadlet_count"
* 32-bit words from "local_buf" to the config ROM starting at the first
* location in config ROM. This routine is meant to update the entire config
* ROM and not meant for a partial update.
*/
static int
hci1394_s1394if_update_config_rom(void *hal_private,
void *local_buf, uint_t quadlet_count)
{
hci1394_state_t *soft_state;
ASSERT(hal_private != NULL);
ASSERT(local_buf != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_update_config_rom_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_update_config_rom_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
hci1394_ohci_cfgrom_update(soft_state->ohci, local_buf, quadlet_count);
TNF_PROBE_0_DEBUG(hci1394_s1394if_update_config_rom_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_s1394if_csr_read()
* CSR register read interface
* For more information on CSR registers, see
* IEEE 1212
* IEEE 1394-1995
* section 8.3.2
* IEEE P1394A Draft 3.0
* sections 10.32,10.33
*/
static int
hci1394_s1394if_csr_read(void *hal_private, uint_t offset, uint32_t *data)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
ASSERT(data != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_read_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_read_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
switch (offset) {
case CSR_STATE_CLEAR:
hci1394_csr_state_get(soft_state->csr, data);
status = DDI_SUCCESS;
break;
case CSR_STATE_SET:
/* Write Only Register */
status = DDI_FAILURE;
break;
case CSR_NODE_IDS:
hci1394_ohci_nodeid_get(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_RESET_START:
/* Not supported */
status = DDI_FAILURE;
break;
case CSR_SPLIT_TIMEOUT_HI:
hci1394_csr_split_timeout_hi_get(soft_state->csr, data);
status = DDI_SUCCESS;
break;
case CSR_SPLIT_TIMEOUT_LO:
hci1394_csr_split_timeout_lo_get(soft_state->csr, data);
status = DDI_SUCCESS;
break;
case CSR_CYCLE_TIME:
/* CYCLE_TIME is implemented in HW */
hci1394_ohci_cycletime_get(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUS_TIME:
/* BUS_TIME is implemented in the hci1394_ohci_* SW */
hci1394_ohci_bustime_get(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUSY_TIMEOUT:
hci1394_ohci_atreq_retries_get(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUS_MANAGER_ID:
/* BUS_MANAGER_ID is implemented in HW */
status = hci1394_ohci_csr_read(soft_state->ohci, 0, data);
break;
case CSR_BANDWIDTH_AVAILABLE:
/* BANDWIDTH_AVAILABLE is implemented in HW */
status = hci1394_ohci_csr_read(soft_state->ohci, 1, data);
break;
case CSR_CHANNELS_AVAILABLE_HI:
/* CHANNELS_AVAILABLE_HI is implemented in HW */
status = hci1394_ohci_csr_read(soft_state->ohci, 2, data);
break;
case CSR_CHANNELS_AVAILABLE_LO:
/* CHANNELS_AVAILABLE_LO is implemented in HW */
status = hci1394_ohci_csr_read(soft_state->ohci, 3, data);
break;
default:
status = DDI_FAILURE;
break;
}
if (status != DDI_SUCCESS) {
TNF_PROBE_1(hci1394_s1394if_csr_read_fail,
HCI1394_TNF_HAL_ERROR, "", tnf_uint, csr_address, offset);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_read_exit,
HCI1394_TNF_HAL_STACK, "");
return (status);
}
/*
* hci1394_s1394if_csr_write()
* CSR register write interface
* For more information on CSR registers, see
* IEEE 1212
* IEEE 1394-1995
* section 8.3.2
* IEEE P1394A Draft 3.0
* sections 10.32,10.33
*/
static int
hci1394_s1394if_csr_write(void *hal_private, uint_t offset, uint32_t data)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_write_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_write_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
switch (offset) {
case CSR_STATE_CLEAR:
hci1394_csr_state_bclr(soft_state->csr, data);
status = DDI_SUCCESS;
break;
case CSR_STATE_SET:
hci1394_csr_state_bset(soft_state->csr, data);
status = DDI_SUCCESS;
break;
case CSR_NODE_IDS:
hci1394_ohci_nodeid_set(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_RESET_START:
/* Not supported */
status = DDI_FAILURE;
break;
/*
* there is a race condition when updating the split timeout
* due to the nature of the interface. (i.e. having a separate
* hi an lo register)
*/
case CSR_SPLIT_TIMEOUT_HI:
hci1394_csr_split_timeout_hi_set(soft_state->csr, data);
/*
* update the pending list timeout value. The split timeout
* is stored in 1394 bus cycles and the timeout is specified in
* nS. Therefore, we need to convert the split timeout into nS.
*/
hci1394_async_pending_timeout_update(soft_state->async,
OHCI_BUS_CYCLE_TO_nS(hci1394_csr_split_timeout_get(
soft_state->csr)));
status = DDI_SUCCESS;
break;
case CSR_SPLIT_TIMEOUT_LO:
hci1394_csr_split_timeout_lo_set(soft_state->csr, data);
/*
* update the pending list timeout value. The split timeout
* is stored in 1394 bus cycles and the timeout is specified in
* nS. Therefore, we need to convert the split timeout into nS.
*/
hci1394_async_pending_timeout_update(soft_state->async,
OHCI_BUS_CYCLE_TO_nS(hci1394_csr_split_timeout_get(
soft_state->csr)));
status = DDI_SUCCESS;
break;
case CSR_CYCLE_TIME:
hci1394_ohci_cycletime_set(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUS_TIME:
hci1394_ohci_bustime_set(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUSY_TIMEOUT:
hci1394_ohci_atreq_retries_set(soft_state->ohci, data);
status = DDI_SUCCESS;
break;
case CSR_BUS_MANAGER_ID:
/* Invalid access, only read/cswap32 allowed */
status = DDI_FAILURE;
break;
case CSR_BANDWIDTH_AVAILABLE:
/* Invalid access, only read/cswap32 allowed */
status = DDI_FAILURE;
break;
case CSR_CHANNELS_AVAILABLE_HI:
/* Invalid access, only read/cswap32 allowed */
status = DDI_FAILURE;
break;
case CSR_CHANNELS_AVAILABLE_LO:
/* Invalid access, only read/cswap32 allowed */
status = DDI_FAILURE;
break;
default:
status = DDI_FAILURE;
break;
}
if (status != DDI_SUCCESS) {
TNF_PROBE_1(hci1394_s1394if_csr_write_fail,
HCI1394_TNF_HAL_ERROR, "", tnf_uint, csr_address, offset);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_write_exit,
HCI1394_TNF_HAL_STACK, "");
return (status);
}
/*
* hci1394_s1394if_csr_cswap32()
* CSR register cswap32 interface
* For more information on CSR registers, see
* IEEE 1212
* IEEE 1394-1995
* section 8.3.2
* IEEE P1394A Draft 3.0
* sections 10.32,10.33
*/
static int
hci1394_s1394if_csr_cswap32(void *hal_private, uint_t generation, uint_t offset,
uint32_t compare, uint32_t swap, uint32_t *old)
{
hci1394_state_t *soft_state;
int status;
ASSERT(hal_private != NULL);
ASSERT(old != NULL);
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_cswap32_enter,
HCI1394_TNF_HAL_STACK, "");
soft_state = (hci1394_state_t *)hal_private;
/* make sure we are not shutdown */
if (hci1394_state(&soft_state->drvinfo) == HCI1394_SHUTDOWN) {
TNF_PROBE_0(hci1394_state_fail, HCI1394_TNF_HAL_ERROR, "");
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_cswap32_exit,
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
switch (offset) {
case CSR_STATE_CLEAR:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_STATE_SET:
/* Invalid access, only write allowed */
status = DDI_FAILURE;
break;
case CSR_NODE_IDS:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_RESET_START:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_SPLIT_TIMEOUT_HI:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_SPLIT_TIMEOUT_LO:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_CYCLE_TIME:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_BUS_TIME:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_BUSY_TIMEOUT:
/* Invalid access, only read/write allowed */
status = DDI_FAILURE;
break;
case CSR_BUS_MANAGER_ID:
/* BUS_MANAGER_ID is implemented in HW */
status = hci1394_ohci_csr_cswap(soft_state->ohci, generation,
OHCI_CSR_SEL_BUS_MGR_ID, compare, swap, old);
break;
case CSR_BANDWIDTH_AVAILABLE:
/* BANDWIDTH_AVAILABLE is implemented in HW */
status = hci1394_ohci_csr_cswap(soft_state->ohci, generation,
OHCI_CSR_SEL_BANDWIDTH_AVAIL, compare, swap, old);
break;
case CSR_CHANNELS_AVAILABLE_HI:
/* CHANNELS_AVAILABLE_HI is implemented in HW */
status = hci1394_ohci_csr_cswap(soft_state->ohci, generation,
OHCI_CSR_SEL_CHANS_AVAIL_HI, compare, swap, old);
break;
case CSR_CHANNELS_AVAILABLE_LO:
/* CHANNELS_AVAILABLE_LO is implemented in HW */
status = hci1394_ohci_csr_cswap(soft_state->ohci, generation,
OHCI_CSR_SEL_CHANS_AVAIL_LO, compare, swap, old);
break;
default:
status = DDI_FAILURE;
break;
}
if (status != DDI_SUCCESS) {
TNF_PROBE_1(hci1394_s1394if_csr_read_fail,
HCI1394_TNF_HAL_ERROR, "", tnf_uint, csr_address, offset);
}
TNF_PROBE_0_DEBUG(hci1394_s1394if_csr_cswap32_exit,
HCI1394_TNF_HAL_STACK, "");
return (status);
}
/*
* hci1394_s1394if_power_state_change()
* Signals that a change in the bus topology has taken place which may affect
* power management.
*/
/*ARGSUSED*/
static void
hci1394_s1394if_power_state_change(void *hal_private,
h1394_node_pwr_flags_t nodeflags)
{
/* not implemented */
}