Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / devices / mmi / sam_dev.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: sam_dev.c
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23/*
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident "@(#)sam_dev.c 1.12 07/10/12 SMI"
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <sys/types.h>
34#include <time.h>
35#include <strings.h>
36
37#include "basics.h"
38#include "fatal.h"
39#include "strutil.h"
40#include "allocate.h"
41#include "simcore.h"
42#include "config.h"
43#include "options.h"
44#include "parser.h"
45#include "fileutil.h"
46#include "lexer.h"
47#include "tsparcv9.h"
48#include "tsparcv9internal.h"
49#include "device.h"
50#include "mmi.h"
51#include "sam_dev.h"
52
53void sam_parse_dev(domain_t* domainp, config_dev_t *config_devp);
54void sam_init_device(char *dev_namep, config_dev_t *config_devp);
55static void sam_set_default_args(mmi_data_t *mmi_datap);
56static void sam_parse_args(mmi_data_t *mmi_datap);
57static void sam_init_dev(config_dev_t *config_devp);
58static void sam_dump_dev(config_dev_t *config_devp);
59static tpaddr_t sam_dev_non_cacheable(config_addr_t *config_addrp, dev_access_t type,
60 tpaddr_t offset, uint8_t **blockp);
61static bool_t sam_dev_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset,
62 maccess_t op, uint64_t *regp);
63static simcpu_t *sam_find_simcpu(int cpuid);
64
65
66/*
67 * Maps an address range in the domain to a SAM device, checking for overlap
68 */
69static void
70sam_insert_address_range(domain_t * domainp, config_dev_t *config_devp,
71 tpaddr_t baseaddr, tpaddr_t topaddr) {
72 config_dev_t *overlapp;
73 insert_domain_address(domainp, config_devp, baseaddr, topaddr);
74
75 overlapp = insert_domain_device(domainp, config_devp);
76
77 if (overlapp != NULL) {
78 lex_fatal("device \"%s\" @ 0x%llx overlaps with device \"%s\" @ 0x%llx",
79 overlapp->dev_typep->dev_type_namep,
80 overlapp->addrp->baseaddr,
81 config_devp->dev_typep->dev_type_namep,
82 config_devp->addrp->baseaddr);
83 }
84}
85
86/*
87 * The SAM MMI device is parsed by the 'mmi_device' directive in
88 * the syntax of
89 *
90 * mmi_device <dev_name> <base_addr> + <size> {
91 * type <string>
92 * }
93 *
94 * Example:
95 *
96 * - use SAM MMI NIU device model for Niagara 2:
97 *
98 * mmi_device "n2niu" 0x8100000000 + 0x100000000;
99 *
100 * - use SAM MMI dumbserial device model:
101 *
102 * mmi_device "dumbserial-mmi" 0x1f10000000 + 0x50 {
103 * type HYPERVISOR;
104 * }
105 */
106void
107sam_parse_dev(domain_t * domainp, config_dev_t *config_devp)
108{
109 dev_type_t *dev_typep = (dev_type_t *)config_devp->dev_typep;
110 sam_device_t *sam_devp;
111 mmi_data_t *mmi_datap;
112 tpaddr_t baseaddr, size, topaddr;
113 bool_t is_size;
114 lexer_tok_t tok;
115 char *type, argv[BUFSIZ];
116
117 DBG(printf("sam_parse_dev: parsing device %d\n", config_devp->device_id); );
118
119 sam_devp = Xcalloc(1, sam_device_t);
120 mmi_datap = Xcalloc(1, mmi_data_t);
121
122 sam_devp->config_devp = config_devp;
123 sam_devp->mmi_datap = mmi_datap;
124
125 mmi_datap->modname = (char *)Xstrdup(dev_typep->dev_type_namep);
126 mmi_datap->argv = (char**) Xcalloc(MMI_MAX_ARGC, char**);
127 mmi_datap->argc = 0; /* Initialize argument count to 0 */
128#if INTERNAL_BUILD
129 mmi_datap->scx = NULL; /* Initialize to NULL for most devices */
130#endif
131
132 config_devp->devp = sam_devp;
133 pthread_mutex_init(&sam_devp->mmi_lock, NULL);
134
135 tok = lex_get_token();
136 if (tok == T_Number) {
137 lex_unget();
138 do {
139 lex_get(T_Number);
140 baseaddr = lex.val;
141
142 is_size = false;
143 tok = lex_get_token();
144 if (tok == T_Plus) {
145 /* Next value is size */
146 is_size = true;
147 } else {
148 /* Next value is end address */
149 lex_unget();
150 }
151
152 sprintf(argv, "base=0x%llx", baseaddr);
153 mmi_datap->argv[0] = Xstrdup(argv);
154 mmi_datap->argc = 1;
155
156 lex_get(T_Number);
157 if (is_size) {
158 topaddr = baseaddr + lex.val;
159 } else {
160 topaddr = lex.val;
161 }
162
163 sprintf(argv, "size=0x%llx", topaddr - baseaddr);
164 mmi_datap->argv[1] = Xstrdup(argv);
165 mmi_datap->argc = 2;
166
167 if (topaddr <= baseaddr)
168 lex_fatal("top address <= base address with device %s",
169 mmi_datap->modname);
170
171 /* Add the current address range into the domain address map */
172 sam_insert_address_range(domainp, config_devp, baseaddr, topaddr);
173 if (lex_get_token() == T_Comma) {
174 /*
175 * More address ranges to map to device.
176 * Allocate new control struct, but share device entry.
177 */
178 config_devp = Xmalloc( sizeof(config_dev_t) );
179 config_devp->dev_typep = dev_typep;
180 config_devp->is_implied = false;
181 config_devp->addrp = NULL;
182 config_devp->devp = sam_devp;
183 } else {
184 break;
185 }
186 } while (1);
187 }
188
189 lex_unget();
190
191 sam_set_default_args(mmi_datap);
192
193 tok = lex_get_token();
194 switch (tok) {
195 case T_S_Colon:
196 return;
197 case T_L_Brace:
198 break;
199 default:
200unexpected:
201 lex_fatal("sam_parse_dev: unexpected token encountered");
202 }
203
204 while ( (tok = lex_get_token()) != T_R_Brace) {
205 lex_unget();
206 sam_parse_args(mmi_datap);
207 }
208
209}
210
211static void sam_parse_args(mmi_data_t *mmi_datap)
212{
213 lexer_tok_t tok;
214 char argv[BUFSIZ];
215 char libname[MAXPATHLEN];
216
217#if INTERNAL_BUILD
218 /*
219 * This code only applies to Rock setups at the moment
220 * necessitating some complex linking code.
221 */
222 if (strstr(mmi_datap->modname, HH)) {
223 scx_handle_t (*find_scx_device_fn)(char*);
224 scx_api *scx_ops;
225
226 tok = lex_get_token();
227 if (tok != T_Token)
228 goto unexpected;
229 if (streq(lex.strp, "scx")) {
230 tok = lex_get_token();
231 if (tok != T_String)
232 goto unexpected;
233 /* Try to get function pointer for find_scx_device */
234 find_scx_device_fn =
235 (scx_handle_t (*)(char*)) dlopen_lib("rock",
236 "find_scx_device",
237 libname);
238 scx_ops = *((scx_api**) dlopen_lib("rock", "scx_ops",
239 libname));
240
241 if (find_scx_device_fn == NULL || scx_ops == NULL) {
242 lex_fatal("Attempted to define SCX Hammerhead "
243 "interface in non-Rock SCX simulation");
244 } else {
245 mmi_datap->scx = find_scx_device_fn(lex.strp);
246 mmi_datap->scx_ops = scx_ops;
247 }
248 lex_get(T_S_Colon);
249 }
250 return;
251 }
252#endif
253
254 if (strstr(mmi_datap->modname, N2NIU)) {
255 char *type;
256
257 tok = lex_get_token();
258 if (tok != T_Token)
259 goto unexpected;
260 if (streq(lex.strp, "type")) {
261 tok = lex_get_token();
262 if (tok != T_Token)
263 goto unexpected;
264 type = Xstrdup(lex.strp);
265 sprintf(argv, "type=%s", type);
266 mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
267 mmi_datap->argc ++;
268 lex_get(T_S_Colon);
269 }
270 return;
271 }
272 if (strstr(mmi_datap->modname, PARROT)) {
273 char *bus = NULL;
274 uint dev = 0;
275 uint func = 0;
276
277 tok = lex_get_token();
278 if (tok != T_Token)
279 goto unexpected;
280 if (streq(lex.strp, "bus")) {
281 lex_get(T_String);
282 bus = Xstrdup(lex.strp);
283 mmi_datap->argc --;
284 sprintf(argv, "bus=%s", bus);
285 mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
286 mmi_datap->argc ++;
287 lex_get(T_S_Colon);
288 }
289 if (streq(lex.strp, "dev")) {
290 lex_get(T_Number);
291 dev = lex.val;
292 if (31 < dev || dev < 0)
293 goto unexpected;
294 sprintf(argv, "dev=%x", dev);
295 mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
296 mmi_datap->argc ++;
297 lex_get(T_S_Colon);
298 }
299 if (streq(lex.strp, "func")) {
300 lex_get(T_Number);
301 func = lex.val;
302 if (7 < func || func < 0)
303 goto unexpected;
304 sprintf(argv, "fun=%x", func);
305 mmi_datap->argv[mmi_datap->argc] = Xstrdup(argv);
306 mmi_datap->argc ++;
307 lex_get(T_S_Colon);
308 }
309 return;
310 }
311 if (strstr(mmi_datap->modname, PCIE_BUS)) {
312 tok = lex_get_token();
313 if (tok != T_Token)
314 goto unexpected;
315 if (streq(lex.strp, "bus")) {
316 lex_get(T_String);
317 mmi_datap->instance_name = Xstrdup(lex.strp);
318 lex_get(T_S_Colon);
319 }
320 return;
321 }
322unexpected:
323 lex_fatal("sam_parse_args: unexpected token encountered");
324}
325
326static void sam_set_default_args(mmi_data_t *mmi_datap)
327{
328 char argv[BUFSIZ];
329 char str[BUFSIZ];
330 uint8_t siu, hh, pcie, parrot = 0;
331
332
333 if (strstr(mmi_datap->modname, ROCK_SIU) ||
334 strstr(mmi_datap->modname, HH) ||
335 strstr(mmi_datap->modname, PCIE_BUS) ||
336 strstr(mmi_datap->modname, PARROT)) {
337 if (mmi_datap->argc) {
338 mmi_datap->argv[0] = "";
339 mmi_datap->argv[1] = "";
340 mmi_datap->argc --;
341 mmi_datap->argc --;
342 }
343 }
344
345#if DEBUG_SAM_MODULES
346 mmi_datap->argv[mmi_datap->argc] = DEBUG_L2;
347 mmi_datap->argc ++;
348#endif /* DEBUG_SAM_MODULES */
349
350 sam_get_instance(ROCK_SIU, &siu);
351 sam_get_instance(HH, &hh);
352 sam_get_instance(PCIE_BUS, &pcie);
353 sam_get_instance(PARROT, &parrot);
354
355 if (strstr(mmi_datap->modname, ROCK_SIU)) {
356 siu++;
357 sprintf(str, "rock_chip_id=%d", (siu -1));
358 mmi_datap->argv[mmi_datap->argc] = strdup(str);
359 mmi_datap->argc ++;
360 sprintf(str, "hh=hh%d", siu);
361 mmi_datap->argv[mmi_datap->argc] = strdup(str);
362 mmi_datap->argc ++;
363 return;
364 }
365
366 if (strstr(mmi_datap->modname, HH)) {
367 hh++;
368 sprintf(str, "pciA=pci%d", hh);
369 mmi_datap->argv[mmi_datap->argc] = strdup(str);
370 mmi_datap->argc ++;
371 sprintf(str, "pciB=pci%d", (hh + 1));
372 mmi_datap->argv[mmi_datap->argc] = strdup(str);
373 mmi_datap->argc ++;
374 sprintf(str, "rock_siu=rock_siu%d", hh);
375 mmi_datap->argv[mmi_datap->argc] = strdup(str);
376 mmi_datap->argc ++;
377 return;
378 }
379
380 if (strstr(mmi_datap->modname, PCIE_BUS)) {
381 pcie++;
382 sprintf(str, "bridge=hh%d", pcie);
383 mmi_datap->argv[mmi_datap->argc] = strdup(str);
384 mmi_datap->argc ++;
385 sprintf(str, "busnum=1");
386 mmi_datap->argv[mmi_datap->argc] = strdup(str);
387 mmi_datap->argc ++;
388 sprintf(str, "pci%d", pcie);
389 mmi_datap->instance_name = strdup(str);
390 return;
391 }
392
393 if (strstr(mmi_datap->modname, PARROT)) {
394 parrot++;
395 sprintf(str, "bus=pci%d", (pcie && (parrot / pcie)) ?
396 (pcie) : (parrot % pcie));
397 mmi_datap->argv[mmi_datap->argc] = strdup(str);
398 mmi_datap->argc ++;
399 return;
400 }
401}
402
403static void sam_parse_dev_stub(config_dev_t *config_devp) {
404
405}
406
407/*
408 * Complete initialization of the SAM MMI device
409 */
410static void sam_init_dev_stub(config_dev_t *config_devp)
411{
412
413}
414
415/*
416 * SAM MMI device configuration dump
417 */
418static void sam_dump_dev_stub(config_dev_t *config_devp)
419{
420
421}
422
423static tpaddr_t sam_dev_non_cacheable(config_addr_t *config_addrp, dev_access_t type,
424 tpaddr_t offset, uint8_t **blockp)
425{
426 return ((tpaddr_t)0); /* no cacheable memory at all */
427}
428
429
430/*
431 * Legion CPU accessing registers of the SAM MMI device
432 */
433static bool_t sam_dev_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset,
434 maccess_t op, uint64_t *regp)
435{
436 mmi_bool_t wr;
437 uint32_t size;
438 uint32_t count;
439 uint64_t end;
440 uint8_t bytemask;
441 mmi_iomap_t *iomap;
442 int cpuid, i;
443 int status;
444
445 size = op & MA_Size_Mask;
446 op &= MA_Op_Mask;
447 bytemask = 0xff;
448
449 count = (1 << size);
450 if (count > 16)
451 count = 0;
452
453 cpuid = sp->config_procp->proc_typep->get_cpuid(sp);
454
455 wr = (op == MA_St) ? mmi_true : mmi_false;
456 end = cap->baseaddr + size;
457 for (iomap = mmi_iomap_head; iomap != NULL; iomap = iomap->next) {
458 if ((iomap->base <= cap->baseaddr + offset) &&
459 (cap->baseaddr + offset <= iomap->end)) {
460 /*
461 * access SAM MMI device (the full PA is expected, instead of the offset)
462 */
463 tpaddr_t pa = offset + cap->baseaddr;
464 status = iomap->access(cpuid, iomap->obj, pa, wr, count, regp, bytemask);
465 if (status == 0) {
466 DBGDEV(lprintf(sp->gid, "sam_dev_cpu_access: %s pa=0x%llx "
467 "data=0x%llx count=0x%x pc=0x%llx status=%d\n",
468 wr ? "WRITE" : "READ", pa, *regp, count,
469 sp->pc, status); );
470 return (true);
471 } else {
472 DBGDEV(lprintf(sp->gid, "sam_dev_cpu_access: FAILED to %s @ "
473 "pa=0x%llx pc=0x%llx status=%d\n",
474 wr ? "WRITE" : "READ", pa, sp->pc, status); );
475 return (false);
476 }
477 }
478 }
479
480 return (false);
481}
482
483
484/*
485 * SAM MMI device accessing Legion main memory
486 */
487bool_t sam_mem_access(uint64_t paddr, uint8_t *datap, uint64_t size, dev_access_t type)
488{
489 config_dev_t *config_devp;
490 domain_t * domainp;
491 config_addr_t * target_cap;
492 tpaddr_t extent;
493 uint8_t * bufp;
494
495 /* XXX - Assumes single address domain per simulation */
496 config_devp = sam_dev_list_head->config_devp;
497 ASSERT(config_devp != NULL);
498 domainp = config_devp->domainp;
499 ASSERT(domainp != NULL);
500
501 target_cap = find_domain_address(domainp, paddr);
502 if (target_cap == NULL) {
503 /* OK it's a bus error there was no backing store */
504 return false;
505 }
506
507 extent = target_cap->config_devp->dev_typep->dev_cacheable(target_cap, type,
508 paddr-target_cap->baseaddr, &bufp);
509
510 if (extent < size)
511 return false;
512
513 /*
514 * Bufp points to the physical memory, datap points to the device memory.
515 */
516 if (type & DA_Load)
517 bcopy(bufp, datap, size);
518 else
519 bcopy(datap, bufp, size);
520
521 return true;
522}
523
524
525/*
526 * Deliver internal on chip I/O interrupts generated by I/O devices such as the
527 * NIU on the Niagara 2 chip. Each of such interrupts comes with a hardwired
528 * interrupt number (no addtitional data payload contained), which is used to
529 * index a table of interrupt information (INT_MAN in NCU for Niagara 2 for
530 * example).
531 */
532void sam_internal_intr(int dest_cpuid, sam_device_t *sam_devp, int src_iscpu,
533 uint32_t vnum, int traptype)
534{
535 config_dev_t *config_devp;
536 config_proc_t *config_procp;
537 ext_sig_t sigtype;
538 int device_id;
539 simcpu_t *sp;
540 sam_intr_rec_t intr;
541
542 DBGDEV(lprintf(-1, "sam_internal_intr: dest_cpuid = %d vnum = 0x%lx\n",
543 dest_cpuid, vnum););
544
545 if (sam_devp) {
546 config_devp = sam_devp->config_devp;
547 /*
548 * get the config_proc_t pointer, assuming the configuration defines
549 * a single chip domain XXX
550 */
551 config_procp = LIST_ENTRY(config_devp->domainp->procs, 0);
552
553 /*
554 * setup ext_sig_t type in terms of the device type (such as ES_NIU
555 * for interrupts handled by Niagara 2 NCU)
556 */
557 if (strcmp(sam_devp->mmi_datap->modname, "n2niu") == 0)
558 sigtype = ES_NIU;
559 /*
560 * call Legion external interrupt handler
561 */
562 pthread_mutex_lock(&sam_devp->mmi_lock);
563 device_id = vnum;
564 config_procp->proc_typep->ext_signal(config_procp, sigtype,
565 &device_id);
566 pthread_mutex_unlock(&sam_devp->mmi_lock);
567
568 } else {
569 sp = sam_find_simcpu(dest_cpuid);
570 if (!sp) {
571 DBGDEV(lprintf(-1, "sam_internal_intr: Invalid "\
572 "target cpuid = %d \n", dest_cpuid););
573 return;
574 }
575 /*
576 * call Legion external interrupt handler
577 */
578 config_procp = sp->config_procp;
579 sigtype = ES_PCIE;
580 intr.tt = vnum;
581 intr.enable = traptype;
582 intr.targetcpu = sp;
583 config_procp->proc_typep->ext_signal(config_procp, sigtype,
584 &intr);
585 }
586}
587
588static simcpu_t *sam_find_simcpu (int cpuid)
589{
590 int i, cur_cpuid;
591 simcpu_t *sp;
592
593 for (i = 0; i < simcpu_list.count; i++) {
594 sp = LIST_ENTRY(simcpu_list, i);
595 cur_cpuid = sp->config_procp->proc_typep->get_cpuid(sp);
596 if (cpuid == cur_cpuid) {
597 return (sp);
598 }
599 }
600 return NULL;
601}
602
603/*
604 * Deliver external I/O mondo interrupts such as those generated through the
605 * PCI-express DMU. Those interrupts are contained with a mondo data payload,
606 * and serviced by the "mondo" interrupt ACK/NACK standard.
607 *
608 */
609void sam_mondo_intr(int dest_cpuid, void *src, int src_iscpu, uint64_t *idata)
610{
611 /* TBD */
612}
613
614/*
615 * Create a new Legion device entry to interface with each SAM MMI device.
616 */
617void sam_init_device(char *dev_namep, config_dev_t *config_devp)
618{
619 dev_type_t *dev_typep;
620
621 dev_typep = Xcalloc(1, dev_type_t);
622
623 dev_typep->dev_type_namep = (char *)Xstrdup(dev_namep);
624 dev_typep->parse_dev = sam_parse_dev_stub;
625 dev_typep->init_dev = sam_init_dev_stub;
626 dev_typep->dump_dev = sam_dump_dev_stub;
627 dev_typep->dev_cacheable = sam_dev_non_cacheable;
628 dev_typep->dev_cpu_access = sam_dev_cpu_access;
629 dev_typep->dev_magic = DEV_MAGIC;
630
631 config_devp->dev_typep = dev_typep;
632 config_devp->is_implied = false; /* this is a real device */
633 config_devp->addrp = NULL;
634}
635
636
637/*
638 * Load SAM MMI device model (per MMI spec, it's coded with the explicit
639 * use of the special symbols "_init" and "_fini").
640 */
641dev_type_t *sam_load_device(config_dev_t *config_devp)
642{
643 sam_device_t *sam_devp, *first_sam_devp;
644 char *dev_namep;
645 char symname[BUFSIZ], libname[MAXPATHLEN], *rv, *lv, *marker;
646
647 /*
648 * link up the new MMI device
649 */
650 sam_devp = (sam_device_t *)config_devp->devp;
651 sam_register_device(sam_devp);
652
653 /*
654 * Dlopen the SAM MMI device loadable module
655 */
656 sprintf(symname, "_init");
657 dev_namep = config_devp->dev_typep->dev_type_namep;
658
659 first_sam_devp = sam_find_device(dev_namep);
660 if (first_sam_devp->mmi_datap->create_instance) {
661 mmi_register_instance_creator (dev_namep,
662 first_sam_devp->mmi_datap->create_instance);
663 }
664
665 if (!dlopen_lib(dev_namep, symname, libname))
666 return (dev_type_t *)0;
667
668#if INTERNAL_BUILD
669 /*
670 * If this is a Hammerhead device, and we are using it with SCX
671 * assign the scx handle and pointer to SCX api structure.
672 */
673 if (strstr(sam_devp->mmi_datap->modname, HH) &&
674 sam_devp->mmi_datap->scx != NULL &&
675 sam_devp->mmi_datap->scx_ops != NULL) {
676 void (*hh_set_scx)(void*, scx_handle_t, scx_api*);
677 void *hhObj = mmi_get_interface(sam_devp->mmi_datap, "HH");
678 if (hhObj == NULL) {
679 fatal("WARNING: Unable to get Hammerhead instance"
680 " for SCX");
681 } else {
682 hh_set_scx = (void (*)(void*, scx_handle_t, scx_api*))
683 mmi_get_interface(sam_devp->mmi_datap,
684 "HH_SET_SCX_INTERFACE");
685 if (hh_set_scx == NULL) {
686 fatal("This version of Hammerhead module does"
687 " not support SCX");
688 }
689 hh_set_scx(hhObj, sam_devp->mmi_datap->scx,
690 sam_devp->mmi_datap->scx_ops);
691 }
692 }
693#endif
694
695 return(config_devp->dev_typep);
696}
697
698
699/*
700 * Add the new SAM MMI device pointer into the linked list.
701 */
702void sam_register_device(sam_device_t *new)
703{
704 sam_device_t *temp;
705
706 if (sam_dev_list_head == NULL) {
707 sam_dev_list_head = new;
708 return;
709 }
710
711 temp = sam_dev_list_head;
712 while (temp->next != NULL)
713 temp = temp->next;
714 temp->next = new;
715 new->next = NULL;
716}
717
718
719/*
720 * Find a SAM MMI device pointer by its name.
721 */
722sam_device_t *sam_find_device(const char *dev_namep)
723{
724 sam_device_t *sam_devp;
725
726 sam_devp = sam_dev_list_head;
727
728 while (sam_devp) {
729 if (sam_devp->mmi_datap->instance_name
730 && strcmp(sam_devp->mmi_datap->instance_name,
731 dev_namep) == 0) {
732 return (sam_devp);
733 }
734 if ( strcmp(sam_devp->mmi_datap->modname, dev_namep) == 0) {
735 return (sam_devp);
736 }
737 sam_devp = sam_devp->next;
738 }
739
740 return (NULL);
741}
742
743sam_device_t *sam_get_instance(const char *dev_namep, uint8_t *instance)
744{
745 sam_device_t *sam_devp;
746 sam_device_t *rsam_devp = NULL;
747 uint8_t ndev = 0;
748
749 sam_devp = sam_dev_list_head;
750
751 while (sam_devp) {
752 if (strcmp(sam_devp->mmi_datap->modname,
753 dev_namep) == 0) {
754 rsam_devp = sam_devp;
755 ndev++;
756 }
757 sam_devp = sam_devp->next;
758 }
759 *instance = ndev;
760 return (rsam_devp);
761}
762
763/*
764 * Add a new physio map to the linked list.
765 */
766void sam_register_iomap(mmi_iomap_t *new)
767{
768 mmi_iomap_t *temp;
769
770 if (mmi_iomap_head == NULL) {
771 mmi_iomap_head = new;
772 return;
773 }
774
775 temp = mmi_iomap_head;
776 while (temp->next != NULL)
777 temp = temp->next;
778 temp->next = new;
779}
780
781
782/*
783 * Remove a physio map from the linked list.
784 */
785void sam_unregister_iomap(uint64_t base, uint64_t size, void *obj)
786{
787 mmi_iomap_t *iomap, *prev, *temp;
788
789 for (prev = NULL, iomap = mmi_iomap_head; iomap != NULL; prev = iomap, iomap = iomap->next) {
790 if ((iomap->obj == obj) && (iomap->base == base) && (iomap->size == size))
791 break;
792 }
793 if (iomap == NULL)
794 return;
795
796 if (prev == NULL) {
797 temp = mmi_iomap_head;
798 mmi_iomap_head = temp->next;
799 } else {
800 temp = prev->next;
801 prev->next = temp->next;
802 }
803
804 free(temp);
805}
806
807/*
808 * Add a new cb_cycle to the linked list.
809 */
810void sam_register_cb_cycle(sam_cycle_t *new)
811{
812 sam_cycle_t *temp;
813
814 if (cb_cycle_head == NULL) {
815 cb_cycle_head = new;
816 return;
817 }
818
819 temp = cb_cycle_head;
820 while (temp->next != NULL)
821 temp = temp->next;
822 temp->next = new;
823}
824
825/*
826 * Remove a cb_cycle from the linked list.
827 */
828void sam_unregister_cb_cycle(void *obj)
829{
830 sam_cycle_t *cb_cycle, *prev, *temp;
831
832 for (prev = NULL, cb_cycle = cb_cycle_head; cb_cycle != NULL;
833 prev = cb_cycle, cb_cycle = cb_cycle->next) {
834 if (cb_cycle == obj)
835 break;
836 }
837 if (cb_cycle == NULL)
838 return;
839
840 if (prev == NULL) {
841 temp = cb_cycle_head;
842 cb_cycle_head = temp->next;
843 } else {
844 temp = prev->next;
845 prev->next = temp->next;
846 }
847
848 free(temp);
849}
850
851sam_cycle_t *sam_find_cb_cycle(void *obj)
852{
853 sam_cycle_t *cb_cycle;
854
855 cb_cycle = cb_cycle_head;
856
857 while (cb_cycle) {
858 if (cb_cycle == obj)
859 return cb_cycle;
860 cb_cycle = cb_cycle->next;
861 }
862 return NULL;
863}
864
865void *sam_start_dma(void *arg)
866{
867 sam_cycle_t *cb_cycle;
868
869 while (1) {
870 cb_cycle = cb_cycle_head;
871 while (cb_cycle) {
872 if (cb_cycle->enable) {
873 cb_cycle->handler(cb_cycle->cb_data,
874 cb_cycle->repeat);
875 }
876 cb_cycle = cb_cycle->next;
877 }
878 }
879}
880
881int sam_asi_ld_handler(uint32_t asi, uint64_t vaddr, uint64_t *buf,
882 int size, uint32_t cpuid)
883{
884 sam_device_t *sam_devp;
885 int count;
886 int idx;
887
888 count = (1 << size);
889 if (count > 16)
890 count = 0;
891
892 idx = cpuid >> 5;
893 if (idx >= sam_asi_dev_list.count)
894 return true;
895 sam_devp = LIST_ENTRY(sam_asi_dev_list, idx);
896 if (sam_devp && sam_devp->mmi_datap->asi_ld_handler(
897 sam_devp->mmi_datap->asi_cb_data, asi, vaddr, buf,
898 count, cpuid)) {
899 return false;
900 }
901 return true;
902}
903
904int sam_asi_st_handler(uint32_t asi, uint64_t vaddr, uint64_t buf,
905 int size, uint32_t cpuid)
906{
907 int count;
908 sam_device_t *sam_devp;
909 int idx;
910
911 count = (1 << size);
912 if (count > 16)
913 count = 0;
914
915 idx = cpuid >> 5;
916 if (idx >= sam_asi_dev_list.count)
917 return true;
918 sam_devp = LIST_ENTRY(sam_asi_dev_list, idx);
919 if (sam_devp && sam_devp->mmi_datap->asi_st_handler(
920 sam_devp->mmi_datap->asi_cb_data, asi, vaddr, buf,
921 count, cpuid)) {
922 return false;
923 }
924 return true;
925}