summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/qoriq
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 09:53:31 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:44 +0200
commit031df3914990db0336a0d386fb53558b05de467e (patch)
tree4661e22f0cdb3f9d06879f0194b77c75f62bac79 /bsps/powerpc/qoriq
parentbsps: Move interrupt controller support to bsps (diff)
downloadrtems-031df3914990db0336a0d386fb53558b05de467e.tar.bz2
bsps: Move legacy network drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/powerpc/qoriq')
-rw-r--r--bsps/powerpc/qoriq/net/if_intercom.c297
-rw-r--r--bsps/powerpc/qoriq/net/network.c136
2 files changed, 433 insertions, 0 deletions
diff --git a/bsps/powerpc/qoriq/net/if_intercom.c b/bsps/powerpc/qoriq/net/if_intercom.c
new file mode 100644
index 0000000000..b692ced655
--- /dev/null
+++ b/bsps/powerpc/qoriq/net/if_intercom.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <info@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.
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
+#define __BSD_VISIBLE 1
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_mii_ioctl.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <bsp.h>
+#include <bsp/intercom.h>
+
+typedef struct {
+ struct arpcom arpcom;
+ int destination_core;
+ intercom_packet *packet;
+ unsigned transmitted_frames;
+ unsigned received_frames;
+} if_intercom_control;
+
+static if_intercom_control if_intercom;
+
+static struct mbuf *new_mbuf(struct ifnet *ifp, bool wait)
+{
+ struct mbuf *m = NULL;
+ int mw = wait ? M_WAIT : M_DONTWAIT;
+
+ MGETHDR(m, mw, MT_DATA);
+ if (m != NULL) {
+ MCLGET(m, mw);
+ if ((m->m_flags & M_EXT) != 0) {
+ m->m_pkthdr.rcvif = ifp;
+
+ return m;
+ } else {
+ m_free(m);
+ }
+ }
+
+ return NULL;
+}
+
+static void if_intercom_service(intercom_packet *packet, void *arg)
+{
+ rtems_bsdnet_semaphore_obtain();
+
+ if_intercom_control *self = arg;
+ struct ifnet *ifp = &self->arpcom.ac_if;
+ struct mbuf *m = new_mbuf(ifp, true);
+
+ memcpy(mtod(m, void *), packet->data, packet->size);
+
+ /* Ethernet header */
+ struct ether_header *eh = mtod(m, struct ether_header *);
+
+ /* Discard Ethernet header and CRC */
+ int sz = (int) packet->size - ETHER_HDR_LEN;
+
+ /* Update mbuf */
+ m->m_len = sz;
+ m->m_pkthdr.len = sz;
+ m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
+
+ /* Hand over */
+ ether_input(ifp, eh, m);
+
+ ++self->received_frames;
+ qoriq_intercom_free_packet(packet);
+
+ rtems_bsdnet_semaphore_release();
+}
+
+static intercom_packet *allocate_packet(void)
+{
+ intercom_packet *packet = qoriq_intercom_allocate_packet(
+ INTERCOM_TYPE_NETWORK,
+ INTERCOM_SIZE_2K
+ );
+
+ packet->size = 0;
+
+ return packet;
+}
+
+static struct mbuf *get_next_fragment(struct ifnet *ifp, struct mbuf *m)
+{
+ struct mbuf *n = NULL;
+ int size = 0;
+
+ while (true) {
+ if (m == NULL) {
+ /* Dequeue first fragment of the next frame */
+ IF_DEQUEUE(&ifp->if_snd, m);
+
+ /* Empty queue? */
+ if (m == NULL) {
+ return m;
+ }
+ }
+
+ /* Get fragment size */
+ size = m->m_len;
+
+ if (size > 0) {
+ /* Now we have a not empty fragment */
+ break;
+ } else {
+ /* Discard empty fragments */
+ m = m_free(m);
+ }
+ }
+
+ /* Discard empty successive fragments */
+ n = m->m_next;
+ while (n != NULL && n->m_len <= 0) {
+ n = m_free(n);
+ }
+ m->m_next = n;
+
+ return m;
+}
+
+static void if_intercom_start(struct ifnet *ifp)
+{
+ if_intercom_control *self = ifp->if_softc;
+ int destination_core = self->destination_core;
+ intercom_packet *packet = self->packet;
+ size_t size = packet->size;
+ char *data = packet->data + size;
+ struct mbuf *m = NULL;
+
+ while ((m = get_next_fragment(ifp, m)) != NULL) {
+ size_t fragment_size = (size_t) m->m_len;
+ size_t new_size = size + fragment_size;
+
+ assert(new_size <= 2048);
+
+ memcpy(data, mtod(m, void *), fragment_size);
+ data += fragment_size;
+ size = new_size;
+
+ m = m_free(m);
+
+ /* Last fragment of frame ? */
+ if (m == NULL) {
+ packet->size = size;
+ qoriq_intercom_send_packet(destination_core, packet);
+ ++self->transmitted_frames;
+ packet = allocate_packet();
+ data = packet->data;
+ size = 0;
+ }
+ }
+
+ packet->size = size;
+ self->packet = packet;
+ ifp->if_flags &= ~IFF_OACTIVE;
+}
+
+static void if_intercom_init(void *arg)
+{
+ if_intercom_control *self = arg;
+ uint32_t self_core = ppc_processor_id();
+
+ self->destination_core = self_core == 0 ? 1 : 0;
+ self->packet = allocate_packet();
+
+ qoriq_intercom_service_install(
+ INTERCOM_TYPE_NETWORK,
+ if_intercom_service,
+ self
+ );
+}
+
+static void show_stats(if_intercom_control *self)
+{
+ printf("transmitted frames: %u\n", self->transmitted_frames);
+ printf("received frames: %u\n", self->received_frames);
+}
+
+static int if_intercom_ioctl(
+ struct ifnet *ifp,
+ ioctl_command_t command,
+ caddr_t data
+)
+{
+ if_intercom_control *self = ifp->if_softc;
+ int rv = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_RUNNING) {
+ /* TODO: off */
+ }
+ if (ifp->if_flags & IFF_UP) {
+ ifp->if_flags |= IFF_RUNNING;
+ /* TODO: init */
+ }
+ break;
+ case SIO_RTEMS_SHOW_STATS:
+ show_stats(self);
+ break;
+ default:
+ rv = EINVAL;
+ break;
+ }
+
+ return rv;
+}
+
+static void if_intercom_watchdog(struct ifnet *ifp)
+{
+ ifp->if_timer = 0;
+}
+
+static int if_intercom_attach(struct rtems_bsdnet_ifconfig *config)
+{
+ if_intercom_control *self = &if_intercom;
+ struct ifnet *ifp = &self->arpcom.ac_if;
+ char *unit_name = NULL;
+ int unit_index = rtems_bsdnet_parse_driver_name(config, &unit_name);
+
+ assert(unit_index == 1);
+ assert(strcmp(unit_name, "intercom") == 0);
+ assert(config->hardware_address != NULL);
+
+ memcpy(self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+
+ /* Set interface data */
+ ifp->if_softc = self;
+ ifp->if_unit = (short) unit_index;
+ ifp->if_name = unit_name;
+ ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU;
+ ifp->if_init = if_intercom_init;
+ ifp->if_ioctl = if_intercom_ioctl;
+ ifp->if_start = if_intercom_start;
+ ifp->if_output = ether_output;
+ ifp->if_watchdog = if_intercom_watchdog;
+ ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_timer = 0;
+
+ /* Attach the interface */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ return 1;
+}
+
+int qoriq_if_intercom_attach_detach(
+ struct rtems_bsdnet_ifconfig *config,
+ int attaching
+)
+{
+ if (attaching) {
+ return if_intercom_attach(config);
+ } else {
+ assert(0);
+ }
+}
diff --git a/bsps/powerpc/qoriq/net/network.c b/bsps/powerpc/qoriq/net/network.c
new file mode 100644
index 0000000000..208b1a5434
--- /dev/null
+++ b/bsps/powerpc/qoriq/net/network.c
@@ -0,0 +1,136 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQ
+ *
+ * @brief Network configuration.
+ */
+
+/*
+ * Copyright (c) 2010-2015 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@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.
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
+#define __BSD_VISIBLE 1
+
+#include <assert.h>
+#include <string.h>
+
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <bsp.h>
+#include <bsp/tsec.h>
+#include <bsp/qoriq.h>
+
+#if QORIQ_CHIP_VARIANT == QORIQ_CHIP_P1020
+
+int BSP_tsec_attach(
+ struct rtems_bsdnet_ifconfig *config,
+ int attaching
+)
+{
+ char *unit_name = NULL;
+ int unit_number = rtems_bsdnet_parse_driver_name(config, &unit_name);
+ tsec_config tsec_cfg;
+ bool has_groups = false;
+
+ memset(&tsec_cfg, 0, sizeof(tsec_cfg));
+ config->drv_ctrl = &tsec_cfg;
+
+ if (unit_number <= 0 || unit_number > TSEC_COUNT) {
+ return 0;
+ }
+
+ switch (ppc_fsl_system_version_sid(ppc_fsl_system_version())) {
+ /* P1010 and P1020 */
+ case 0x0ec:
+ case 0x0e4:
+ case 0x0ed:
+ case 0x0e5:
+ has_groups = true;
+ break;
+ }
+
+ if (config->hardware_address == NULL) {
+ #ifdef HAS_UBOOT
+ switch (unit_number) {
+ case 1:
+ config->hardware_address = bsp_uboot_board_info.bi_enetaddr;
+ break;
+ case 2:
+ config->hardware_address = bsp_uboot_board_info.bi_enet1addr;
+ break;
+ case 3:
+ config->hardware_address = bsp_uboot_board_info.bi_enet2addr;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ #else
+ assert(0);
+ #endif
+ }
+
+ switch (unit_number) {
+ case 1:
+ if (has_groups) {
+ tsec_cfg.reg_ptr = &qoriq.tsec_1_group_0;
+ } else {
+ tsec_cfg.reg_ptr = &qoriq.tsec_1;
+ }
+ tsec_cfg.mdio_ptr = &qoriq.tsec_1;
+ tsec_cfg.irq_num_tx = QORIQ_IRQ_ETSEC_TX_1;
+ tsec_cfg.irq_num_rx = QORIQ_IRQ_ETSEC_RX_1;
+ tsec_cfg.irq_num_err = QORIQ_IRQ_ETSEC_ER_1;
+ tsec_cfg.phy_default = QORIQ_ETSEC_1_PHY_ADDR;
+ break;
+ case 2:
+ if (has_groups) {
+ tsec_cfg.reg_ptr = &qoriq.tsec_2_group_0;
+ } else {
+ tsec_cfg.reg_ptr = &qoriq.tsec_2;
+ }
+ tsec_cfg.mdio_ptr = &qoriq.tsec_1;
+ tsec_cfg.irq_num_tx = QORIQ_IRQ_ETSEC_TX_2;
+ tsec_cfg.irq_num_rx = QORIQ_IRQ_ETSEC_RX_2;
+ tsec_cfg.irq_num_err = QORIQ_IRQ_ETSEC_ER_2;
+ tsec_cfg.phy_default = QORIQ_ETSEC_2_PHY_ADDR;
+ break;
+ case 3:
+ if (has_groups) {
+ tsec_cfg.reg_ptr = &qoriq.tsec_3_group_0;
+ } else {
+ tsec_cfg.reg_ptr = &qoriq.tsec_3;
+ }
+ tsec_cfg.mdio_ptr = &qoriq.tsec_1;
+ tsec_cfg.irq_num_tx = QORIQ_IRQ_ETSEC_TX_3;
+ tsec_cfg.irq_num_rx = QORIQ_IRQ_ETSEC_RX_3;
+ tsec_cfg.irq_num_err = QORIQ_IRQ_ETSEC_ER_3;
+ tsec_cfg.phy_default = QORIQ_ETSEC_3_PHY_ADDR;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ tsec_cfg.unit_number = unit_number;
+ tsec_cfg.unit_name = unit_name;
+
+ return tsec_driver_attach_detach(config, attaching);
+}
+
+#endif /* QORIQ_CHIP_VARIANT */