[PATCH 1/2] bsp/motorola_powerpc: Add MPCI support for Qemu

Sebastian Huber sebastian.huber at embedded-brains.de
Tue Mar 29 11:47:39 UTC 2016


---
 .../libbsp/powerpc/motorola_powerpc/Makefile.am    |   2 +
 .../libbsp/powerpc/motorola_powerpc/include/bsp.h  |  10 +
 .../libbsp/powerpc/motorola_powerpc/shmsupp/mpci.c | 379 +++++++++++++++++++++
 3 files changed, 391 insertions(+)
 create mode 100644 c/src/lib/libbsp/powerpc/motorola_powerpc/shmsupp/mpci.c

diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
index e09820608..3576b75 100644
--- a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
@@ -136,6 +136,8 @@ noinst_PROGRAMS         += ne2000.rel
 ne2000_rel_SOURCES       = ../../i386/pc386/ne2000/ne2000.c
 ne2000_rel_CPPFLAGS      = $(AM_CPPFLAGS) $(ne2000_CPPFLAGS)
 ne2000_rel_LDFLAGS       = $(RTEMS_RELLDFLAGS)
+
+libbsp_a_SOURCES += shmsupp/mpci.c
 endif
 endif
 
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/include/bsp.h b/c/src/lib/libbsp/powerpc/motorola_powerpc/include/bsp.h
index 493a37d..26960dc 100644
--- a/c/src/lib/libbsp/powerpc/motorola_powerpc/include/bsp.h
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/include/bsp.h
@@ -241,6 +241,16 @@ void zero_bss(void);
  */
 void VIA_isa_bridge_interrupts_setup(void);
 
+#if defined(RTEMS_MULTIPROCESSING) && defined(RTEMS_NETWORKING)
+
+extern rtems_mpci_table net_mpci_table;
+
+#define CONFIGURE_MP_MPCI_TABLE_POINTER &net_mpci_table
+
+#define MPCI_Print_statistics() do { } while (0)
+
+#endif /* defined(RTEMS_MULTIPROCESSING) && defined(RTEMS_NETWORKING) */
+
 #endif
 
 #ifdef __cplusplus
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/shmsupp/mpci.c b/c/src/lib/libbsp/powerpc/motorola_powerpc/shmsupp/mpci.c
new file mode 100644
index 0000000..e7bc3ce
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/shmsupp/mpci.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+
+#if defined(RTEMS_MULTIPROCESSING) && defined(RTEMS_NETWORKING)
+
+#include <sys/select.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <rtems/chain.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/score/objectimpl.h>
+
+#define MAX_PACKET_SIZE 512
+
+#define MAX_NODES 2
+
+#define PACKET_COUNT (32 * MAX_NODES)
+
+#define IP_ADDR_SIZE 16
+
+#define MPCI_PORT 1234
+
+typedef struct {
+  rtems_chain_node node;
+  uint32_t dest;
+  char data[MAX_PACKET_SIZE];
+} net_mpci_packet;
+
+typedef struct {
+  rtems_chain_control outbound_packets;
+  rtems_id outbound_server;
+  RTEMS_INTERRUPT_LOCK_MEMBER(outbound_lock)
+  rtems_chain_control free_packets;
+  RTEMS_INTERRUPT_LOCK_MEMBER(free_lock)
+  int outbound_fds[MAX_NODES];
+  int inbound_fds[MAX_NODES - 1];
+  int inbound_nfds;
+  net_mpci_packet packets[PACKET_COUNT];
+  char ip_addr[IP_ADDR_SIZE];
+} net_mpci_context;
+
+static net_mpci_context net_mpci_instance;
+
+static net_mpci_packet *net_mpci_get_outbound_packet(net_mpci_context *ctx)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_chain_node *node;
+
+  rtems_interrupt_lock_acquire(&ctx->outbound_lock, &lock_context);
+  node = rtems_chain_get_unprotected(&ctx->outbound_packets);
+  rtems_interrupt_lock_release(&ctx->outbound_lock, &lock_context);
+
+  return (net_mpci_packet *) node;
+}
+
+static void net_mpci_free_packet(
+  net_mpci_context *ctx,
+  net_mpci_packet *packet
+)
+{
+  rtems_interrupt_lock_context lock_context;
+
+  rtems_interrupt_lock_acquire(&ctx->free_lock, &lock_context);
+  rtems_chain_prepend_unprotected(&ctx->free_packets, &packet->node);
+  rtems_interrupt_lock_release(&ctx->free_lock, &lock_context);
+}
+
+static void net_mpci_write(
+  net_mpci_context *ctx,
+  net_mpci_packet *packet,
+  uint32_t dest
+)
+{
+  ssize_t n =
+    write(ctx->outbound_fds[dest - 1], &packet->data[0], sizeof(packet->data));
+  assert(n == MAX_PACKET_SIZE);
+}
+
+static void net_mpci_dest_to_ip_addr(uint32_t dest, char ip_addr[IP_ADDR_SIZE])
+{
+  int n = snprintf(&ip_addr[0], IP_ADDR_SIZE, "10.0.1.%" PRIu32, dest);
+  assert(n < IP_ADDR_SIZE);
+}
+
+static void net_mpci_outbound_server(rtems_task_argument arg)
+{
+  net_mpci_context *ctx = (net_mpci_context *) arg;
+  uint32_t n = _Objects_Maximum_nodes;
+  uint32_t self = _Objects_Local_node;
+  uint32_t dest;
+
+  for (dest = 1; dest <= n; ++dest) {
+    if (dest != self) {
+      int fd;
+      char ip_addr[IP_ADDR_SIZE];
+      struct sockaddr_in addr;
+      int ok;
+      int rv;
+
+      fd = socket(PF_INET, SOCK_STREAM, 0);
+      assert(fd >= 0);
+
+      net_mpci_dest_to_ip_addr(dest, ip_addr);
+
+      memset(&addr, 0, sizeof(addr));
+      addr.sin_family = AF_INET;
+      addr.sin_port = htons(MPCI_PORT);
+      ok = inet_aton(&ip_addr[0], &addr.sin_addr);
+      assert(ok != 0);
+
+      rv = connect(fd, (const struct sockaddr *) &addr, sizeof(addr));
+      assert(rv == 0);
+
+      ctx->outbound_fds[dest - 1] = fd;
+    }
+  }
+
+  while (true) {
+    rtems_status_code sc;
+    net_mpci_packet *packet;
+
+    sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+    assert(sc == RTEMS_SUCCESSFUL);
+
+    while ((packet = net_mpci_get_outbound_packet(ctx))) {
+      if (packet->dest != MPCI_ALL_NODES) {
+        net_mpci_write(ctx, packet, packet->dest);
+      } else {
+        uint32_t n = _Objects_Maximum_nodes;
+        uint32_t self = _Objects_Local_node;
+        uint32_t dest;
+
+        for (dest = 1; dest <= n; ++dest) {
+          if (dest != self) {
+            net_mpci_write(ctx, packet, dest);
+          }
+        }
+      }
+
+      net_mpci_free_packet(ctx, packet);
+    }
+  }
+}
+
+static void net_mpci_atexit(void)
+{
+  sleep(30);
+}
+
+static void net_mpci_init(void)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+
+  assert(_Objects_Maximum_nodes <= MAX_NODES);
+
+  ctx->inbound_nfds = -1;
+  rtems_chain_initialize_empty(&ctx->outbound_packets);
+  rtems_interrupt_lock_initialize(&ctx->outbound_packets, "MPCI Outbound");
+  rtems_chain_initialize(
+    &ctx->free_packets,
+    &ctx->packets[0],
+    PACKET_COUNT,
+    sizeof(ctx->packets[0])
+  );
+  rtems_interrupt_lock_initialize(&ctx->free_packets, "MPCI Free");
+
+  atexit(net_mpci_atexit);
+}
+
+static net_mpci_packet *net_mpci_prefix_to_packet(rtems_packet_prefix *prefix)
+{
+  return RTEMS_CONTAINER_OF(prefix, net_mpci_packet, data);
+}
+
+static rtems_packet_prefix *net_mpci_packet_to_prefix(net_mpci_packet *packet)
+{
+  return (rtems_packet_prefix *) &packet->data[0];
+}
+
+static net_mpci_packet *net_mpci_get_packet(net_mpci_context *ctx)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_chain_node *node;
+
+  rtems_interrupt_lock_acquire(&ctx->free_lock, &lock_context);
+  node = rtems_chain_get_unprotected(&ctx->free_packets);
+  rtems_interrupt_lock_release(&ctx->free_lock, &lock_context);
+
+  return (net_mpci_packet *) node;
+}
+
+static void net_mpci_get_prefix(rtems_packet_prefix **prefix_ptr)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+  net_mpci_packet *packet = net_mpci_get_packet(ctx);
+
+  if (packet != NULL) {
+    *prefix_ptr = net_mpci_packet_to_prefix(packet);
+  } else {
+    *prefix_ptr = NULL;
+  }
+}
+
+static void net_mpci_return_prefix(rtems_packet_prefix *prefix)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+  net_mpci_packet *packet = net_mpci_prefix_to_packet(prefix);
+
+  net_mpci_free_packet(ctx, packet);
+}
+
+static void net_mpci_send_prefix(uint32_t dest, rtems_packet_prefix *prefix)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+  net_mpci_packet *packet = net_mpci_prefix_to_packet(prefix);
+  rtems_status_code sc;
+  rtems_interrupt_lock_context lock_context;
+
+  packet->dest = dest;
+
+  rtems_interrupt_lock_acquire(&ctx->outbound_lock, &lock_context);
+  rtems_chain_append_unprotected(&ctx->outbound_packets, &packet->node);
+  rtems_interrupt_lock_release(&ctx->outbound_lock, &lock_context);
+
+  sc = rtems_event_transient_send(ctx->outbound_server);
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void net_mpci_receive_prefix(rtems_packet_prefix **prefix_ptr)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+  uint32_t n = _Objects_Maximum_nodes - 1;
+  uint32_t i;
+  struct fd_set read_set;
+  int rv;
+
+  FD_ZERO(&read_set);
+
+  for (i = 0; i < n; ++i) {
+    FD_SET(ctx->inbound_fds[i], &read_set);
+  }
+
+  rv = select(ctx->inbound_nfds, &read_set, NULL, NULL, NULL);
+  assert(rv > 0);
+
+  for (i = 0; i < n; ++i) {
+    int fd = ctx->inbound_fds[i];
+
+    if (FD_ISSET(fd, &read_set)) {
+      net_mpci_packet *packet;
+      size_t j;
+
+      packet = net_mpci_get_packet(ctx);
+      assert(packet != NULL);
+
+      j = 0;
+
+      do {
+        ssize_t n = read(fd, &packet->data[j], sizeof(packet->data) - j);
+        assert(n > 0);
+
+        j += (size_t) n;
+      } while (j != sizeof(packet->data));
+
+      *prefix_ptr = net_mpci_packet_to_prefix(packet);
+      return;
+    }
+  }
+}
+
+static struct rtems_bsdnet_ifconfig net_mpci_ifconfig = {
+  .name = RTEMS_BSP_NETWORK_DRIVER_NAME,
+  .attach = RTEMS_BSP_NETWORK_DRIVER_ATTACH,
+  .ip_address = &net_mpci_instance.ip_addr[0],
+  .ip_netmask = "255.255.255.0",
+};
+
+struct rtems_bsdnet_config rtems_bsdnet_config = {
+  .ifconfig = &net_mpci_ifconfig,
+  .network_task_priority = UINT32_MAX,
+  .gateway = "10.0.1.254"
+};
+
+__attribute__((__constructor__)) static void net_mpci_init_network(void)
+{
+  net_mpci_context *ctx = &net_mpci_instance;
+  uint32_t n = _Objects_Maximum_nodes;
+  uint32_t self = _Objects_Local_node;
+  uint32_t i;
+  rtems_status_code sc;
+  int rv;
+  int fd;
+  struct sockaddr_in addr;
+
+  net_mpci_dest_to_ip_addr(self, ctx->ip_addr);
+
+  rv = rtems_bsdnet_initialize_network();
+  assert(rv == 0);
+
+  sc = rtems_task_create(
+    rtems_build_name('M', 'P', 'C', 'I'),
+    1,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    RTEMS_DEFAULT_MODES,
+    &ctx->outbound_server
+  );
+  assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_start(
+    ctx->outbound_server,
+    net_mpci_outbound_server,
+    (rtems_task_argument) ctx
+  );
+  assert(sc == RTEMS_SUCCESSFUL);
+
+  fd = socket(PF_INET, SOCK_STREAM, 0);
+  assert(fd >= 0);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(MPCI_PORT);
+
+  rv = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
+  assert(rv == 0);
+
+  rv = listen(fd, 0);
+  assert(rv == 0);
+
+  for (i = 1; i < n; ++i) {
+    socklen_t addr_len;
+
+    addr_len = sizeof(addr);
+    rv = accept(fd, (struct sockaddr *) &addr, &addr_len);
+    assert(rv >= 0);
+
+    if (rv + 1 > ctx->inbound_nfds) {
+      ctx->inbound_nfds = rv + 1;
+    }
+
+    ctx->inbound_fds[i - 1] = rv;
+  }
+
+  rtems_multiprocessing_announce();
+}
+
+rtems_mpci_table net_mpci_table = {
+  .default_timeout = UINT32_MAX,
+  .maximum_packet_size = MAX_PACKET_SIZE,
+  .initialization = net_mpci_init,
+  .get_packet = net_mpci_get_prefix,
+  .return_packet = net_mpci_return_prefix,
+  .send_packet = net_mpci_send_prefix,
+  .receive_packet = net_mpci_receive_prefix
+};
+
+#endif /* defined(RTEMS_MULTIPROCESSING) && defined(RTEMS_NETWORKING) */
-- 
1.8.4.5



More information about the devel mailing list