1
0
Files
2022-09-29 17:59:04 +03:00

650 lines
14 KiB
C

/**************************************************************************
* *
* Copyright (C) 1992-1996, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#ident "$Revision: 1.11 $"
/*
* pgdrv.c - promgraph driver interface.
*/
#include <sys/types.h>
#include <sys/PCI/bridge.h> /* for the GET_PCI stuff ... */
#include <sys/SN/addrs.h>
#include <sys/graph.h>
#include <sys/hwgraph.h>
#include <promgraph.h>
#include <sys/iograph.h>
#include <sys/SN/SN0/klhwinit.h>
#include <arcs/hinv.h>
#include <arcs/eiob.h>
#include <prom_msgs.h>
#include <libsc.h>
#include <pgdrv.h>
#ifdef SN_PDI
extern graph_hdl_t pg_hdl ;
extern vertex_hdl_t snpdi_rvhdl ;
#define REPORT_ERR 1
/*
* promDrvTab
*
* This table contains info about all drivers
* configured into the prom - like the unix
* 'devsw' tables.
*/
#define MAX_PROM_DRIVERS 32
prom_drv_t *promDrvTab[MAX_PROM_DRIVERS] ;
/* Driver interface routines vector definitions. */
#include "pgdrvinst.c"
/*
* This routine creates the 'devsw' tables for PROM.
*/
void
pgDrvTabInit(void)
{
int i ;
for (i=0;i<MAX_PROM_DRIVERS;i++)
promDrvTab[i] = 0 ;
/* NOTE : promDrvTab[SHOULD NOT EXCEED MAX_PROM_DRIVERS] */
promDrvTab[0] = &ql_drv_info ;
promDrvTab[1] = &ioc3_drv_info ;
promDrvTab[2] = &ef_drv_info ;
promDrvTab[3] = &tty_drv_info ;
promDrvTab[4] = &pckm_drv_info ;
#if defined(SN0PROM) || defined(SN0XXLPROM)
promDrvTab[5] = &kona_drv_info ;
promDrvTab[6] = &mgras_drv_info ;
#endif
/* Add new drivers here */
}
/*
* Search the prom registered driver table for an
* entry based on the keys.
*/
int
pgGetDrvTabIndex(int key1, int key2, char *strkey)
{
prom_drv_t **pdp ;
int indx = 0 ;
int kp1, kp2, kp3 ; /* key present? */
int kc1, kc2, kc3 ; /* key condition */
kp1 = (key1 != -1) ;
kp2 = (key2 != -1) ;
kp3 = (strkey != NULL) ;
if (!(kp1 || kp2 || kp3))
return -1 ;
pdp = promDrvTab ;
while (*pdp) {
prom_drv_t *pd ;
pd = *pdp ;
if (kp1)
kc1 = (key1 == pd->key1) ;
else
kc1 = 1 ;
if (kp2)
kc2 = (key2 == pd->key2) ;
else
kc2 = 1 ;
if (kp3)
kc3 = ((pd->strkey) && !strcmp(strkey, pd->strkey)) ;
else
kc3 = 1 ;
if (kc1 && kc2 && kc3) {
return indx ;
}
pdp ++ ;
indx ++ ;
}
return -1 ;
}
/*
* Get both the prom driver entry pointer and index.
*/
prom_drv_t *
pgGetDrvTabPtrIndx(int key1, int key2, char *strkey, int *indxp)
{
int indx ;
if ((indx = pgGetDrvTabIndex(key1, key2, strkey)) < 0)
return NULL ;
*indxp = indx ;
return(promDrvTab[indx]) ;
}
/*
* make_COMP_Key
*
* A Key is a ULONG that has info about a IO device
* encoded in it, like widget id, nasid, hub widget id.
* Used to calculate a dma addr for a pci device.
*/
ULONG
make_COMP_Key(klinfo_t *k, int ctrl_id)
{
__psunsigned_t hb ;
int hw ;
ULONG Key ;
Key = 0 ;
Key |= ctrl_id ;
Key |= MK_SN0_KEY(k->nasid, k->widid, k->physid) ;
hb = (__psunsigned_t) REMOTE_HUB(k->nasid, 0) ;
hw = GET_FIELD64((hb + IIO_WIDGET_CTRL), WIDGET_ID_MASK, 0) ;
ADD_HUBWID_KEY(Key, hw) ;
ADD_HSTNASID_KEY(Key, get_nasid()) ;
return Key ;
}
/*
* pgCreatePd
*
* Create a prom driv struct and zero it.
*/
void *
pgCreatePd(int size)
{
void *tmp ;
tmp = (void *)malloc(size) ;
if (tmp != NULL)
bzero(tmp, size) ;
return tmp ;
}
int sn_pass ; /* Checks for multiple inits */
/*
* pgDevInit
*
* Calls init routine of all drivers.
*/
int
pgDevInit(void *arg, vertex_hdl_t vhdl)
{
pd_info_t *pdi ;
register struct eiob *io ;
graph_error_t ge ;
pdi = (pd_info_t *)pg_get_lbl(vhdl, INFO_LBL_DRIVER) ;
if (pdi == NULL)
return 0 ;
if (!IS_PD_INSTALLED(pdi))
return 0 ;
if ((io = new_eiob()) == NULL)
return 1 ;
io->iob.Controller = pdi->pdi_ctrl_id ;
io->iob.FunctionCode = FC_INITIALIZE;
io->iob.Count = sn_pass ;
if (pdiStrat(pdi))
if ((*pdiStrat(pdi))(&pdiArcsComp(pdi), &io->iob) != 0)
/* XXX check if ac->flag is set */ ;
/*
* The flag of the device needs to be set to fail if
* init failed. This is because, when we Open a device the
* INFO_LBL_DEVICE gets opened. But here we have the klinfo_t
* of the driver.
* This flag is checked in parse_path. Since on SN, the
* driver inits are fairly simple and are mostly successful
* we do not set this flag and let Open continue. It will
* encounter a problem somewhere else, if there is a real
* hw failure. Also, in critical cases like console, if init
* has a problem we have to panic.
*/
/*
* In the SN prom there is no place to call tpsc init and
* tpsc uses the same ql driver, but different processing.
* So, call tpsc_strat here if we are dealing with dksc.
*/
#if 0
if (pdiStrat(pdi) == dksc_strat) {
tpsc_strat(&pdiArcsComp(pdi), &io->iob) ;
}
#endif
free_eiob(io) ;
return 0 ; /* continue for all nodes */
}
void
sn_init_devices(void)
{
vertex_hdl_t nv ;
graph_error_t ge ;
printf("sn Initializing devices...\n") ;
sn_pass ++ ;
graph_vertex_visit(pg_hdl, pgDevInit, &snpdi_rvhdl,
&ge, &nv) ;
}
/*
* pgInitPdih
*
*/
void
pgInitPdih(pd_inst_hdl_t *pdih, vertex_hdl_t v, pd_info_t *pdi)
{
pdih->pdih_magic = PDIH_MAGIC ;
pdih->pdih_ctrl_v = v ;
pdih->pdih_pdi = pdi ;
}
pd_inst_hdl_t *
pgMakeInstHdl(vertex_hdl_t v, pd_info_t *pdi)
{
pd_inst_hdl_t *pdih ;
pdih = (pd_inst_hdl_t *)pgCreatePd(sizeof(pd_inst_hdl_t)) ;
if (pdih)
pgInitPdih(pdih, v, pdi) ;
return pdih ;
}
void *
make_inst_parm(drv_inst_info_t *drvii, lboard_t *lb, klinfo_t *k)
{
ULONG Key ;
drvii->drvii_ctrl_id = 0 ;
Key = make_COMP_Key(k, drvii->drvii_ctrl_id) ;
drvii->drvii_cfg_base = GET_PCICFGBASE_FROM_KEY(Key);
drvii->drvii_mem_base = GET_PCIBASE_FROM_KEY(Key);
drvii->drvii_dma_parm = Key ;
#if 0
/* XXX this is a side effect and needs to be cleared */
k->virtid = drvii->drvii_ctrl_id ;
k->arcs_compt = (COMPONENT *)malloc(sizeof(COMPONENT)) ;
#endif
return (void *)drvii ;
}
pd_inst_parm_t *
pgMakeInstParm(pd_info_t *pdi)
{
pd_inst_parm_t *pdip ;
pdip = (pd_inst_parm_t *)pgCreatePd(sizeof(pd_inst_parm_t)) ;
if (pdip == NULL)
goto MIP_done ;
/* assigns ctrl id */
if (pdiMakeInstParm(pdi)) {
(*pdiMakeInstParm(pdi))(&pdip->pdip_drvii,
pdiLb(pdi), pdiK(pdi)) ;
}
else {
make_inst_parm(&pdip->pdip_drvii, pdiLb(pdi), pdiK(pdi)) ;
}
/* back propagate the ctrl_id and other stuff to the pdi */
if (pdiMakeInstParm(pdi)) {
pdiCtrlId(pdi) = pdipCtrlId(pdip) ;
if (pdiK(pdi)->arcs_compt)
bcopy(pdiK(pdi)->arcs_compt,
&pdiArcsComp(pdi), sizeof(COMPONENT)) ;
}
MIP_done:
return pdip ;
}
int
gen_inst_check(klinfo_t *k)
{
if ( (k->flags & (KLINFO_INSTALL|KLINFO_ENABLE)) ==
(KLINFO_INSTALL|KLINFO_ENABLE))
return 1 ;
return 0 ;
}
/*
* pgCallInstall
*
* Called to install a driver for a controller.
* Called only if the check install callback
* returns OK.
*/
void *
pgDoInstall(vertex_hdl_t v, pd_info_t *pdi)
{
pd_inst_hdl_t *pdih ;
pd_inst_parm_t *pdip ;
if (!gen_inst_check(pdiK(pdi)))
return NULL ;
/*
* If the user has supplied a check_install routine use it.
* The default is to go ahead and install.
*/
if (pdiCheckInstall(pdi))
if (!(*pdiCheckInstall(pdi))(pdiLb(pdi), pdiK(pdi)))
return NULL ;
/* Make inst handle */
pdih = pgMakeInstHdl(v, pdi) ;
if (pdih == NULL) {
return NULL ;
}
/* Make install parm */
pdip = (pd_inst_parm_t *)pgMakeInstParm(pdi) ;
if (pdip == NULL) {
return NULL ;
}
(*pdiInstall(pdi))(pdih, pdip) ;
free(pdih) ;
free(pdip) ;
return (void *)pdi ;
}
int
pgCallInstall(void *arg, vertex_hdl_t v)
{
pd_info_t *pdi ;
pdi = (pd_info_t *)pg_get_lbl(v, INFO_LBL_DRIVER) ;
if (pdi == NULL)
return 0 ;
if (pgDoInstall(v, pdi) == NULL)
return NULL ;
/* Set status of the driver */
pdi->pdi_flags |= PDI_INSTALLED ;
return 0 ;
}
void
pgDriverRegister()
{
vertex_hdl_t nv ;
graph_error_t ge ;
graph_vertex_visit(pg_hdl, pgCallInstall,
&snpdi_rvhdl, &ge, &nv) ;
}
pd_dev_info_t *
pgMakePdev(pd_inst_hdl_t *pdih, pd_inst_parm_t *pdip)
{
pd_dev_info_t *pdev ;
dev_inst_info_t *devii = (dev_inst_info_t *)&pdip->pdip_devii ;
/* alloc a dev info struct */
pdev = (pd_dev_info_t *)pgCreatePd(sizeof(pd_dev_info_t)) ;
if (!pdev)
goto MPDEV_done ;
/* Copy the pdi of the controller */
bcopy(pdih->pdih_pdi, &pdev->pdev_pdi, sizeof(pd_info_t)) ;
/* zero the pdi_k ptr. It was pointing to the ctrl klinfo */
pdev->pdev_pdi.pdi_k = 0 ;
/* controller id from inst handle */
pdev->pdev_pdp.pdp_ctrl = pdih->pdih_pdi->pdi_ctrl_id ;
/* unit from dev inst info */
pdev->pdev_pdp.pdp_type = GET_DEV_CLASS(devii->devii_c.Type) ;
pdev->pdev_pdp.pdp_unit = devii->devii_unit ;
pdev->pdev_pdp.pdp_lun = devii->devii_lun ;
pdev->pdev_pdp.pdp_part = 0 ;
pdev->pdev_devii = *devii ; /* struct assign */
MPDEV_done:
return pdev ;
}
/*
* snAddChild
*
* Called by the device driver install routine for every
* device found. The driver add child needs to grow a
* fancy path for the device from ctrl_v, using the info
* returned by the driver install in devii. It also has to
* make the required sncfg, using the pdih->pdih_pdi->init_sncfg
* routine.
*/
void
snAddChild(pd_inst_hdl_t *pdih, pd_inst_parm_t *pdip)
{
pd_dev_info_t *pdev ;
vertex_hdl_t dev_v ;
klinfo_t *k = NULL ;
dev_inst_info_t *devii = (dev_inst_info_t *)&pdip->pdip_devii ;
if (!IS_DEVICE_PSEUDO(pdip)) {
pdev = pgMakePdev(pdih, pdip) ;
if (!pdev)
return ;
}
else
pdev = NULL ;
/* Call driver supplied add child routine to
extend the graph, and represent the new device */
if (pdiSnAddChild(pdih->pdih_pdi))
(*pdiSnAddChild(pdih->pdih_pdi))(pdev,
pdih->pdih_ctrl_v, (void *)devii) ;
}
vertex_hdl_t
snAddChildPostOp(pd_dev_info_t *pdev,
vertex_hdl_t ctrl_v,
char *path,
klinfo_t *k,
dev_inst_info_t *devii)
{
vertex_hdl_t dev_v ;
#if 0
COMPONENT *c = &devii->devii_c ;
#endif
/* Update some new stuff from dev specific add child */
/* XXX If dev specific add child updates any info
in devii, it needs to be copied here. */
if (pdev)
pdev->pdev_pdi.pdi_k = k ;
/*
* create the rest of the path as required
* by the driver. If *path is null it means
* that the caller has created the full
* path and passed in the leaf vertex as ctrl_v.
*/
if (*path)
dev_v = create_graph_path(ctrl_v, path, 1) ;
else
dev_v = ctrl_v ;
/*
* Hang the 2 required prom labels off of the vertex
* that represents the device.
*/
if (k)
pg_add_lbl(dev_v, INFO_LBL_KLCFG_INFO, (void *)k) ;
if (pdev)
pg_add_lbl(dev_v, INFO_LBL_DEVICE, (void *)pdev) ;
return dev_v ;
}
int
check_install_once(int *once_flag)
{
if (*once_flag) {
return 0 ;
}
else {
*once_flag = 1 ;
return 1 ;
}
}
static klinfo_t *
sn_init_device_graph(pd_dev_info_t *pdev, vertex_hdl_t ctlr_v, int dev_type)
{
klinfo_t *dev_k = NULL ;
pd_info_t *pdi = &pdev->pdev_pdi ;
void *(*fptr)() ;
graph_error_t ge ;
/* XXX we need to get the ctlr_k here some how.
Ultimately, we need to eliminate the need for the
ctlr k here.
*/
klinfo_t *ctlr_k = NULL ;
ge = graph_info_get_LBL(pg_hdl,
ctlr_v,
INFO_LBL_KLCFG_INFO, NULL,
(arbitrary_info_t *)&ctlr_k) ;
if (ge != GRAPH_SUCCESS)
return NULL ;
fptr = NULL ;
if (pdev)
if ((fptr = pdiInitDevSncfg(pdi)) == NULL)
/* XXX need a generic routine here, input - k */
;
/* dev_type is ignored by most functions except scsi, kbd */
if (fptr)
dev_k = (klinfo_t *)(*fptr)(ctlr_k, dev_type) ;
return(dev_k) ;
}
klinfo_t *
sn_make_dev_klcfg(pd_dev_info_t *pdev, vertex_hdl_t v, int type, COMPONENT *c)
{
klinfo_t *k ;
COMPONENT *ac ;
k = (klinfo_t *)sn_init_device_graph(pdev, v, type) ;
if (k == NULL)
return NULL ;
ac = (COMPONENT *)malloc(sizeof(COMPONENT)) ;
if (ac == NULL)
return NULL ;
bzero(ac, sizeof(COMPONENT)) ;
bcopy(c, ac, sizeof(COMPONENT)) ;
k->arcs_compt = ac ;
return k ;
}
/*
* Typical AddChild for a device.
* Use this unless a device has
* specific requirements.
*/
vertex_hdl_t
snDevAddChild( pd_dev_info_t *pdev ,
vertex_hdl_t v ,
dev_inst_info_t *devii ,
char *path ,
int type ,
COMPONENT *c)
{
char tpath[128] ;
klinfo_t *k ;
pd_info_t *pdi = &pdev->pdev_pdi ;
strcpy(tpath, path) ;
k = sn_make_dev_klcfg(pdev, v, type, c) ;
if (k)
k->physid = devii->devii_unit ;
return(snAddChildPostOp(pdev, v, path, (klinfo_t *)k, devii)) ;
}
#endif SN_PDI