sgsbbc_iosram.c revision 03831d35f7499c87d51205817c93e9a8d42c4bae
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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"
/*
* Driver for handling Serengeti I/O SRAM
* for Solaris <-> SC comm.
*/
#include <sys/dditypes.h>
#include <sys/sysmacros.h>
#include <sys/prom_plat.h>
#include <sys/serengeti.h>
#include <sys/sgsbbc_priv.h>
#include <sys/sgsbbc_iosram_priv.h>
#include <sys/sgsbbc_mailbox_priv.h>
/*
* Local stuff
*/
static int iosram_convert_key(char *);
static int iosram_switch_intr(void);
static void tunnel_fini(tunnel_t *);
static void clear_break();
/* CSTYLED */ \
/* CSTYLED */ \
/* CSTYLED */ \
/* CSTYLED */ \
/*
* sgsbbc_iosram_is_chosen(struct sbbc_softstate *softsp)
*
* Looks up "chosen" node property to
* determine if it is the chosen IOSRAM.
*/
int
{
char pn[MAXNAMELEN];
char chosen_iosram[MAXNAMELEN];
int nodeid;
int chosen;
extern pnode_t chosen_nodeid;
/*
* get the full OBP pathname of this node
*/
sizeof (chosen_iosram)) < 0) {
return (0);
}
SGSBBC_DBG_ALL("sgsbbc_iosram(%d): prom_phandle_to_path(%x) is '%s'\n",
SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ddi_pathname(%p) is '%s'\n",
return (chosen);
}
void
{
int i;
KM_NOSLEEP)) == NULL) {
prom_printf("Can't allocate space for Chosen IOSRAM\n");
panic("Can't allocate space for Chosen IOSRAM");
}
KM_NOSLEEP)) == NULL) {
prom_printf("Can't allocate space for tunnel\n");
panic("Can't allocate space for tunnel");
}
for (i = 0; i < SBBC_MAX_KEYS; i++) {
}
for (i = 0; i < SBBC_MAX_INTRS; i++)
}
void
{
struct tunnel_key *tunnel;
int i;
/*
* destroy any tunnel maps
*/
for (i = 0; i < SBBC_MAX_KEYS; i++) {
}
}
}
static void
{
panic("Up-rev System Controller version.\n"
"You must restore an earlier revision of System "
"Controller firmware, or upgrade Solaris.\n"
"Please consult the System Controller release notice "
"for additional details.");
}
}
static void
{
/*
* SBBC has pointer to interrupt handlers for simplicity
*/
}
static int
{
int i, key;
struct tunnel_key *tunnel;
struct ddi_device_acc_attr attr;
return (DDI_FAILURE);
}
SGSBBC_DBG_ALL("map in the IOSRAM TOC at offset %x\n",
/*
* First map in the TOC, then set up the tunnel
*/
sizeof (struct iosram_toc),
return (DDI_FAILURE);
}
for (i = 0; i < toc->iosram_tagno; i++) {
/*
* map in the SRAM area using the offset
* from the base of SRAM + SRAM offset into
* the register property for the SBBC base
* address
*/
return (DDI_FAILURE);
}
SGSBBC_DBG_ALL("%d: key %s size %d offset %x addr %p\n",
}
}
}
/*
* Set up the 'interrupt reason' SRAM pointers
* for the SBBC interrupt handler
*/
/*
* Can't really do much if these are not here
*/
prom_printf("No Interrupt Reason Fields set by SC\n");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Unmap a tunnel
*/
static void
{
int i;
struct tunnel_key *tunnel_key;
/*
* Unmap the tunnel
*/
for (i = 0; i < SBBC_MAX_KEYS; i++) {
}
}
}
static void
{
struct tunnel_key tunnel_key;
}
int
{
int rc;
clear_break();
}
return (rc);
}
int
{
}
int
{
}
static int
{
struct tunnel_key *tunnel;
/*
*/
if (size == 0)
return (0);
/*
* Key not matched ?
*/
return (ENXIO);
}
return (EFBIG);
}
/*
* We assume that such clients could guarantee their buffers
* are aligned at the boundary of the request sizes. We also
* assume that the source/destination of such requests are
* aligned at the right boundaries in IOSRAM. If either
* condition fails, byte access is performed.
*/
switch (size) {
case sizeof (uint16_t):
case sizeof (uint32_t):
case sizeof (uint64_t):
else
break;
}
/* FALLTHRU */
default:
break;
}
} else {
switch (size) {
case sizeof (uint16_t):
case sizeof (uint32_t):
case sizeof (uint64_t):
else
break;
}
/* FALLTHRU */
default:
break;
}
}
return (0);
}
int
iosram_size(int key)
{
int size = -1;
/*
* Key not matched ?
*/
return (size);
}
/*
* Generate an interrupt to the SC using the SBBC EPLD
*
* Note: intr_num can be multiple interrupts OR'ed together
*/
int
{
int rc = 0;
/*
* Verify that we have already set up the master sbbc
*/
if (master_iosram == NULL)
return (ENXIO);
/*
* Grab the lock to prevent tunnel switch in the middle
* of sending an interrupt.
*/
goto send_intr_exit;
}
/*
* previous interrupts have not been cleared yet by the SC
*/
goto send_intr_exit;
}
/*
* Set a bit in the interrupt reason field
* call back into the sbbc handler to hit the EPLD
*
* First check the interrupts enabled by the SC
*/
goto send_intr_exit;
}
/*
* at least one of the interrupts is
* not enabled by the SC
*/
goto send_intr_exit;
}
goto send_intr_exit;
}
/*
* All interrupts specified are already pending
*/
goto send_intr_exit;
}
intr_reason |= intr_num;
goto send_intr_exit;
}
/*
* Hit the EPLD interrupt bit
*/
return (rc);
}
/*
* Register an interrupt handler
*/
int
{
int rc = 0;
int intr_no;
/*
* Verify that we have already set up the master sbbc
*/
if (master_iosram == NULL)
return (ENXIO);
/*
* determine which bit is this intr_num for ?
*/
break;
}
/*
* Check the parameters
*/
return (EINVAL);
return (ENXIO);
}
goto reg_intr_exit;
}
/*
* we need to make sure that the mutex is for
* an ADAPTIVE lock, so call mutex_init() again with
* the sbbc iblock cookie
*/
goto reg_intr_exit;
}
/*
* Set the bit in the Interrupts Enabled Field for this
* interrupt
*/
goto reg_intr_exit;
}
intr_enabled |= intr_num;
goto reg_intr_exit;
}
return (rc);
}
/*
* Remove an interrupt handler
*/
int
{
int rc = 0;
int intr_no;
/*
* Verify that we have already set up the master sbbc
*/
if (master_iosram == NULL)
return (ENXIO);
/*
* determine which bit is this intr_num for ?
*/
break;
}
return (EINVAL);
return (ENXIO);
}
/*
* No handler installed
*/
goto unreg_intr_exit;
}
/*
* Unset the bit in the Interrupts Enabled Field for this
* interrupt
*/
goto unreg_intr_exit;
}
intr_enabled &= ~intr_num;
goto unreg_intr_exit;
}
/*
* If handler is running, wait until it's done.
* It won't get triggered again because we disabled it above.
* When we wait, drop sbbc_lock so other interrupt handlers
* can still run.
*/
for (; ; ) {
} else {
break;
}
}
if (intr->sbbc_intr_id)
intr->sbbc_intr_id = 0;
return (rc);
}
/*
* sgsbbc_iosram_switchfrom(softsp)
* Switch master tunnel away from the specified instance.
*/
int
{
struct sbbc_softstate *sp;
int rv = DDI_FAILURE;
int new_instance;
/*
* Find the candidate target of tunnel from the linked list.
*/
continue;
continue;
break;
}
/* at least one IOSRAM should be attached */
rv = DDI_FAILURE;
} else {
/* Do the tunnel switch */
if (rv == DDI_SUCCESS) {
/* reset the chosen_iosram back ref */
}
}
return (rv);
}
/*
* Switch the tunnel to a different I/O board.
* At the moment, we will say that this is
* called with the instance of the SBBC to switch
* to. This will probably change, but as long as we
* doesn't matter what the parameter is.
*/
int
{
int portid;
int rc = DDI_SUCCESS;
static fn_t f = "iosram_switch_tunnel";
/* Check the firmware for tunnel switch support */
if (prom_test("SUNW,switch-tunnel") != 0) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
return (DDI_FAILURE);
/*
* create the new tunnel
*/
return (DDI_FAILURE);
}
"portid", -1)) < 0) {
SGSBBC_DBG_ALL("%s: couldn't get portid\n", f);
return (DDI_FAILURE);
}
/*
* Compute node id and board number from port id
*/
/*
* lock the chosen IOSRAM
*/
return (DDI_FAILURE);
}
/*
* If the target SBBC has not mapped in its
* register address space, do it now
*/
return (DDI_FAILURE);
}
}
/*
* Get a pointer to the current sbbc
*/
/*
* Disable interrupts from the SC now
*/
/*
* move SC interrupts to the new tunnel
*/
} else {
/*
* If OBP switch is unsuccessful, abort the switch.
*/
!= DDI_SUCCESS) {
/*
* Restart other CPUs.
*/
/*
* Remove interrupt
*/
/*
* Unmap new tunnel
*/
} else {
/*
* Remove interrupt from original softsp
*/
/*
* Unmap original tunnel
*/
/*
* Move the softintrs to the new dip.
*/
(void) iosram_switch_intr();
(void) sbbc_mbox_switch(to_softsp);
}
}
/*
* Enable interrupt.
*/
/*
* Unlock and get out
*/
/*
* Call the interrupt handler directly in case
* we have missed an interrupt
*/
if (rc != DDI_SUCCESS) {
/*
* Free up the new_tunnel
*/
}
return (rc);
}
/*
* convert an alphanumeric OBP key to
* our defined numeric keys
*/
static int
iosram_convert_key(char *toc_key)
{
return (SBBC_DOMAIN_KEY);
return (SBBC_KEYSWITCH_KEY);
return (SBBC_TOD_KEY);
return (SBBC_CONSOLE_KEY);
return (SBBC_MAILBOX_KEY);
return (SBBC_INTR_SC_KEY);
return (SBBC_SC_INTR_KEY);
return (SBBC_ENVCTRL_KEY);
return (SBBC_INTR_SC_ENABLED_KEY);
return (SBBC_SC_INTR_ENABLED_KEY);
return (SBBC_SIGBLCK_KEY);
/* Unknown key */
return (-1);
}
/*
* Move the software interrupts from the old dip to the new dip
* when doing tunnel switch.
*/
static int
{
int intr_no;
int rc = 0;
if (intr->sbbc_intr_id) {
!= DDI_SUCCESS) {
}
}
}
return (rc);
}