Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

sig_host_bus.c

/*
 * $Id: sig_host_bus.c,v 1.25 2009-01-27 17:06:41 potyra Exp $
 *
 * Copyright (C) 2004-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include "config.h"

#define DEBUG_INOUT     0
#define DEBUG_MEM 0
#define DEBUG_IRQ 0
#define DEBUG_MAP 0

#include "compiler.h"

#include <sys/types.h>
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fixme.h"

#include "glue-shm.h"

#include "sig_host_bus.h"

int
sig_host_bus_type_addr(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int type,
      uint32_t addr
)
{
      unsigned int nr;

      for (nr = 0; ; nr++) {
            int (*func)(void *, unsigned int, uint32_t);
            void *func_s;

            if (nr == b->member_count) {
                  /* Not found. */
                  return -1;
            }
            if (b->member[nr].s == s) {
                  /* Don't ask myself. */
                  continue;
            }
            func = b->member[nr].f->type_addr;
            func_s = b->member[nr].s;
            if (func
             && func(func_s, type, addr) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_read_data(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int bs,
      uint32_t *valp
)
{
      unsigned int nr;

      for (nr = 0; ; nr++) {
            int (*func)(void *, unsigned int, uint32_t *);
            void *func_s;

            if (nr == b->member_count) {
                  /* Not found. */
                  *valp = 0xffffffff;
                  return -1;
            }
            if (b->member[nr].s == s) {
                  /* Don't ask myself. */
                  continue;
            }
            func = b->member[nr].f->read_data;
            func_s = b->member[nr].s;
            if (func
             && func(func_s, bs, valp) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_write_data(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int bs,
      uint32_t val
)
{
      unsigned int nr;

      for (nr = 0; ; nr++) {
            int (*func)(void *, unsigned int, uint32_t);
            void *func_s;

            if (nr == b->member_count) {
                  /* Not found. */
                  return -1;
            }
            if (b->member[nr].s == s) {
                  /* Don't ask myself. */
                  continue;
            }
            func = b->member[nr].f->write_data;
            func_s = b->member[nr].s;
            if (func
             && func(func_s, bs, val) == 0) {
                  return 0;
            }
      }
}

static inline __attribute__((always_inline)) unsigned int
_sig_host_bus_io_hash(uint32_t port, unsigned int bs)
{
      unsigned int val;

      val = port / 4;
      val ^= bs;
      val %= SIG_HOST_BUS_HASH_SIZE;

      return val;
}

static inline __attribute__((always_inline)) int
_sig_host_bus_ior_lookup(
      struct sig_host_bus_main *b,
      uint32_t port,
      unsigned int bs,
      int (**f)(void *s, uint32_t port, unsigned int bs, uint32_t *valp),
      void **s
)
{
      unsigned int hash;
      struct sig_host_bus_main_ior *m;

      hash = _sig_host_bus_io_hash(port, bs);

      for (m = b->ior_hash_first[hash]; ; m = m->hash_next) {
            if (unlikely(! m)) {
                  /* Not found. */
                  return 0;
            }
            if (likely(m->port == port
                  && m->bs == bs)) {
                  /* Found. */
                  *f = m->f;
                  *s = m->s;
                  return 1;
            }
      }
}

static void
_sig_host_bus_ior_add(
      struct sig_host_bus_main *b,
      uint32_t port,
      unsigned int bs,
      int (*f)(void *s, uint32_t port, unsigned int bs, uint32_t *valp),
      void *s
)
{
      unsigned int hash;
      struct sig_host_bus_main_ior *m;

      m = b->ior_lru_last;

      /* Remove from LRU list. */
      m->lru_prev->lru_next = 0;
      b->ior_lru_last = m->lru_prev;

      if (m->port != -1) {
            /* Remove from HASH list. */
            hash = _sig_host_bus_io_hash(m->port, m->bs);
            if (m->hash_prev) {
                  m->hash_prev->hash_next = m->hash_next;
            } else {
                  b->ior_hash_first[hash] = m->hash_next;
            }
            if (m->hash_next) {
                  m->hash_next->hash_prev = m->hash_prev;
            } else {
                  b->ior_hash_last[hash] = m->hash_prev;
            }
      }

      /* Add new info. */
      m->port = port;
      m->bs = bs;
      m->f = f;
      m->s = s;

      /* Add to HASH list. */
      hash = _sig_host_bus_io_hash(port, bs);
      m->hash_prev = 0;
      m->hash_next = b->ior_hash_first[hash];
      b->ior_hash_first[hash] = m;
      if (m->hash_next) {
            m->hash_next->hash_prev = m;
      } else {
            b->ior_hash_last[hash] = m;
      }

      /* Add to LRU list. */
      m->lru_prev = 0;
      m->lru_next = b->ior_lru_first;
      b->ior_lru_first = m;
      m->lru_next->lru_prev = m;
}

int
sig_host_bus_ior_info(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
      void **csp
)
{
      unsigned int nr;

      for (nr = 0; ; nr++) {
            int (*info_f)(void *, uint32_t, unsigned int,
                  int (**)(void *, uint32_t, unsigned int, uint32_t *),
                  void **);
            void *info_s;

            if (nr == b->member_count) {
                  /* No info found. */
                  return -1;
            }
            if (b->member[nr].s == s) {
                  /* Don't ask myself. */
                  continue;
            }
            info_f = b->member[nr].f->ior_info;
            info_s = b->member[nr].s;
            if (info_f
             && info_f(info_s, port, bs, cfp, csp) == 0) {
                  return 0;
            }
      }
}

static int
_sig_host_bus_ior_dummy(
      void *s,
      uint32_t port,
      unsigned int bs,
      uint32_t *valp
)
{
      *valp = 0xffffffff;
      return 1;
}

int
sig_host_bus_ior(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs,
      uint32_t *valp
)
{
      int (*cf)(void *, uint32_t, unsigned int, uint32_t *);
      void *cs;
      unsigned int nr;

      assert(! (port & 3));

      if (_sig_host_bus_ior_lookup(b, port, bs, &cf, &cs)) {
            return (*cf)(cs, port, bs, valp);
      }

      if (sig_host_bus_ior_info(b, s, port, bs, &cf, &cs) == 0) {
            _sig_host_bus_ior_add(b, port, bs, cf, cs);
            return cf(cs, port, bs, valp);
      }

#if 0
      fprintf(stderr, "INFO: No IOR info for 0x%04x 0x%x\n", port, bs);
#endif

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  break;
            }
            if (b->member[nr].s == s) {
                  continue;
            }
            cf = b->member[nr].f->ior;
            cs = b->member[nr].s;
            if (cf
             && cf(cs, port, bs, valp) == 0) {
                  _sig_host_bus_ior_add(b, port, bs, cf, cs);
                  return 0;
            }
      }

      cf = _sig_host_bus_ior_dummy;
      cs = 0;
      _sig_host_bus_ior_add(b, port, bs, cf, cs);
      return 1;
}

static inline __attribute__((always_inline)) int
_sig_host_bus_iow_lookup(
      struct sig_host_bus_main *b,
      uint32_t port,
      unsigned int bs,
      int (**f)(void *s, uint32_t port, unsigned int bs, uint32_t val),
      void **s
)
{
      unsigned int hash;
      struct sig_host_bus_main_iow *m;

      hash = _sig_host_bus_io_hash(port, bs);

      for (m = b->iow_hash_first[hash]; ; m = m->hash_next) {
            if (unlikely(! m)) {
                  /* Not found. */
                  return 0;
            }
            if (likely(m->port == port
                  && m->bs == bs)) {
                  /* Found. */
                  *f = m->f;
                  *s = m->s;
                  return 1;
            }
      }
}

static void
_sig_host_bus_iow_add(
      struct sig_host_bus_main *b,
      uint32_t port,
      unsigned int bs,
      int (*f)(void *s, uint32_t port, unsigned int bs, uint32_t val),
      void *s
)
{
      unsigned int hash;
      struct sig_host_bus_main_iow *m;

      m = b->iow_lru_last;

      /* Remove from LRU list. */
      m->lru_prev->lru_next = 0;
      b->iow_lru_last = m->lru_prev;

      if (m->port != -1) {
            /* Remove from HASH list. */
            hash = _sig_host_bus_io_hash(m->port, m->bs);
            if (m->hash_prev) {
                  m->hash_prev->hash_next = m->hash_next;
            } else {
                  b->iow_hash_first[hash] = m->hash_next;
            }
            if (m->hash_next) {
                  m->hash_next->hash_prev = m->hash_prev;
            } else {
                  b->iow_hash_last[hash] = m->hash_prev;
            }
      }

      /* Add new info. */
      m->port = port;
      m->bs = bs;
      m->f = f;
      m->s = s;

      /* Add to HASH list. */
      hash = _sig_host_bus_io_hash(port, bs);
      m->hash_prev = 0;
      m->hash_next = b->iow_hash_first[hash];
      b->iow_hash_first[hash] = m;
      if (m->hash_next) {
            m->hash_next->hash_prev = m;
      } else {
            b->iow_hash_last[hash] = m;
      }

      /* Add to LRU list. */
      m->lru_prev = 0;
      m->lru_next = b->iow_lru_first;
      b->iow_lru_first = m;
      m->lru_next->lru_prev = m;
}

int
sig_host_bus_iow_info(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
      void **csp
)
{
      unsigned int nr;

      for (nr = 0; ; nr++) {
            int (*info_f)(void *, uint32_t, unsigned int,
                  int (**)(void *, uint32_t, unsigned int, uint32_t),
                  void **);
            void *info_s;

            if (nr == b->member_count) {
                  /* No info found. */
                  return -1;
            }
            if (b->member[nr].s == s) {
                  /* Don't ask myself. */
                  continue;
            }
            info_f = b->member[nr].f->iow_info;
            info_s = b->member[nr].s;
            if (info_f
             && info_f(info_s, port, bs, cfp, csp) == 0) {
                  return 0;
            }
      }
}

static int
_sig_host_bus_iow_dummy(
      void *s,
      uint32_t port,
      unsigned int bs,
      uint32_t val
)
{
      return 1;
}

int
sig_host_bus_iow(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs,
      uint32_t val
)
{
      int (*cf)(void *, uint32_t, unsigned int, uint32_t);
      void *cs;
      unsigned int nr;

      assert((port & 3) == 0);

      if (_sig_host_bus_iow_lookup(b, port, bs, &cf, &cs)) {
            return cf(cs, port, bs, val);
      }

      if (sig_host_bus_iow_info(b, s, port, bs, &cf, &cs) == 0) {
            _sig_host_bus_iow_add(b, port, bs, cf, cs);
            return cf(cs, port, bs, val);
      }

#if 0
      fprintf(stderr, "INFO: No IOW info for 0x%04x 0x%x\n", port, bs);
#endif

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  break;
            }
            if (b->member[nr].s == s) {
                  continue;
            }
            cf = b->member[nr].f->iow;
            cs = b->member[nr].s;
            if (cf
             && cf(cs, port, bs, val) == 0) {
                  _sig_host_bus_iow_add(b, port, bs, cf, cs);
                  return 0;
            }
      }

      cf = _sig_host_bus_iow_dummy;
      cs = 0;
      _sig_host_bus_iow_add(b, port, bs, cf, cs);
      return 1;
}

static inline unsigned int
_sig_host_bus_map_hash(unsigned int state, uint32_t addr)
{
      return (addr >> 12) % SIG_HOST_BUS_HASH_SIZE;
}

static inline __attribute__((always_inline)) struct sig_host_bus_main_map *
_sig_host_bus_map_lookup(
      struct sig_host_bus_main *b,
      unsigned int state,
      unsigned long addr
)
{
      unsigned int hash;
      struct sig_host_bus_main_map *m;

      addr &= ~0xfff;

      hash = _sig_host_bus_map_hash(state, addr);

      for (m = b->map_hash_first[hash]; ; m = m->hash_next) {
            if (! m) {
                  /*
                   * Not Found
                   */
                  return (struct sig_host_bus_main_map *) 0;
            }
            if (m->state == state
             && m->addr == addr) {
                  /*
                   * Found
                   */
                  /* Don't update LRU list. */
                  /* Costs too much... */
                  return m;
            }
      }
}

static __attribute__((always_inline)) struct sig_host_bus_main_map *
_sig_host_bus_map_add(
      struct sig_host_bus_main *b,
      unsigned int state,
      unsigned long addr
)
{
      char *haddr_mr;
      char *haddr_mw;
      char *haddr_mx;
      unsigned int hash;
      struct sig_host_bus_main_map *m;

      addr &= ~0xfff;

      if (sig_host_bus_map(b, b, state, addr, 0x1000,
                  &haddr_mr, &haddr_mw, &haddr_mx) != 0) {
            haddr_mr = NULL;
            haddr_mw = NULL;
            haddr_mx = NULL;
      }

      /* Get entry from LRU list. */
      m = b->map_lru_last;

      /* Remove from LRU list. */
      assert(m->lru_prev);
      m->lru_prev->lru_next = 0;
      b->map_lru_last = m->lru_prev;

      if (m->addr != -1) {
            /* Remove from HASH list. */
            hash = _sig_host_bus_map_hash(m->state, m->addr);
            if (m->hash_prev) {
                  m->hash_prev->hash_next = m->hash_next;
            } else {
                  b->map_hash_first[hash] = m->hash_next;
            }
            if (m->hash_next) {
                  m->hash_next->hash_prev = m->hash_prev;
            } else {
                  b->map_hash_last[hash] = m->hash_prev;
            }
      }

      /* Add new info. */
      m->state = state;
      m->addr = addr;
      m->va_mr = (uint32_t *) haddr_mr;
      m->va_mw = (uint32_t *) haddr_mw;
      m->va_mx = (uint32_t *) haddr_mx;

      /* Add to HASH list. */
      hash = _sig_host_bus_map_hash(state, addr);
      m->hash_prev = 0;
      m->hash_next = b->map_hash_first[hash];
      b->map_hash_first[hash] = m;
      if (m->hash_next) {
            m->hash_next->hash_prev = m;
      } else {
            b->map_hash_last[hash] = m;
      }

      /* Add to LRU list. */
      m->lru_prev = 0;
      m->lru_next = b->map_lru_first;
      b->map_lru_first = m;
      m->lru_next->lru_prev = m;

      return m;
}

static void
_sig_host_bus_map_flush(
      struct sig_host_bus_main *b,
      unsigned long addr,
      unsigned long len
)
{
      unsigned int hash;
      unsigned int i;
      struct sig_host_bus_main_map *m;

      for (i = 0; i < sizeof(b->map) / sizeof(b->map[0]); i++) {
            m = &b->map[i];

            if (m->addr == -1
             || m->addr < addr
             || addr + len - 1 < m->addr) {
                  continue;
            }

            /* Remove from LRU list. */
            if (m->lru_prev) {
                  m->lru_prev->lru_next = m->lru_next;
            } else {
                  b->map_lru_first = m->lru_next;
            }
            if (m->lru_next) {
                  m->lru_next->lru_prev = m->lru_prev;
            } else {
                  b->map_lru_last = m->lru_prev;
            }

            /* Remove from HASH list. */
            hash = _sig_host_bus_map_hash(m->state, m->addr);
            if (m->hash_prev) {
                  m->hash_prev->hash_next = m->hash_next;
            } else {
                  b->map_hash_first[hash] = m->hash_next;
            }
            if (m->hash_next) {
                  m->hash_next->hash_prev = m->hash_prev;
            } else {
                  b->map_hash_last[hash] = m->hash_prev;
            }

            /* Unmap page. */
            m->state = -1;
            m->addr = -1;

            /* Don't add empty entry to HASH list. */

            /* Add to LRU list. */
            m->lru_prev = b->map_lru_last;
            m->lru_next = 0;
            m->lru_prev->lru_next = m;
            b->map_lru_last = m;
      }
}

int
sig_host_bus_mr(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_map *m;
      uint32_t *from;
      unsigned int nr;
      int (*func)(void *, unsigned int, uint32_t, unsigned int, uint32_t *);

      m = _sig_host_bus_map_lookup(b, state, addr);
      if (! m) {
            m = _sig_host_bus_map_add(b, state, addr);
      }
      if (m->va_mr) {
            from = m->va_mr + ((addr & 0xffc) >> 2);

            /* No need to obey `bs'. */
            *valp = *from;

            return 0;
      }

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  return -1;
            }
            if (b->member[nr].s == s
             || ! b->member[nr].f
             || ! b->member[nr].f->mr) {
                  continue;
            }
            func = b->member[nr].f->mr;
            if (func(b->member[nr].s, state, addr, bs, valp) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_mw(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_map *m;
      uint32_t *to;
      unsigned int nr;
      int (*func)(void *, unsigned int, uint32_t, unsigned int, uint32_t);

      m = _sig_host_bus_map_lookup(b, state, addr);
      if (! m) {
            m = _sig_host_bus_map_add(b, state, addr);
      }
      if (m->va_mw) {
            to = m->va_mw + ((addr & 0xffc) >> 2);

            if ((bs >> 0) & 1) {
                  *to &= ~(0xff << 0);
                  *to |= val & (0xff << 0);
            }
            if ((bs >> 1) & 1) {
                  *to &= ~(0xff << 8);
                  *to |= val & (0xff << 8);
            }
            if ((bs >> 2) & 1) {
                  *to &= ~(0xff << 16);
                  *to |= val & (0xff << 16);
            }
            if ((bs >> 3) & 1) {
                  *to &= ~(0xff << 24);
                  *to |= val & (0xff << 24);
            }
            return 0;
      }

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  return -1;
            }
            if (b->member[nr].s == s
             || ! b->member[nr].f
             || ! b->member[nr].f->mw) {
                  continue;
            }
            func = b->member[nr].f->mw;
            if (func(b->member[nr].s, state, addr, bs, val) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_inta_addr(
      struct sig_host_bus_main *b,
      void *s
)
{
      unsigned int nr;
      int (*func)(void *);

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  return 1;
            }
            if (b->member[nr].s == s) {
                  continue;
            }
            func = b->member[nr].f->inta_addr;
            if (func
             && func(b->member[nr].s) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_inta_data(
      struct sig_host_bus_main *b,
      void *s,
      uint8_t *valp
)
{
      unsigned int nr;
      int (*func)(void *, uint8_t *);

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  return 1;
            }
            if (b->member[nr].s == s) {
                  continue;
            }
            func = b->member[nr].f->inta_data;
            if (func
             && func(b->member[nr].s, valp) == 0) {
                  return 0;
            }
      }
}

int
sig_host_bus_map(
      struct sig_host_bus_main *b,
      void *s,
      unsigned int state,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p,
      char **haddr_mx_p
)
{
      unsigned int nr;
      int (*func)(void *, unsigned int, unsigned long, unsigned int,
                  char **, char **, char **);

      for (nr = 0; ; nr++) {
            if (nr == b->member_count) {
                  return 1;
            }
            if (b->member[nr].s == s) {
                  continue;
            }
            func = b->member[nr].f->map;
            if (func
             && func(b->member[nr].s, state, pa, len,
                        haddr_mr_p, haddr_mw_p, haddr_mx_p) == 0) {
                  return 0;
            }
      }
}

void
sig_host_bus_ior_info_flush(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs
)
{
      unsigned int hash;
      struct sig_host_bus_main_ior *m;

      hash = _sig_host_bus_io_hash(port, bs);

      for (m = b->ior_hash_first[hash]; ; m = m->hash_next) {
            if (! m) {
                  /* Not found. */
                  return;
            }
            if (port == m->port
             && (bs == m->bs
              || bs == 0)) {
                  /* Found. */
                  /* Remove from LRU list. */
                  if (m->lru_prev) {
                        m->lru_prev->lru_next = m->lru_next;
                  } else {
                        b->ior_lru_first = m->lru_next;
                  }
                  if (m->lru_next) {
                        m->lru_next->lru_prev = m->lru_prev;
                  } else {
                        b->ior_lru_last = m->lru_prev;
                  }

                  /* Remove from HASH list. */
                  hash = _sig_host_bus_io_hash(port, bs);
                  if (m->hash_prev) {
                        m->hash_prev->hash_next = m->hash_next;
                  } else {
                        b->ior_hash_first[hash] = m->hash_next;
                  }
                  if (m->hash_next) {
                        m->hash_next->hash_prev = m->hash_prev;
                  } else {
                        b->ior_hash_last[hash] = m->hash_prev;
                  }

                  /* Remove info. */
                  m->port = -1;
                  m->bs = -1;

                  /* Don't add empty entry to HASH list. */

                  /* Add to LRU list. */
                  m->lru_prev = b->ior_lru_last;
                  m->lru_next = 0;
                  m->lru_prev->lru_next = m;
                  b->ior_lru_last = m;
                  return;
            }
      }
}

void
sig_host_bus_iow_info_flush(
      struct sig_host_bus_main *b,
      void *s,
      uint32_t port,
      unsigned int bs
)
{
      unsigned int hash;
      struct sig_host_bus_main_iow *m;

      hash = _sig_host_bus_io_hash(port, bs);

      for (m = b->iow_hash_first[hash]; ; m = m->hash_next) {
            if (! m) {
                  /* Not found. */
                  return;
            }
            if (port == m->port
             && (bs == m->bs
              || bs == 0)) {
                  /* Found. */
                  /* Remove from LRU list. */
                  if (m->lru_prev) {
                        m->lru_prev->lru_next = m->lru_next;
                  } else {
                        b->iow_lru_first = m->lru_next;
                  }
                  if (m->lru_next) {
                        m->lru_next->lru_prev = m->lru_prev;
                  } else {
                        b->iow_lru_last = m->lru_prev;
                  }

                  /* Remove from HASH list. */
                  hash = _sig_host_bus_io_hash(port, bs);
                  if (m->hash_prev) {
                        m->hash_prev->hash_next = m->hash_next;
                  } else {
                        b->iow_hash_first[hash] = m->hash_next;
                  }
                  if (m->hash_next) {
                        m->hash_next->hash_prev = m->hash_prev;
                  } else {
                        b->iow_hash_last[hash] = m->hash_prev;
                  }

                  /* Remove info. */
                  m->port = -1;
                  m->bs = -1;

                  /* Don't add empty entry to HASH list. */

                  /* Add to LRU list. */
                  m->lru_prev = b->iow_lru_last;
                  m->lru_next = 0;
                  m->lru_prev->lru_next = m;
                  b->iow_lru_last = m;
                  return;
            }
      }
}

void
sig_host_bus_unmap(
      struct sig_host_bus_main *b,
      void *s,
      unsigned long pa,
      unsigned long len
)
{
      unsigned int nr;
      void (*func)(void *, unsigned long, unsigned long);

      assert((pa & 0x00000fff) == 0x00000000);
      len = (len + 0x00000fff) & 0xfffff000;

      _sig_host_bus_map_flush(b, pa, len);

      for (nr = 0; nr < b->member_count; nr++) {
            if (b->member[nr].s == s) {
                  continue;
            }
            func = b->member[nr].f->unmap;
            if (func) {
                  func(b->member[nr].s, pa, len);
            }
      }
}

void
sig_host_bus_main_connect(
      struct sig_host_bus_main *b,
      void *s,
      const struct sig_host_bus_main_funcs *f
)
{
      assert(b->member_count < sizeof(b->member) / sizeof(b->member[0]));

      b->member[b->member_count].s = s;
      b->member[b->member_count].f = f;
      b->member_count++;
}


struct sig_host_bus_main *
sig_host_bus_main_init(const char *name, int nr)
{
      struct sig_host_bus_main *b;
      struct sig_host_bus_main_ior *ior;
      struct sig_host_bus_main_iow *iow;
      struct sig_host_bus_main_map *m;
      unsigned int i;

      b = shm_map(name, nr, sizeof(*b), 0);

      b->member_count = 0;

      b->ior_lru_first = 0;
      b->ior_lru_last = 0;
      for (i = 0; i < sizeof(b->ior_hash_first) / sizeof(b->ior_hash_first[0]); i++) {
            b->ior_hash_first[i] = 0;
            b->ior_hash_last[i] = 0;
      }
      for (i = 0; i < sizeof(b->ior) / sizeof(b->ior[0]); i++) {
            ior = &b->ior[i];
            ior->port = -1;
            ior->bs = -1;

            /* Don't add empty entry to HASH list. */

            /* Add to LRU list. */
            ior->lru_prev = b->ior_lru_last;
            ior->lru_next = 0;
            if (ior->lru_prev) {
                  ior->lru_prev->lru_next = ior;
            } else {
                  b->ior_lru_first = ior;
            }
            b->ior_lru_last = ior;
      }

      b->iow_lru_first = 0;
      b->iow_lru_last = 0;
      for (i = 0; i < sizeof(b->iow_hash_first) / sizeof(b->iow_hash_first[0]); i++) {
            b->iow_hash_first[i] = 0;
            b->iow_hash_last[i] = 0;
      }
      for (i = 0; i < sizeof(b->iow) / sizeof(b->iow[0]); i++) {
            iow = &b->iow[i];
            iow->port = -1;
            iow->bs = -1;

            /* Don't add empty entry to HASH list. */

            /* Add to LRU list. */
            iow->lru_prev = b->iow_lru_last;
            iow->lru_next = 0;
            if (iow->lru_prev) {
                  iow->lru_prev->lru_next = iow;
            } else {
                  b->iow_lru_first = iow;
            }
            b->iow_lru_last = iow;
      }

      b->map_lru_first = 0;
      b->map_lru_last = 0;
      for (i = 0; i < sizeof(b->map_hash_first) / sizeof(b->map_hash_first[0]); i++) {
            b->map_hash_first[i] = 0;
            b->map_hash_last[i] = 0;
      }
      for (i = 0; i < sizeof(b->map) / sizeof(b->map[0]); i++) {
            m = &b->map[i];
            m->state = -1;
            m->addr = -1;
            m->va_mr = NULL;
            m->va_mw = NULL;
            m->va_mx = NULL;

            /* Don't add empty entry to HASH list. */

            /* Add to LRU list. */
            m->lru_prev = b->map_lru_last;
            m->lru_next = 0;
            if (m->lru_prev) {
                  m->lru_prev->lru_next = m;
            } else {
                  b->map_lru_first = m;
            }
            b->map_lru_last = m;
      }

      return b;
}

static int
sig_host_bus_main_s0_type_addr(
      void *_f,
      unsigned int type,
      uint32_t addr
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_type_addr(f->s1, f, type, addr);
}

static int
sig_host_bus_main_s0_read_data(
      void *_f,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_read_data(f->s1, f, bs, valp);
}

static int
sig_host_bus_main_s0_write_data(
      void *_f,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_write_data(f->s1, f, bs, val);
}

static int
sig_host_bus_main_s0_ior(
      void *_f,
      uint32_t port,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_ior(f->s1, f, port, bs, valp);
}

static int
sig_host_bus_main_s0_ior_info(
      void *_f,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
      void **csp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_ior_info(f->s1, f, port, bs, cfp, csp);
}

static int
sig_host_bus_main_s0_iow(
      void *_f,
      uint32_t port,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_iow(f->s1, f, port, bs, val);
}

static int
sig_host_bus_main_s0_iow_info(
      void *_f,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
      void **csp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_iow_info(f->s1, f, port, bs, cfp, csp);
}

static int
sig_host_bus_main_s0_mr(
      void *_f,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_mr(f->s1, f, state, addr, bs, valp);
}

static int
sig_host_bus_main_s0_mw(
      void *_f,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_mw(f->s1, f, state, addr, bs, val);
}

static int
sig_host_bus_main_s0_map(
      void *_f,
      unsigned int state,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p,
      char **haddr_mx_p
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_map(f->s1, f, state, pa, len,
                  haddr_mr_p, haddr_mw_p, haddr_mx_p);
}

static int
sig_host_bus_main_s0_inta_addr(
      void *_f
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_inta_addr(f->s1, f);
}

static int
sig_host_bus_main_s0_inta_data(
      void *_f,
      uint8_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_inta_data(f->s1, f, valp);
}

static void
sig_host_bus_main_s0_unmap(
      void *_f,
      unsigned long pa,
      unsigned long len
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_unmap(f->s1, f, pa, len);
}

static int
sig_host_bus_main_s1_type_addr(
      void *_f,
      unsigned int type,
      uint32_t addr
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_type_addr(f->s0, f, type, addr);
}

static int
sig_host_bus_main_s1_read_data(
      void *_f,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_read_data(f->s0, f, bs, valp);
}

static int
sig_host_bus_main_s1_write_data(
      void *_f,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_write_data(f->s0, f, bs, val);
}

static int
sig_host_bus_main_s1_ior(
      void *_f,
      uint32_t port,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_ior(f->s0, f, port, bs, valp);
}

static int
sig_host_bus_main_s1_ior_info(
      void *_f,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
      void **csp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_ior_info(f->s0, f, port, bs, cfp, csp);
}

static int
sig_host_bus_main_s1_iow(
      void *_f,
      uint32_t port,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_iow(f->s0, f, port, bs, val);
}

static int
sig_host_bus_main_s1_iow_info(
      void *_f,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
      void **csp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_iow_info(f->s0, f, port, bs, cfp, csp);
}

static int
sig_host_bus_main_s1_mr(
      void *_f,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_mr(f->s0, f, state, addr, bs, valp);
}

static int
sig_host_bus_main_s1_mw(
      void *_f,
      unsigned int state,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_mw(f->s0, f, state, addr, bs, val);
}

static int
sig_host_bus_main_s1_map(
      void *_f,
      unsigned int state,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p,
      char **haddr_mx_p
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_map(f->s0, f, state, pa, len,
                  haddr_mr_p, haddr_mw_p, haddr_mx_p);
}

static int
sig_host_bus_main_s1_inta_addr(
      void *_f
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_inta_addr(f->s0, f);
}

static int
sig_host_bus_main_s1_inta_data(
      void *_f,
      uint8_t *valp
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_inta_data(f->s0, f, valp);
}

static void
sig_host_bus_main_s1_unmap(
      void *_f,
      unsigned long pa,
      unsigned long len
)
{
      struct sig_host_bus_main_merge *f
                  = (struct sig_host_bus_main_merge *) _f;

      return sig_host_bus_unmap(f->s0, f, pa, len);
}

struct sig_host_bus_main_merge *
sig_host_bus_main_merge(
      struct sig_host_bus_main *s0,
      struct sig_host_bus_main *s1
)
{
      static const struct sig_host_bus_main_funcs mb_funcs = {
            .type_addr = sig_host_bus_main_s0_type_addr,
            .read_data = sig_host_bus_main_s0_read_data,
            .write_data = sig_host_bus_main_s0_write_data,
            .ior = sig_host_bus_main_s0_ior,
            .iow = sig_host_bus_main_s0_iow,
            .ior_info = sig_host_bus_main_s0_ior_info,
            .iow_info = sig_host_bus_main_s0_iow_info,
            .mr = sig_host_bus_main_s0_mr,
            .mw = sig_host_bus_main_s0_mw,
            .map = sig_host_bus_main_s0_map,
            .inta_addr = sig_host_bus_main_s0_inta_addr,
            .inta_data = sig_host_bus_main_s0_inta_data,
            .unmap = sig_host_bus_main_s0_unmap,
      };
      static const struct sig_host_bus_main_funcs cpu_funcs = {
            .type_addr = sig_host_bus_main_s1_type_addr,
            .read_data = sig_host_bus_main_s1_read_data,
            .write_data = sig_host_bus_main_s1_write_data,
            .ior = sig_host_bus_main_s1_ior,
            .iow = sig_host_bus_main_s1_iow,
            .ior_info = sig_host_bus_main_s1_ior_info,
            .iow_info = sig_host_bus_main_s1_iow_info,
            .mr = sig_host_bus_main_s1_mr,
            .mw = sig_host_bus_main_s1_mw,
            .map = sig_host_bus_main_s1_map,
            .inta_addr = sig_host_bus_main_s1_inta_addr,
            .inta_data = sig_host_bus_main_s1_inta_data,
            .unmap = sig_host_bus_main_s1_unmap,
      };
      struct sig_host_bus_main_merge *m;

      m = malloc(sizeof(*m));
      assert(m);

      m->s0 = s0;
      sig_host_bus_main_connect(s0, m, &mb_funcs);
      m->s1 = s1;
      sig_host_bus_main_connect(s1, m, &cpu_funcs);

      return m;
}

void
sig_host_bus_main_split(struct sig_host_bus_main_merge *m)
{
      fixme();
}

void
sig_host_bus_main_create(const char *name, int nr)
{
      shm_create(name, nr, sizeof(struct sig_host_bus_main));
}

void
sig_host_bus_main_destroy(const char *name, int nr)
{
      shm_destroy(name, nr);
}

struct sig_host_bus *
sig_host_bus_init(const char *name, unsigned int nr)
{
      struct sig_host_bus *b;
      char n[1000];

      b = shm_map(name, nr, sizeof(*b), 0);
      b->type = SIG_GEN_HOST_BUS;

      sprintf(n, "%s-power", name);
      b->power = sig_boolean_init(n, nr);
      sprintf(n, "%s-n_reset", name);
      b->n_reset = sig_boolean_init(n, nr);
      sprintf(n, "%s-n_init", name);
      b->n_init = sig_boolean_init(n, nr);
      sprintf(n, "%s-main", name);
      b->main = sig_host_bus_main_init(n, nr);
      sprintf(n, "%s-lint0", name);
      b->lint0 = sig_boolean_or_init(n, nr);
      sprintf(n, "%s-lint1", name);
      b->lint1 = sig_boolean_or_init(n, nr);
      sprintf(n, "%s-smi", name);
      b->smi = sig_boolean_init(n, nr);
      sprintf(n, "%s-a20", name);
      b->a20 = sig_boolean_init(n, nr);
      sprintf(n, "%s-icc", name);
      b->icc = sig_icc_bus_init(n, nr);
      sprintf(n, "%s-n_ferr", name);
      b->n_ferr = sig_boolean_or_init(n, nr);
      sprintf(n, "%s-n_ignne", name);
      b->n_ignne = sig_boolean_init(n, nr);

      return b;
}

void
sig_host_bus_create(const char *name, unsigned int nr)
{
      char n[1000];

      shm_create(name, nr, sizeof(struct sig_host_bus));

      sprintf(n, "%s-power", name);
      sig_boolean_create(n, nr);
      sprintf(n, "%s-n_reset", name);
      sig_boolean_create(n, nr);
      sprintf(n, "%s-n_init", name);
      sig_boolean_create(n, nr);
      sprintf(n, "%s-main", name);
      sig_host_bus_main_create(n, nr);
      sprintf(n, "%s-lint0", name);
      sig_boolean_or_create(n, nr);
      sprintf(n, "%s-lint1", name);
      sig_boolean_or_create(n, nr);
      sprintf(n, "%s-smi", name);
      sig_boolean_create(n, nr);
      sprintf(n, "%s-a20", name);
      sig_boolean_create(n, nr);
      sprintf(n, "%s-icc", name);
      sig_icc_bus_create(n, nr);
      sprintf(n, "%s-n_ferr", name);
      sig_boolean_or_create(n, nr);
      sprintf(n, "%s-n_ignne", name);
      sig_boolean_create(n, nr);
}

void
sig_host_bus_destroy(const char *name, unsigned int nr)
{
      char n[1000];

      shm_destroy(name, nr);

      sprintf(n, "%s-power", name);
      sig_boolean_destroy(n, nr);
      sprintf(n, "%s-n_reset", name);
      sig_boolean_destroy(n, nr);
      sprintf(n, "%s-n_init", name);
      sig_boolean_destroy(n, nr);
      sprintf(n, "%s-main", name);
      sig_host_bus_main_destroy(n, nr);
      sprintf(n, "%s-lint0", name);
      sig_boolean_or_destroy(n, nr);
      sprintf(n, "%s-lint1", name);
      sig_boolean_or_destroy(n, nr);
      sprintf(n, "%s-smi", name);
      sig_boolean_destroy(n, nr);
      sprintf(n, "%s-a20", name);
      sig_boolean_destroy(n, nr);
      sprintf(n, "%s-icc", name);
      sig_icc_bus_destroy(n, nr);
      sprintf(n, "%s-n_ferr", name);
      sig_boolean_or_destroy(n, nr);
      sprintf(n, "%s-n_ignne", name);
      sig_boolean_destroy(n, nr);
}

Generated by  Doxygen 1.6.0   Back to index