Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / devices / mmi / sam_dev.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: sam_dev.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)sam_dev.c 1.12 07/10/12 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <strings.h>
#include "basics.h"
#include "fatal.h"
#include "strutil.h"
#include "allocate.h"
#include "simcore.h"
#include "config.h"
#include "options.h"
#include "parser.h"
#include "fileutil.h"
#include "lexer.h"
#include "tsparcv9.h"
#include "tsparcv9internal.h"
#include "device.h"
#include "mmi.h"
#include "sam_dev.h"
void sam_parse_dev(domain_t* domainp, config_dev_t *config_devp);
void sam_init_device(char *dev_namep, config_dev_t *config_devp);
static void sam_set_default_args(mmi_data_t *mmi_datap);
static void sam_parse_args(mmi_data_t *mmi_datap);
static void sam_init_dev(config_dev_t *config_devp);
static void sam_dump_dev(config_dev_t *config_devp);
static tpaddr_t sam_dev_non_cacheable(config_addr_t *config_addrp, dev_access_t type,
tpaddr_t offset, uint8_t **blockp);
static bool_t sam_dev_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset,
maccess_t op, uint64_t *regp);
static simcpu_t *sam_find_simcpu(int cpuid);
/*
* Maps an address range in the domain to a SAM device, checking for overlap
*/
static void
sam_insert_address_range(domain_t * domainp, config_dev_t *config_devp,
tpaddr_t baseaddr, tpaddr_t topaddr) {
config_dev_t *overlapp;
insert_domain_address(domainp, config_devp, baseaddr, topaddr);
overlapp = insert_domain_device(domainp, config_devp);
if (overlapp != NULL) {
lex_fatal("device \"%s\" @ 0x%llx overlaps with device \"%s\" @ 0x%llx",
overlapp->dev_typep->dev_type_namep,
overlapp->addrp->baseaddr,
config_devp->dev_typep->dev_type_namep,
config_devp->addrp->baseaddr);
}
}
/*
* The SAM MMI device is parsed by the 'mmi_device' directive in
* the syntax of
*
* mmi_device <dev_name> <base_addr> + <size> {
* type <string>
* }
*
* Example:
*
* - use SAM MMI NIU device model for Niagara 2:
*
* mmi_device "n2niu" 0x8100000000 + 0x100000000;
*
* - use SAM MMI dumbserial device model:
*
* mmi_device "dumbserial-mmi" 0x1f10000000 + 0x50 {
* type HYPERVISOR;
* }
*/
void
sam_parse_dev(domain_t * domainp, config_dev_t *config_devp)
{
dev_type_t *dev_typep = (dev_type_t *)config_devp->dev_typep;
sam_device_t *sam_devp;
mmi_data_t *mmi_datap;
tpaddr_t baseaddr, size, topaddr;
bool_t is_size;
lexer_tok_t tok;
char *type, argv[BUFSIZ];
DBG(printf("sam_parse_dev: parsing device %d\n", config_devp->device_id); );
sam_devp = Xcalloc(1, sam_device_t);
mmi_datap = Xcalloc(1, mmi_data_t);
sam_devp->config_devp = config_devp;
sam_devp->mmi_datap = mmi_datap;
mmi_datap->modname = (char *)Xstrdup(dev_typep->dev_type_namep);
mmi_datap->argv = (char**) Xcalloc(MMI_MAX_ARGC, char**);
mmi_datap->argc = 0; /* Initialize argument count to 0 */
#if INTERNAL_BUILD
mmi_datap->scx = NULL; /* Initialize to NULL for most devices */
#endif
config_devp->devp = sam_devp;
pthread_mutex_init(&sam_devp->mmi_lock, NULL);
tok = lex_get_token();
if (tok == T_Number) {
lex_unget();
do {
lex_get(T_Number);
baseaddr = lex.val;
is_size = false;
tok = lex_get_token();
if (tok == T_Plus) {
/* Next value is size */
is_size = true;
} else {
/* Next value is end address */
lex_unget();
}
sprintf(argv, "base=0x%llx", baseaddr);
mmi_datap->argv[0] = Xstrdup(argv);
mmi_datap->argc = 1;
lex_get(T_Number);
if (is_size) {
topaddr = baseaddr + lex.val;
} else {
topaddr = lex.val;
}
sprintf(argv, "size=0x%llx", topaddr - baseaddr);
mmi_datap->argv[1] = Xstrdup(argv);
mmi_datap->argc = 2;
if (topaddr <= baseaddr)
lex_fatal("top address <= base address with device %s",
mmi_datap->modname);
/* Add the current address range into the domain address map */
sam_insert_address_range(domainp, config_devp, baseaddr, topaddr);
if (lex_get_token() == T_Comma) {
/*
* More address ranges to map to device.
* Allocate new control struct, but share device entry.
*/
config_devp = Xmalloc( sizeof(config_dev_t) );
config_devp->dev_typep = dev_typep;
config_devp->is_implied = false;
config_devp->addrp = NULL;
config_devp->devp = sam_devp;
} else {
break;
}
} while (1);
}
lex_unget();
sam_set_default_args(mmi_datap);
tok = lex_get_token();
switch (tok) {
case T_S_Colon:
return;
case T_L_Brace:
break;
default:
unexpected:
lex_fatal("sam_parse_dev: unexpected token encountered");
}
while ( (tok = lex_get_token()) != T_R_Brace) {
lex_unget();
sam_parse_args(mmi_datap);
}
}
static void sam_parse_args(mmi_data_t *mmi_datap)
{
lexer_tok_t tok;
char argv[BUFSIZ];
char libname[MAXPATHLEN];
#if INTERNAL_BUILD
/*
* This code only applies to Rock setups at the moment
* necessitating some complex linking code.
*/
if (strstr(mmi_datap->modname, HH)) {
scx_handle_t (*find_scx_device_fn)(char*);
scx_api *scx_ops;
tok = lex_get_token();
if (tok != T_Token)
goto unexpected;
if (streq(lex.strp, "scx")) {
tok = lex_get_token();
if (tok != T_String)
goto unexpected;
/* Try to get function pointer for find_scx_device */
find_scx_device_fn =
(scx_handle_t (*)(char*)) dlopen_lib("rock",
"find_scx_device",
libname);
scx_ops = *((scx_api**) dlopen_lib("rock", "scx_ops",
libname));
if (find_scx_device_fn == NULL || scx_ops == NULL) {
lex_fatal("Attempted to define SCX Hammerhead "
"interface in non-Rock SCX simulation");
} else {
mmi_datap->scx = find_scx_device_fn(lex.strp);
mmi_datap->scx_ops = scx_ops;
}
lex_get(T_S_Colon);
}
return;
}
#endif
if (strstr(mmi_datap->modname, N2NIU)) {
char *type;
tok = lex_get_token();
if (tok != T_Token)
goto unexpected;
if (streq(lex.strp, "type")) {
tok = lex_get_token();
if (tok != T_Token)
goto unexpected;
type = Xstrdup(lex.strp);
sprintf(argv, "type=%s", type);
mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
mmi_datap->argc ++;
lex_get(T_S_Colon);
}
return;
}
if (strstr(mmi_datap->modname, PARROT)) {
char *bus = NULL;
uint dev = 0;
uint func = 0;
tok = lex_get_token();
if (tok != T_Token)
goto unexpected;
if (streq(lex.strp, "bus")) {
lex_get(T_String);
bus = Xstrdup(lex.strp);
mmi_datap->argc --;
sprintf(argv, "bus=%s", bus);
mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
mmi_datap->argc ++;
lex_get(T_S_Colon);
}
if (streq(lex.strp, "dev")) {
lex_get(T_Number);
dev = lex.val;
if (31 < dev || dev < 0)
goto unexpected;
sprintf(argv, "dev=%x", dev);
mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
mmi_datap->argc ++;
lex_get(T_S_Colon);
}
if (streq(lex.strp, "func")) {
lex_get(T_Number);
func = lex.val;
if (7 < func || func < 0)
goto unexpected;
sprintf(argv, "fun=%x", func);
mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
mmi_datap->argc ++;
lex_get(T_S_Colon);
}
return;
}
if (strstr(mmi_datap->modname, PCIE_BUS)) {
tok = lex_get_token();
if (tok != T_Token)
goto unexpected;
if (streq(lex.strp, "bus")) {
lex_get(T_String);
mmi_datap->instance_name = Xstrdup(lex.strp);
lex_get(T_S_Colon);
}
return;
}
unexpected:
lex_fatal("sam_parse_args: unexpected token encountered");
}
static void sam_set_default_args(mmi_data_t *mmi_datap)
{
char argv[BUFSIZ];
char str[BUFSIZ];
uint8_t siu, hh, pcie, parrot = 0;
if (strstr(mmi_datap->modname, ROCK_SIU) ||
strstr(mmi_datap->modname, HH) ||
strstr(mmi_datap->modname, PCIE_BUS) ||
strstr(mmi_datap->modname, PARROT)) {
if (mmi_datap->argc) {
mmi_datap->argv[0] = "";
mmi_datap->argv[1] = "";
mmi_datap->argc --;
mmi_datap->argc --;
}
}
#if DEBUG_SAM_MODULES
mmi_datap->argv[mmi_datap->argc] = DEBUG_L2;
mmi_datap->argc ++;
#endif /* DEBUG_SAM_MODULES */
sam_get_instance(ROCK_SIU, &siu);
sam_get_instance(HH, &hh);
sam_get_instance(PCIE_BUS, &pcie);
sam_get_instance(PARROT, &parrot);
if (strstr(mmi_datap->modname, ROCK_SIU)) {
siu++;
sprintf(str, "rock_chip_id=%d", (siu -1));
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
sprintf(str, "hh=hh%d", siu);
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
return;
}
if (strstr(mmi_datap->modname, HH)) {
hh++;
sprintf(str, "pciA=pci%d", hh);
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
sprintf(str, "pciB=pci%d", (hh + 1));
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
sprintf(str, "rock_siu=rock_siu%d", hh);
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
return;
}
if (strstr(mmi_datap->modname, PCIE_BUS)) {
pcie++;
sprintf(str, "bridge=hh%d", pcie);
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
sprintf(str, "busnum=1");
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
sprintf(str, "pci%d", pcie);
mmi_datap->instance_name = strdup(str);
return;
}
if (strstr(mmi_datap->modname, PARROT)) {
parrot++;
sprintf(str, "bus=pci%d", (pcie && (parrot / pcie)) ?
(pcie) : (parrot % pcie));
mmi_datap->argv[mmi_datap->argc] = strdup(str);
mmi_datap->argc ++;
return;
}
}
static void sam_parse_dev_stub(config_dev_t *config_devp) {
}
/*
* Complete initialization of the SAM MMI device
*/
static void sam_init_dev_stub(config_dev_t *config_devp)
{
}
/*
* SAM MMI device configuration dump
*/
static void sam_dump_dev_stub(config_dev_t *config_devp)
{
}
static tpaddr_t sam_dev_non_cacheable(config_addr_t *config_addrp, dev_access_t type,
tpaddr_t offset, uint8_t **blockp)
{
return ((tpaddr_t)0); /* no cacheable memory at all */
}
/*
* Legion CPU accessing registers of the SAM MMI device
*/
static bool_t sam_dev_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset,
maccess_t op, uint64_t *regp)
{
mmi_bool_t wr;
uint32_t size;
uint32_t count;
uint64_t end;
uint8_t bytemask;
mmi_iomap_t *iomap;
int cpuid, i;
int status;
size = op & MA_Size_Mask;
op &= MA_Op_Mask;
bytemask = 0xff;
count = (1 << size);
if (count > 16)
count = 0;
cpuid = sp->config_procp->proc_typep->get_cpuid(sp);
wr = (op == MA_St) ? mmi_true : mmi_false;
end = cap->baseaddr + size;
for (iomap = mmi_iomap_head; iomap != NULL; iomap = iomap->next) {
if ((iomap->base <= cap->baseaddr + offset) &&
(cap->baseaddr + offset <= iomap->end)) {
/*
* access SAM MMI device (the full PA is expected, instead of the offset)
*/
tpaddr_t pa = offset + cap->baseaddr;
status = iomap->access(cpuid, iomap->obj, pa, wr, count, regp, bytemask);
if (status == 0) {
DBGDEV(lprintf(sp->gid, "sam_dev_cpu_access: %s pa=0x%llx "
"data=0x%llx count=0x%x pc=0x%llx status=%d\n",
wr ? "WRITE" : "READ", pa, *regp, count,
sp->pc, status); );
return (true);
} else {
DBGDEV(lprintf(sp->gid, "sam_dev_cpu_access: FAILED to %s @ "
"pa=0x%llx pc=0x%llx status=%d\n",
wr ? "WRITE" : "READ", pa, sp->pc, status); );
return (false);
}
}
}
return (false);
}
/*
* SAM MMI device accessing Legion main memory
*/
bool_t sam_mem_access(uint64_t paddr, uint8_t *datap, uint64_t size, dev_access_t type)
{
config_dev_t *config_devp;
domain_t * domainp;
config_addr_t * target_cap;
tpaddr_t extent;
uint8_t * bufp;
/* XXX - Assumes single address domain per simulation */
config_devp = sam_dev_list_head->config_devp;
ASSERT(config_devp != NULL);
domainp = config_devp->domainp;
ASSERT(domainp != NULL);
target_cap = find_domain_address(domainp, paddr);
if (target_cap == NULL) {
/* OK it's a bus error there was no backing store */
return false;
}
extent = target_cap->config_devp->dev_typep->dev_cacheable(target_cap, type,
paddr-target_cap->baseaddr, &bufp);
if (extent < size)
return false;
/*
* Bufp points to the physical memory, datap points to the device memory.
*/
if (type & DA_Load)
bcopy(bufp, datap, size);
else
bcopy(datap, bufp, size);
return true;
}
/*
* Deliver internal on chip I/O interrupts generated by I/O devices such as the
* NIU on the Niagara 2 chip. Each of such interrupts comes with a hardwired
* interrupt number (no addtitional data payload contained), which is used to
* index a table of interrupt information (INT_MAN in NCU for Niagara 2 for
* example).
*/
void sam_internal_intr(int dest_cpuid, sam_device_t *sam_devp, int src_iscpu,
uint32_t vnum, int traptype)
{
config_dev_t *config_devp;
config_proc_t *config_procp;
ext_sig_t sigtype;
int device_id;
simcpu_t *sp;
sam_intr_rec_t intr;
DBGDEV(lprintf(-1, "sam_internal_intr: dest_cpuid = %d vnum = 0x%lx\n",
dest_cpuid, vnum););
if (sam_devp) {
config_devp = sam_devp->config_devp;
/*
* get the config_proc_t pointer, assuming the configuration defines
* a single chip domain XXX
*/
config_procp = LIST_ENTRY(config_devp->domainp->procs, 0);
/*
* setup ext_sig_t type in terms of the device type (such as ES_NIU
* for interrupts handled by Niagara 2 NCU)
*/
if (strcmp(sam_devp->mmi_datap->modname, "n2niu") == 0)
sigtype = ES_NIU;
/*
* call Legion external interrupt handler
*/
pthread_mutex_lock(&sam_devp->mmi_lock);
device_id = vnum;
config_procp->proc_typep->ext_signal(config_procp, sigtype,
&device_id);
pthread_mutex_unlock(&sam_devp->mmi_lock);
} else {
sp = sam_find_simcpu(dest_cpuid);
if (!sp) {
DBGDEV(lprintf(-1, "sam_internal_intr: Invalid "\
"target cpuid = %d \n", dest_cpuid););
return;
}
/*
* call Legion external interrupt handler
*/
config_procp = sp->config_procp;
sigtype = ES_PCIE;
intr.tt = vnum;
intr.enable = traptype;
intr.targetcpu = sp;
config_procp->proc_typep->ext_signal(config_procp, sigtype,
&intr);
}
}
static simcpu_t *sam_find_simcpu (int cpuid)
{
int i, cur_cpuid;
simcpu_t *sp;
for (i = 0; i < simcpu_list.count; i++) {
sp = LIST_ENTRY(simcpu_list, i);
cur_cpuid = sp->config_procp->proc_typep->get_cpuid(sp);
if (cpuid == cur_cpuid) {
return (sp);
}
}
return NULL;
}
/*
* Deliver external I/O mondo interrupts such as those generated through the
* PCI-express DMU. Those interrupts are contained with a mondo data payload,
* and serviced by the "mondo" interrupt ACK/NACK standard.
*
*/
void sam_mondo_intr(int dest_cpuid, void *src, int src_iscpu, uint64_t *idata)
{
/* TBD */
}
/*
* Create a new Legion device entry to interface with each SAM MMI device.
*/
void sam_init_device(char *dev_namep, config_dev_t *config_devp)
{
dev_type_t *dev_typep;
dev_typep = Xcalloc(1, dev_type_t);
dev_typep->dev_type_namep = (char *)Xstrdup(dev_namep);
dev_typep->parse_dev = sam_parse_dev_stub;
dev_typep->init_dev = sam_init_dev_stub;
dev_typep->dump_dev = sam_dump_dev_stub;
dev_typep->dev_cacheable = sam_dev_non_cacheable;
dev_typep->dev_cpu_access = sam_dev_cpu_access;
dev_typep->dev_magic = DEV_MAGIC;
config_devp->dev_typep = dev_typep;
config_devp->is_implied = false; /* this is a real device */
config_devp->addrp = NULL;
}
/*
* Load SAM MMI device model (per MMI spec, it's coded with the explicit
* use of the special symbols "_init" and "_fini").
*/
dev_type_t *sam_load_device(config_dev_t *config_devp)
{
sam_device_t *sam_devp, *first_sam_devp;
char *dev_namep;
char symname[BUFSIZ], libname[MAXPATHLEN], *rv, *lv, *marker;
/*
* link up the new MMI device
*/
sam_devp = (sam_device_t *)config_devp->devp;
sam_register_device(sam_devp);
/*
* Dlopen the SAM MMI device loadable module
*/
sprintf(symname, "_init");
dev_namep = config_devp->dev_typep->dev_type_namep;
first_sam_devp = sam_find_device(dev_namep);
if (first_sam_devp->mmi_datap->create_instance) {
mmi_register_instance_creator (dev_namep,
first_sam_devp->mmi_datap->create_instance);
}
if (!dlopen_lib(dev_namep, symname, libname))
return (dev_type_t *)0;
#if INTERNAL_BUILD
/*
* If this is a Hammerhead device, and we are using it with SCX
* assign the scx handle and pointer to SCX api structure.
*/
if (strstr(sam_devp->mmi_datap->modname, HH) &&
sam_devp->mmi_datap->scx != NULL &&
sam_devp->mmi_datap->scx_ops != NULL) {
void (*hh_set_scx)(void*, scx_handle_t, scx_api*);
void *hhObj = mmi_get_interface(sam_devp->mmi_datap, "HH");
if (hhObj == NULL) {
fatal("WARNING: Unable to get Hammerhead instance"
" for SCX");
} else {
hh_set_scx = (void (*)(void*, scx_handle_t, scx_api*))
mmi_get_interface(sam_devp->mmi_datap,
"HH_SET_SCX_INTERFACE");
if (hh_set_scx == NULL) {
fatal("This version of Hammerhead module does"
" not support SCX");
}
hh_set_scx(hhObj, sam_devp->mmi_datap->scx,
sam_devp->mmi_datap->scx_ops);
}
}
#endif
return(config_devp->dev_typep);
}
/*
* Add the new SAM MMI device pointer into the linked list.
*/
void sam_register_device(sam_device_t *new)
{
sam_device_t *temp;
if (sam_dev_list_head == NULL) {
sam_dev_list_head = new;
return;
}
temp = sam_dev_list_head;
while (temp->next != NULL)
temp = temp->next;
temp->next = new;
new->next = NULL;
}
/*
* Find a SAM MMI device pointer by its name.
*/
sam_device_t *sam_find_device(const char *dev_namep)
{
sam_device_t *sam_devp;
sam_devp = sam_dev_list_head;
while (sam_devp) {
if (sam_devp->mmi_datap->instance_name
&& strcmp(sam_devp->mmi_datap->instance_name,
dev_namep) == 0) {
return (sam_devp);
}
if ( strcmp(sam_devp->mmi_datap->modname, dev_namep) == 0) {
return (sam_devp);
}
sam_devp = sam_devp->next;
}
return (NULL);
}
sam_device_t *sam_get_instance(const char *dev_namep, uint8_t *instance)
{
sam_device_t *sam_devp;
sam_device_t *rsam_devp = NULL;
uint8_t ndev = 0;
sam_devp = sam_dev_list_head;
while (sam_devp) {
if (strcmp(sam_devp->mmi_datap->modname,
dev_namep) == 0) {
rsam_devp = sam_devp;
ndev++;
}
sam_devp = sam_devp->next;
}
*instance = ndev;
return (rsam_devp);
}
/*
* Add a new physio map to the linked list.
*/
void sam_register_iomap(mmi_iomap_t *new)
{
mmi_iomap_t *temp;
if (mmi_iomap_head == NULL) {
mmi_iomap_head = new;
return;
}
temp = mmi_iomap_head;
while (temp->next != NULL)
temp = temp->next;
temp->next = new;
}
/*
* Remove a physio map from the linked list.
*/
void sam_unregister_iomap(uint64_t base, uint64_t size, void *obj)
{
mmi_iomap_t *iomap, *prev, *temp;
for (prev = NULL, iomap = mmi_iomap_head; iomap != NULL; prev = iomap, iomap = iomap->next) {
if ((iomap->obj == obj) && (iomap->base == base) && (iomap->size == size))
break;
}
if (iomap == NULL)
return;
if (prev == NULL) {
temp = mmi_iomap_head;
mmi_iomap_head = temp->next;
} else {
temp = prev->next;
prev->next = temp->next;
}
free(temp);
}
/*
* Add a new cb_cycle to the linked list.
*/
void sam_register_cb_cycle(sam_cycle_t *new)
{
sam_cycle_t *temp;
if (cb_cycle_head == NULL) {
cb_cycle_head = new;
return;
}
temp = cb_cycle_head;
while (temp->next != NULL)
temp = temp->next;
temp->next = new;
}
/*
* Remove a cb_cycle from the linked list.
*/
void sam_unregister_cb_cycle(void *obj)
{
sam_cycle_t *cb_cycle, *prev, *temp;
for (prev = NULL, cb_cycle = cb_cycle_head; cb_cycle != NULL;
prev = cb_cycle, cb_cycle = cb_cycle->next) {
if (cb_cycle == obj)
break;
}
if (cb_cycle == NULL)
return;
if (prev == NULL) {
temp = cb_cycle_head;
cb_cycle_head = temp->next;
} else {
temp = prev->next;
prev->next = temp->next;
}
free(temp);
}
sam_cycle_t *sam_find_cb_cycle(void *obj)
{
sam_cycle_t *cb_cycle;
cb_cycle = cb_cycle_head;
while (cb_cycle) {
if (cb_cycle == obj)
return cb_cycle;
cb_cycle = cb_cycle->next;
}
return NULL;
}
void *sam_start_dma(void *arg)
{
sam_cycle_t *cb_cycle;
while (1) {
cb_cycle = cb_cycle_head;
while (cb_cycle) {
if (cb_cycle->enable) {
cb_cycle->handler(cb_cycle->cb_data,
cb_cycle->repeat);
}
cb_cycle = cb_cycle->next;
}
}
}
int sam_asi_ld_handler(uint32_t asi, uint64_t vaddr, uint64_t *buf,
int size, uint32_t cpuid)
{
sam_device_t *sam_devp;
int count;
int idx;
count = (1 << size);
if (count > 16)
count = 0;
idx = cpuid >> 5;
if (idx >= sam_asi_dev_list.count)
return true;
sam_devp = LIST_ENTRY(sam_asi_dev_list, idx);
if (sam_devp && sam_devp->mmi_datap->asi_ld_handler(
sam_devp->mmi_datap->asi_cb_data, asi, vaddr, buf,
count, cpuid)) {
return false;
}
return true;
}
int sam_asi_st_handler(uint32_t asi, uint64_t vaddr, uint64_t buf,
int size, uint32_t cpuid)
{
int count;
sam_device_t *sam_devp;
int idx;
count = (1 << size);
if (count > 16)
count = 0;
idx = cpuid >> 5;
if (idx >= sam_asi_dev_list.count)
return true;
sam_devp = LIST_ENTRY(sam_asi_dev_list, idx);
if (sam_devp && sam_devp->mmi_datap->asi_st_handler(
sam_devp->mmi_datap->asi_cb_data, asi, vaddr, buf,
count, cpuid)) {
return false;
}
return true;
}