wrsmplat.c revision 03831d35f7499c87d51205817c93e9a8d42c4bae
/*
* 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
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Serengeti WRSM platform-specific module
*/
#include <sys/int_fmtio.h>
#include <sys/cpu_module.h>
#include <sys/wrsm_config.h>
#include <sys/wrsm_plat_impl.h>
#include <sys/wci_regs.h>
#include <sys/wci_offsets.h>
#include <sys/wci_common.h>
#include <sys/sgsbbc_mailbox.h>
#ifdef DEBUG
#define WP_DEBUG 1
#define WP_QUEUE 2
#define WP_LINK 4
#define WP_THREAD 8
#define WP_MBOX 16
static uint_t wrsm_plat_debug = 0;
#else
#define DPRINTF(a, b) { }
#endif
/* this variable allows for runtime changes of the use of the mailbox */
/* Converts a 10-bit safari port id to its 4-bit SSM node id */
/*
* Module linkage information for the kernel.
*/
"Sun Fire wrsm platmod %I%"
};
static struct modlinkage modlinkage = {
};
typedef struct wrsmplat_mbox_msg {
void *msg_data;
struct wrsmplat_mbox_msg *next;
/*
* If stop_thread is set for a particular link of a wci, that means that
* the thread trying to bringup that link should give up and exit.
*/
typedef struct wrsmplat_link {
typedef struct wrsmplat_wci {
static struct wrsmplat_state {
} wrsmplat_state = {0};
/*
* serengeti implementations of these functions are empty since
* for serengeti cesr ids can be specified in 6 bits given the
* maximum of 48 cores
*/
void
wrsmplat_set_asi_cesr_id(void)
{
}
void
wrsmplat_clr_asi_cesr_id(void)
{
}
/* support when SC is not available */
static void
{
int i;
wrsmplat_link_t *l;
for (i = 0; i < WRSM_MAX_WCIS; i++) {
mutex_enter(&l->mutex);
while (l->thread_active) {
"stop_thread: wci %d link %d "
"waiting for thread to stop",
l->stop_thread = B_TRUE;
}
mutex_exit(&l->mutex);
"wci %d link %d thread stopped",
break;
}
}
}
static void
{
int i;
wrsmplat_link_t *l;
/* First, look to see if WCI already exists */
for (i = 0; i < WRSM_MAX_WCIS; i++) {
/* Don't start the thread if wci was suspended */
"suspended, can't start thread", wci_id));
return;
}
mutex_enter(&l->mutex);
if (l->thread_active) {
mutex_exit(&l->mutex);
return;
}
l->thread_active = B_TRUE;
l->stop_thread = B_FALSE;
mutex_exit(&l->mutex);
break;
}
}
/* If not, then search for free space and add wci to the list */
if (!found) {
for (i = 0; i < WRSM_MAX_WCIS; i++) {
NULL);
l->thread_active = B_TRUE;
l->stop_thread = B_FALSE;
wci_id));
break;
}
}
}
"start_thread: wci %d, link %d, thread #%d",
/* LINTED - E_NOP_ELSE_STMT */
} else {
}
}
static void
{
int i;
wrsmplat_link_t *l;
for (i = 0; i < WRSM_MAX_WCIS; i++) {
mutex_enter(&l->mutex);
l->thread_active = B_FALSE;
cv_broadcast(&l->cv);
mutex_exit(&l->mutex);
}
}
"exiting for wci %d link %d. There are %d threads left",
thread_exit();
}
static boolean_t
{
int i;
if (wrsmplat_state.thread_stop) {
return (B_TRUE);
}
for (i = 0; i < WRSM_MAX_WCIS; i++) {
}
}
return (B_FALSE);
}
/* Use default timeout */
#define SC_TIMEOUT_SEC MBOX_DEFAULT_TIMEOUT
static wrsmplat_mbox_msg_t *dequeue_msg(void);
static void process_message(void);
static void wrsmplat_thread(void *arg);
/* used to start a thread */
typedef struct wrsmplat_thread_data {
int
_init(void)
{
int rc = 0;
if (!wrsm_use_sgsbbc) {
}
sizeof (wrsmplat_state.junk_stuff);
!= 0) {
return (rc);
}
MUTEX_DRIVER, NULL);
MUTEX_DRIVER, NULL);
return (rc);
}
return (0);
}
int
_fini(void)
{
int rc;
return (rc);
}
/*
* This blocks waiting for all the child threads to die
*/
(void) wrsmplat_unreg_callbacks();
return (0);
}
int
{
}
/*
* Handle asynchronous messages from the SC up to the kernel
*/
/* ARGSUSED */
{
" type=%d, sub-type: %d status = %d, length= %d, data=%x %x",
} else {
switch (linkisup_msg->async_msg_type) {
case LINKISUP:
"wci %d link %d",
/* put this message on a queue to be handled later */
sizeof (linkisup_msg->link_info));
break;
default:
" unhandled async_msg_type");
}
}
return (0);
}
wrsmplat_get_node_type(void)
{
return (node_type);
}
int
{
wrsm_uplink_msg_t msg = {0};
return (0);
}
int
{
wrsm_link_msg_t msg = {0};
return (0);
}
int
{
return (EINVAL);
&wrsm_regs);
if (!wrsm_regs)
return (ENXIO);
return (EAGAIN);
return (0);
}
int
{
wrsm_link_led_msg_t msg = {0};
return (0);
}
int
{
wrsm_ncslice_claim_msg_t msg = {0};
wrsm_ncslice_claim_msg_t answer = {0};
sbbc_msg_t request = {0};
sbbc_msg_t response = {0};
int rc;
int i;
ncslice_bitmask_t allocated = {0};
if (wrsm_use_sgsbbc) {
SC_TIMEOUT_SEC)) != 0) {
} else {
if (response.msg_status) {
"from NCSLICE request",
}
}
return (rc);
} else {
/*
* We are only allowed to use NC slices 161 to 254,
* and 0 is reserved.
*/
if (WRSM_IN_SET(requested, i))
WRSMSET_ADD(allocated, i);
return (0);
}
}
int
{
if (length > WIB_SEPROM_MSG_SIZE)
return (EINVAL);
return (0);
}
int
{
"called more than once"));
return (EEXIST);
}
/*
* no need to lock the thread count:
* when using the mailbox : only one thread exists
* not using the mailbox : the wrsmplat thread starts other threads
*/
return (0);
}
int
wrsmplat_unreg_callbacks(void)
{
/* Wake up the message thread */
/*
* Eventually, all of the threads should wake up, notice the
* thread_stop flag is set and exit. When they have all
* finished, the count should go to zero and it is safe to
* proceed. In case of not using SBBC ther is only one thread.
*/
while (wrsmplat_state.thread_count > 0) {
}
return (0);
}
static void
{
wrsmplat_mbox_msg_t *entry, *p;
else {
p = wrsmplat_state.msg_queue;
p = p->next;
}
msg_type));
msg_type));
}
static wrsmplat_mbox_msg_t *
dequeue_msg(void)
{
return (msg);
}
/* ARGSUSED */
static void
wrsmplat_thread(void *arg)
{
/* LINTED */
while (1) {
/* go to sleep waiting for the next message */
if (wrsmplat_state.thread_stop) {
process_message(); /* finish any waiting messages */
if (!wrsm_use_sgsbbc) { /* there > 1 thread */
}
/* in SBBC case there is only one thread */
if (!wrsm_use_sgsbbc) {
}
thread_exit();
}
}
}
static void
process_message(void)
{
wrsm_link_msg_t question = {0};
wrsm_uplink_msg_t answer = {0};
sbbc_msg_t request = {0};
sbbc_msg_t response = {0};
int rc = 0;
/* LINTED */
while (entry = dequeue_msg()) {
case LINKISUP: {
/* this is the message from SC, need to get more data */
&response, SC_TIMEOUT_SEC)) != 0) {
"failed rc=%d", rc);
break;
}
if (response.msg_status) {
"from LINKDATA request",
}
"link %d fmnid %d gnid %d alink %d port %d "
(msg->wci_port_id,
break;
}
case UPLINK: {
/* this is a message to be sent to SC */
if (wrsm_use_sgsbbc) {
&response, SC_TIMEOUT_SEC)) != 0) {
"sbbc_mbox_request_response "
"failed rc=%d", rc);
}
if (response.msg_status ==
"SC reports mismatch fmnodeid");
} else if (response.msg_status) {
"unrecognized error status %d "
"from UPLINK request",
}
} else {
sizeof (wrsmplat_thread_data_t), KM_SLEEP);
(umsg->wci_port_id,
&thread_data->wrsm_regs);
if (!thread_data->wrsm_regs) {
"UPLINK: failed to get register "
"base"));
return;
}
}
break;
}
case DOWNLINK: {
/* this is a message to be sent to SC */
if (wrsm_use_sgsbbc) {
&response, SC_TIMEOUT_SEC)) != 0) {
"sbbc_mbox_request_response failed "
"rc=%d", rc);
}
if (response.msg_status ==
"SC reports hardware failure for "
"DOWNLINK request");
} else if (response.msg_status) {
"DOWNLINK request",
}
/* should not call link_down for loopback */
(msg->wci_port_id,
} else {
(msg->wci_port_id,
&wrsm_regs);
if (wrsm_regs) {
/* LINTED - E_NOP_ELSE_STMT */
} else {
"DOWNLINK: failed to get register "
"base"));
}
/* should not call link_down for loopback */
(msg->wci_port_id,
}
break;
}
case SETLEDSTATE: {
/* this is a message to be sent to SC */
if (wrsm_use_sgsbbc) {
&response, SC_TIMEOUT_SEC)) != 0) {
"sbbc_mbox_request_response failed "
"rc=%d", rc);
}
if (response.msg_status ==
"SC reports hardware failure for "
"SETLEDSTATE request");
} else if (response.msg_status) {
"SETLEDSTATE request",
}
}
break;
}
case SETSEPROM: {
/* this is a message to be sent to SC */
if (wrsm_use_sgsbbc) {
sizeof (wrsm_wib_seprom_msg_t);
&response, SC_TIMEOUT_SEC)) != 0) {
"sbbc_mbox_request_response failed "
"rc=%d", rc);
}
if (response.msg_status ==
"SC reports hardware failure for "
"SETSEPROM request");
} else if (response.msg_status) {
"SETSEPROM request",
}
}
break;
}
case NCSLICE: {
/* NOT HANDLED HERE */
break;
}
default :
}
if (free_msg)
}
}
static uint64_t
{
}
static void
{
}
/* ARGSUSED */
void
{
/*
* wci_qlim_3req_priority, wci_qlim_2req_priority,
* wci_qlim_sort_ciq, wci_qlim_sort_niq, and wci_qlim_sort_piq
* need to be updated if this cluster node is part of a
* wildcat SSM.
*/
}
void
{
}
void
{
#ifdef DEBUG
#endif /* DEBUG */
/* LINTED */
}
#ifdef DEBUG
(void *)pa));
#endif
}
}
/*
* Set the link to in use mode and, turn on the transmitters,
* and clear out the error count.
*/
error_count.val = 0;
/*
* We can send 16 bits to the far side via usr_data_1, it is
* encoded as follows:
* 0-7: gnid
* 8-12: portid
* 13-15: linknum
*/
/*
* Spin waiting for the remote side to set the user_data_2
*/
}
}
/* XXX - just to be sure the link settles down */
}
}
}
/*
* Don't make the callback if the link is supposed to
* be in loopback mode.
*/
} else {
}
}
void
{
switch (link) {
case 0:
break;
case 1:
break;
case 2:
break;
default:
link));
break;
}
/* read back to commit the write */
}
int
{
int checks;
int good_tnid;
int tnid;
if (link_id >= WRSM_LINKS_PER_WCI) {
}
/* Clear error bits corresponding to this link */
sw_esr_mask.val = 0;
case 0:
break;
case 1:
break;
case 2:
break;
}
/* read it back to make sure the write happened */
"Trying to bring up link %d wci %d",
/*
* The max paroli reset setup time is 100ms. Putting the link
* into STATE_SEEK brings the paroli out of reset, so we have
* to wait 100ms before we can expect anything useful from the
* status register
*/
/* Wait for optical_signal_detect to come on */
count = 0;
++count;
if (count >= 200) {
"signal detect link %d wci %d",
return (-1);
}
/* sleep 250ms */
}
}
"Trying tnid %d", tnid));
/*
* There is some probability <1 that the end_status
* will be reported correctly in the link_status
* register. Dave Saterfield guesses ~60% but it
* could be a lot worse if there is much clock skew
* between machines. It should only give false
* negative, not false positive results. So we try a
* few times and if it ever says "ready" then we declare
* success.
*/
break;
}
}
if (good_tnid) {
break;
}
}
#ifdef DEBUG
if (tnid == 16) {
} else {
"link %d wci %d retries %d", tnid,
}
#endif /* DEBUG */
/*
* If we didn't find the right tnid, the link must be in a bad
* state, so reset and try again.
*/
if (!good_tnid)
return (-1);
error_count.val = 0;
#ifndef NEW_PAROLIS_ONLY
#endif /* NEW_PAROLIS_ONLY */
}
statAddr);
continue;
eCntAddr);
/*
* if it's still up and error count is
* not too high, declare success
*/
return (0);
} else {
"high error count %" PRIx64
" status = %" PRIx64,
link_status.val));
return (-1);
}
}
}
}
}
return (-1);
}
/*
* Verifies valid stripegroup. For Serengeti, all wcis must be in same
* SSM node.
*/
int
{
int ssmnode;
int i;
return (0);
}
return (ENOTSUP);
}
}
return (0);
}
/*
* If in an SSM, configures SSM-mode WCIs to route appropriate ncslices
* to the right local domain. For non-SSM Serengeti, no action is required.
*/
/* ARGSUSED */
void
{
/* XXX - SSM case not yet implemented */
}
/*
* Enter ncslice update critical section - no action for non-SSM Serengeti.
*/
void
wrsmplat_ncslice_enter(void)
{
}
/*
* Exit ncslice update critical section - no action for non-SSM Serengeti.
*/
void
wrsmplat_ncslice_exit(void)
{
}
/* Does a cross-trap sync */
void
wrsmplat_xt_sync(int cpu_id)
{
}
void
{
if (!wrsm_use_sgsbbc) {
int i;
int link;
for (i = 0; i < WRSM_MAX_WCIS; i++) {
return;
}
break;
}
}
}
}
}
void
{
/*
* No need to restart link bring-up thread, since driver will
* eventually time-out and retry later.
*/
if (!wrsm_use_sgsbbc) {
int i;
for (i = 0; i < WRSM_MAX_WCIS; i++) {
break;
}
}
}
}