diff options
Diffstat (limited to 'bsps/powerpc/qoriq')
-rw-r--r-- | bsps/powerpc/qoriq/net/if_intercom.c | 297 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/net/network.c | 136 |
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 */ |