|
|
@@ -0,0 +1,2836 @@
|
|
|
+/*********************************************************************
|
|
|
+ * _ _ _
|
|
|
+ * _ __ | |_ _ | | __ _ | |__ ___
|
|
|
+ * | '__|| __|(_)| | / _` || '_ \ / __|
|
|
|
+ * | | | |_ _ | || (_| || |_) |\__ \
|
|
|
+ * |_| \__|(_)|_| \__,_||_.__/ |___/
|
|
|
+ *
|
|
|
+ * www.rt-labs.com
|
|
|
+ * Copyright 2021 rt-labs AB, Sweden.
|
|
|
+ *
|
|
|
+ * This software is dual-licensed under GPLv3 and a commercial
|
|
|
+ * license. See the file LICENSE.md distributed with this software for
|
|
|
+ * full license information.
|
|
|
+ ********************************************************************/
|
|
|
+
|
|
|
+#include "microchip/ethernet/rte/api.h"
|
|
|
+
|
|
|
+#include "pf_includes.h"
|
|
|
+#include "pnet_driver_options.h"
|
|
|
+#include "pnet_lan9662_api.h"
|
|
|
+#include "pf_lan9662_mera.h"
|
|
|
+#include "pf_rte_uio.h"
|
|
|
+#include "pf_sram_uio.h"
|
|
|
+#include "pf_mera_trace.h"
|
|
|
+#include "pnal_filetools.h"
|
|
|
+
|
|
|
+#include <string.h>
|
|
|
+#include <inttypes.h>
|
|
|
+#include <stdlib.h>
|
|
|
+
|
|
|
+#define PF_MERA_GROUP_ID_NONE 0
|
|
|
+#define PF_MERA_GROUP_ID_PPM 1
|
|
|
+#define PF_MERA_GROUP_ID_CPM 2
|
|
|
+
|
|
|
+#define PF_MERA_INVALID_ID 0xFFFF
|
|
|
+#define PF_MERA_DATA_STATUS_MASK 0x35
|
|
|
+#define PF_MERA_SCRIPT_ARG_LEN 24
|
|
|
+#define PF_MERA_RTE_INFO_PERIOD_IN_US 30000000
|
|
|
+#define PF_MERA_POLL_INTERVAL_IN_US 1000000
|
|
|
+#define PF_MERA_PPM_IODATA_OFFSET 6 /* frame ID + vlan ID */
|
|
|
+#define PF_MERA_CPM_IODATA_OFFSET 2 /* frame ID + vlan ID */
|
|
|
+#define PF_MERA_RAL_TIME_OFFSET 100 /* Time in ns */
|
|
|
+#define PF_MERA_OB_RTP_TIME_OFFSET 300 /* Time in ns */
|
|
|
+
|
|
|
+/* Default behaviour is that pf_mera assigns SRAM address for iodata/subslot
|
|
|
+ * Enabling this define allows the application to set the SRAM address using
|
|
|
+ * rte configuration functions in P-Net API.
|
|
|
+ */
|
|
|
+#define PF_MERA_ALLOW_APPLICATION_SRAM 0
|
|
|
+
|
|
|
+/* Log enable / disable of features shared between PPM and CPM side */
|
|
|
+#define PF_MERA_LOG (PF_PPM_LOG | PF_CPM_LOG)
|
|
|
+
|
|
|
+typedef struct pf_mera_rte_cfg
|
|
|
+{
|
|
|
+ bool valid;
|
|
|
+ pnet_mera_rte_data_cfg_t cfg;
|
|
|
+} pf_mera_rte_cfg_t;
|
|
|
+
|
|
|
+/**
|
|
|
+ * RTE mapping of an iodata object.
|
|
|
+ * Same type is used for both inbound and outbound
|
|
|
+ * data.
|
|
|
+ */
|
|
|
+typedef struct pf_rte_object
|
|
|
+{
|
|
|
+ bool in_use;
|
|
|
+ pf_iodata_object_t * iodata;
|
|
|
+ mera_io_intf_t io_interface_type;
|
|
|
+ uint16_t sram_address;
|
|
|
+ uint16_t qspi_address;
|
|
|
+ const uint8_t * default_data;
|
|
|
+ mera_ob_dg_id_t ob_dg_id;
|
|
|
+ mera_ib_ra_id_t ib_ra_id;
|
|
|
+ mera_ib_ral_id_t ib_ral_id;
|
|
|
+ mera_buf_t ib_ral_buf;
|
|
|
+} pf_rte_object_t;
|
|
|
+
|
|
|
+/**
|
|
|
+ * RTE configuration for a complete frame.
|
|
|
+ * The frame can be either a PPM or a CPM frame.
|
|
|
+ * Includes information of the RTE configuration as
|
|
|
+ * well as an array with the configuration of each
|
|
|
+ * iodata object / subslot and their RTE configurations.
|
|
|
+ */
|
|
|
+typedef struct pf_mera_frame
|
|
|
+{
|
|
|
+ pf_drv_frame_t drv_frame;
|
|
|
+ bool used; /* true when allocated */
|
|
|
+ bool active; /* true when RTE is started */
|
|
|
+ bool is_ppm; /* true if ppm / inbound RTE frame */
|
|
|
+ bool is_cpm; /* true if cpm / outbound RTE frame */
|
|
|
+
|
|
|
+ /* Configuration passed on allocation */
|
|
|
+ pf_mera_frame_cfg_t config;
|
|
|
+
|
|
|
+ /* General RTE configuration */
|
|
|
+ uint16_t port;
|
|
|
+ uint32_t interval; /* Frame read/write interval [ns] */
|
|
|
+ uint16_t vcam_id;
|
|
|
+ uint16_t vlan_idx;
|
|
|
+ mera_rtp_id_t rtp_id;
|
|
|
+
|
|
|
+ uint16_t sram_frame_address; /* Start address of SRAM frame */
|
|
|
+ uint16_t rte_data_offset; /* RTE io-data offset. Different for inbound and
|
|
|
+ outbound configurations */
|
|
|
+
|
|
|
+ /* RTE configuration for individual iodata objects */
|
|
|
+ pf_rte_object_t rte_object[PNET_MAX_SLOTS][PNET_MAX_SUBSLOTS];
|
|
|
+
|
|
|
+ /* Inbound configuration */
|
|
|
+ uint16_t ib_ral_id_count;
|
|
|
+ uint16_t ib_ra_id_count;
|
|
|
+ /* Internal transfer QSPI -> SRAM */
|
|
|
+ mera_ob_wal_id_t internal_wal_id;
|
|
|
+
|
|
|
+ /* Outbound configuration */
|
|
|
+ mera_ob_wal_id_t ob_wal_id;
|
|
|
+ uint16_t ob_wa_count;
|
|
|
+ uint16_t ob_dg_count;
|
|
|
+
|
|
|
+ uint64_t rx_count;
|
|
|
+
|
|
|
+ /* A ref to the mera lib should not be part
|
|
|
+ * of the frame. But it is added to avoid updating
|
|
|
+ * a call chain including the block writer.
|
|
|
+ * Todo: Fix by adding net ref in CPM interface function
|
|
|
+ * get_data_status()
|
|
|
+ */
|
|
|
+ struct mera_inst * mera_lib;
|
|
|
+
|
|
|
+} pf_mera_frame_t;
|
|
|
+
|
|
|
+typedef struct pf_mera
|
|
|
+{
|
|
|
+ pf_drv_t hwo_drv;
|
|
|
+
|
|
|
+ struct mera_inst * mera_lib; /* MERA library ref */
|
|
|
+ pf_mera_frame_t frame[PNET_LAN9662_MAX_FRAMES];
|
|
|
+ pf_scheduler_handle_t sched_handle; /* Debug info timeout handle */
|
|
|
+ pf_scheduler_handle_t poll_handle; /* Mera lib poll timeout handle */
|
|
|
+
|
|
|
+ /* Submodule RTE configuration set by calls to
|
|
|
+ * pnet_mera_input_set_rte_config and pnet_mera_out_set_rte_config.
|
|
|
+ * Should be part of frame, but application has to set configuration
|
|
|
+ * before cpm frame is created and config is stored until ppm/cpm
|
|
|
+ * are activated.
|
|
|
+ */
|
|
|
+ pf_mera_rte_cfg_t rte_data_cfg[PNET_MAX_SLOTS][PNET_MAX_SUBSLOTS];
|
|
|
+
|
|
|
+ /* RTE resource management */
|
|
|
+ struct
|
|
|
+ {
|
|
|
+ uint16_t base_id;
|
|
|
+ bool used[PNET_LAN9662_MAX_IDS];
|
|
|
+ } vcam_id;
|
|
|
+
|
|
|
+ struct
|
|
|
+ {
|
|
|
+ uint16_t base_id;
|
|
|
+ bool used[PNET_LAN9662_MAX_IDS];
|
|
|
+ } vlan_index;
|
|
|
+
|
|
|
+ struct
|
|
|
+ {
|
|
|
+ uint16_t base_id;
|
|
|
+ bool used[PNET_LAN9662_MAX_IDS];
|
|
|
+ } rtp;
|
|
|
+
|
|
|
+ struct
|
|
|
+ {
|
|
|
+ uint16_t base_id;
|
|
|
+ bool used[PNET_LAN9662_MAX_IDS];
|
|
|
+ } ral;
|
|
|
+
|
|
|
+ struct
|
|
|
+ {
|
|
|
+ uint16_t base_id;
|
|
|
+ bool used[PNET_LAN9662_MAX_IDS];
|
|
|
+ } wal;
|
|
|
+
|
|
|
+} pf_mera_t;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get string representation of RTE interface type
|
|
|
+ * @param t In: RTE interface type
|
|
|
+ * @return String representation
|
|
|
+ */
|
|
|
+static const char * pf_mera_rte_data_type_to_str (pnet_mera_rte_data_type_t t)
|
|
|
+{
|
|
|
+ switch (t)
|
|
|
+ {
|
|
|
+ case PNET_MERA_DATA_TYPE_SRAM:
|
|
|
+ return "SRAM";
|
|
|
+ case PNET_MERA_DATA_TYPE_QSPI:
|
|
|
+ return "QSPI";
|
|
|
+ default:
|
|
|
+ return "UNSUPPORTED";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static const char * pf_mera_interface_type_to_str (mera_io_intf_t if_type)
|
|
|
+{
|
|
|
+ switch (if_type)
|
|
|
+ {
|
|
|
+ case MERA_IO_INTF_QSPI:
|
|
|
+ return "QSPI";
|
|
|
+ case MERA_IO_INTF_PI:
|
|
|
+ return "PI";
|
|
|
+ case MERA_IO_INTF_SRAM:
|
|
|
+ return "SRAM";
|
|
|
+ case MERA_IO_INTF_PCIE:
|
|
|
+ return "PCIE";
|
|
|
+ default:
|
|
|
+ return "UNKNOWN";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get the subslot index
|
|
|
+ * The subslots numbers starts at 1 and DAP subslots for
|
|
|
+ * identity and port information at 0x8000. This
|
|
|
+ * function converts the subslot number to corresponding
|
|
|
+ * index in the management data structures.
|
|
|
+ *
|
|
|
+ * subslot number id
|
|
|
+ * slot 0
|
|
|
+ * subslot 1 0
|
|
|
+ * subslot 0x8000 1
|
|
|
+ * subslot 0x8001 2
|
|
|
+ * subslot 0x8002 3
|
|
|
+ * slot 1
|
|
|
+ * subslot 1 0
|
|
|
+ * subslot 2 1
|
|
|
+ * @param subslot In: (Real) Subslot number
|
|
|
+ * @return Subslot index
|
|
|
+ */
|
|
|
+static uint16_t get_subslot_index (uint16_t subslot)
|
|
|
+{
|
|
|
+ uint16_t subslot_index;
|
|
|
+ if (subslot < PNET_SUBSLOT_DAP_INTERFACE_1_IDENT)
|
|
|
+ {
|
|
|
+ subslot_index = subslot - 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ subslot_index = subslot - PNET_SUBSLOT_DAP_INTERFACE_1_IDENT + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CC_ASSERT (subslot_index < PNET_MAX_SUBSLOTS);
|
|
|
+
|
|
|
+ return subslot_index;
|
|
|
+}
|
|
|
+
|
|
|
+pf_rte_object_t * get_rte_object (
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ uint16_t slot,
|
|
|
+ uint16_t subslot)
|
|
|
+{
|
|
|
+ uint16_t subslot_index = get_subslot_index (subslot);
|
|
|
+
|
|
|
+ CC_ASSERT (frame != NULL);
|
|
|
+ CC_ASSERT (subslot < PNET_MAX_SLOTS);
|
|
|
+
|
|
|
+ return &frame->rte_object[slot][subslot_index];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Callback for mera library debug info
|
|
|
+ * Prints debug information using vprintf()
|
|
|
+ * @param fmt In: Format string
|
|
|
+ * @param ... In: argumet list
|
|
|
+ * @return Always returns 0
|
|
|
+ */
|
|
|
+static int pf_mera_printf_cb (const char * fmt, ...)
|
|
|
+{
|
|
|
+ va_list args;
|
|
|
+ va_start (args, fmt);
|
|
|
+ vprintf (fmt, args);
|
|
|
+ va_end (args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#if PNET_OPTION_LAN9662_SHOW_RTE_INFO
|
|
|
+/**
|
|
|
+ * Display RTE status using printf
|
|
|
+ * @param mera In: mera lib reference
|
|
|
+ */
|
|
|
+static void pf_mera_rte_show (struct mera_inst * mera)
|
|
|
+{
|
|
|
+ mera_debug_info_t info;
|
|
|
+
|
|
|
+ info.group = MERA_DEBUG_GROUP_ALL;
|
|
|
+ info.rtp_id = 0; /* All RTP IDs */
|
|
|
+ info.full = false; /* Only active IDs */
|
|
|
+ info.clear = true;
|
|
|
+
|
|
|
+ printf ("RTE Status:\n");
|
|
|
+ mera_debug_info_print (mera, pf_mera_printf_cb, &info);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/**
|
|
|
+ * @internal
|
|
|
+ * Show current RTE configuration
|
|
|
+ * This is a callback for the scheduler.
|
|
|
+ * @param net InOut: The p-net stack instance
|
|
|
+ * @param arg In: Handle to the LAN9662 driver.
|
|
|
+ * @param current_time In: The current system time, in microseconds,
|
|
|
+ * when the scheduler is started to execute
|
|
|
+ * stored tasks.
|
|
|
+ */
|
|
|
+#if PNET_OPTION_LAN9662_SHOW_RTE_INFO
|
|
|
+static void pf_mera_rte_show_periodic (
|
|
|
+ pnet_t * net,
|
|
|
+ void * arg,
|
|
|
+ uint32_t current_time)
|
|
|
+{
|
|
|
+
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)arg;
|
|
|
+ pf_mera_rte_show (handle->mera_lib);
|
|
|
+
|
|
|
+ pf_scheduler_add (
|
|
|
+ net,
|
|
|
+ PF_MERA_RTE_INFO_PERIOD_IN_US,
|
|
|
+ pf_mera_rte_show_periodic,
|
|
|
+ handle,
|
|
|
+ &handle->sched_handle);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/**
|
|
|
+ * @internal
|
|
|
+ * Poll mera lib / RTE
|
|
|
+ * This is a callback for the scheduler.
|
|
|
+ * @param net InOut: The p-net stack instance
|
|
|
+ * @param arg In: Handle to the LAN9662 driver.
|
|
|
+ * @param current_time In: The current system time, in microseconds,
|
|
|
+ * when the scheduler is started to execute
|
|
|
+ * stored tasks.
|
|
|
+ */
|
|
|
+static void pf_mera_poll (pnet_t * net, void * arg, uint32_t current_time)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)arg;
|
|
|
+
|
|
|
+ mera_poll (handle->mera_lib);
|
|
|
+
|
|
|
+ pf_scheduler_add (
|
|
|
+ net,
|
|
|
+ PF_MERA_POLL_INTERVAL_IN_US,
|
|
|
+ pf_mera_poll,
|
|
|
+ handle,
|
|
|
+ &handle->poll_handle);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add vcam rule for an inbound RTE connection
|
|
|
+ * Calls the add_inbound_vcap_rule.sh script
|
|
|
+ *
|
|
|
+ * @param vcam_handle In: VCAM handle
|
|
|
+ * @param vlan_id In: VLAN ID
|
|
|
+ * @param mac_addr In: MAC of management port
|
|
|
+ * @param rt_vlan_idx In: RTE VLAN index
|
|
|
+ * @param frame_id In: Profinet frame ID
|
|
|
+ * @param rtp_id In: RTP ID
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ib_add_vcam_rule (
|
|
|
+ int vcam_handle,
|
|
|
+ uint16_t vlan_id,
|
|
|
+ pnet_ethaddr_t * mac_addr,
|
|
|
+ int rt_vlan_idx,
|
|
|
+ int frame_id,
|
|
|
+ int rtp_id)
|
|
|
+{
|
|
|
+ const char * argv[8];
|
|
|
+ char vlan_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char mac_addr_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char rt_vlan_idx_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char vcam_handle_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char frame_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char rtp_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+
|
|
|
+ snprintf (vlan_id_str, sizeof (vlan_id_str), "0x%x", vlan_id);
|
|
|
+ snprintf (
|
|
|
+ mac_addr_str,
|
|
|
+ sizeof (mac_addr_str),
|
|
|
+ "%02X:%02X:%02X:%02X:%02X:%02X",
|
|
|
+ mac_addr->addr[0],
|
|
|
+ mac_addr->addr[1],
|
|
|
+ mac_addr->addr[2],
|
|
|
+ mac_addr->addr[3],
|
|
|
+ mac_addr->addr[4],
|
|
|
+ mac_addr->addr[5]);
|
|
|
+
|
|
|
+ snprintf (rt_vlan_idx_str, sizeof (rt_vlan_idx_str), "%d", rt_vlan_idx);
|
|
|
+ snprintf (vcam_handle_str, sizeof (vcam_handle_str), "%d", vcam_handle);
|
|
|
+ snprintf (frame_id_str, sizeof (frame_id_str), "%d", frame_id);
|
|
|
+ snprintf (rtp_id_str, sizeof (rtp_id_str), "%d", rtp_id);
|
|
|
+
|
|
|
+ argv[0] = "add_inbound_vcap_rule.sh";
|
|
|
+ argv[1] = vcam_handle_str;
|
|
|
+ argv[2] = vlan_id_str;
|
|
|
+ argv[3] = mac_addr_str;
|
|
|
+ argv[4] = rt_vlan_idx_str;
|
|
|
+ argv[5] = frame_id_str;
|
|
|
+ argv[6] = rtp_id_str;
|
|
|
+ argv[7] = NULL;
|
|
|
+
|
|
|
+ return pnal_execute_script (argv);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add vcam rule for an outbound RTE connection
|
|
|
+ * Calls the add_outbound_vcap_rule.sh script
|
|
|
+ *
|
|
|
+ * @param vcam_handle In: VCAM handle
|
|
|
+ * @param vlan_id In: VLAN ID
|
|
|
+ * @param mac_addr In: MAC of management port
|
|
|
+ * @param rt_vlan_idx In: RTE VLAN index
|
|
|
+ * @param frame_id In: Profinet frame ID
|
|
|
+ * @param rtp_id In: RTP ID
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+int ob_add_vcam_rule (
|
|
|
+ int vcam_handle,
|
|
|
+ uint16_t vlan_id,
|
|
|
+ pnet_ethaddr_t * mac_addr,
|
|
|
+ int rt_vlan_idx,
|
|
|
+ int frame_id,
|
|
|
+ int rtp_id)
|
|
|
+{
|
|
|
+ const char * argv[7];
|
|
|
+ char vlan_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char mac_addr_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char rt_vlan_idx_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char vcam_handle_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char frame_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+ char rtp_id_str[PF_MERA_SCRIPT_ARG_LEN];
|
|
|
+
|
|
|
+ snprintf (vlan_id_str, sizeof (vlan_id_str), "0x%x", vlan_id);
|
|
|
+ snprintf (
|
|
|
+ mac_addr_str,
|
|
|
+ sizeof (mac_addr_str),
|
|
|
+ "%02X:%02X:%02X:%02X:%02X:%02X",
|
|
|
+ mac_addr->addr[0],
|
|
|
+ mac_addr->addr[1],
|
|
|
+ mac_addr->addr[2],
|
|
|
+ mac_addr->addr[3],
|
|
|
+ mac_addr->addr[4],
|
|
|
+ mac_addr->addr[5]);
|
|
|
+ snprintf (rt_vlan_idx_str, sizeof (rt_vlan_idx_str), "%d", rt_vlan_idx);
|
|
|
+ snprintf (vcam_handle_str, sizeof (vcam_handle_str), "%d", vcam_handle);
|
|
|
+ snprintf (frame_id_str, sizeof (frame_id_str), "%d", frame_id);
|
|
|
+ snprintf (rtp_id_str, sizeof (rtp_id_str), "%d", rtp_id);
|
|
|
+
|
|
|
+ argv[0] = "add_outbound_vcap_rule.sh";
|
|
|
+ argv[1] = vcam_handle_str;
|
|
|
+ argv[2] = vlan_id_str;
|
|
|
+ argv[3] = rt_vlan_idx_str;
|
|
|
+ argv[4] = frame_id_str;
|
|
|
+ argv[5] = rtp_id_str;
|
|
|
+ argv[6] = mac_addr_str;
|
|
|
+ argv[7] = NULL;
|
|
|
+
|
|
|
+ return pnal_execute_script (argv);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Delete vcam rule
|
|
|
+ * Calls the delete_vcap_rule.sh script
|
|
|
+ * @param vcam_handle In: VCAM handle
|
|
|
+ * @param vlan_id In: VLAN ID
|
|
|
+ * @param rt_vlan_idx In: RTE VLAN index
|
|
|
+ * @param frame_id In: Profinet frame ID
|
|
|
+ * @param rtp_id In: RTP ID
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_delete_vcam_rule (int vcam_handle)
|
|
|
+{
|
|
|
+ const char * argv[3];
|
|
|
+ char vcam_handle_str[16];
|
|
|
+
|
|
|
+ snprintf (vcam_handle_str, sizeof (vcam_handle_str), "%d", vcam_handle);
|
|
|
+
|
|
|
+ argv[0] = "del_vcap_rule.sh";
|
|
|
+ argv[1] = vcam_handle_str;
|
|
|
+ argv[2] = NULL;
|
|
|
+
|
|
|
+ return pnal_execute_script (argv);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a vcam ID for a RTE configuration
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @return vcam ID, PF_MERA_INVALID_ID on error
|
|
|
+ */
|
|
|
+static uint16_t pf_mera_vcam_id_alloc (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ for (i = 0; i < NELEMENTS (handle->vcam_id.used); i++)
|
|
|
+ {
|
|
|
+ if (handle->vcam_id.used[i] == false)
|
|
|
+ {
|
|
|
+ handle->vcam_id.used[i] = true;
|
|
|
+ return handle->vcam_id.base_id + i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to alloc VCAM ID \n", __LINE__);
|
|
|
+ return PF_MERA_INVALID_ID;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a vcam ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param id In: vcam ID
|
|
|
+ */
|
|
|
+static void pf_mera_vcam_id_free (pf_mera_t * handle, uint16_t id)
|
|
|
+{
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ if (id != PF_MERA_INVALID_ID)
|
|
|
+ {
|
|
|
+ handle->vcam_id.used[id - handle->vcam_id.base_id] = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a vlan index for a RTE configuration
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @return vlan index, PF_MERA_INVALID_ID on error
|
|
|
+ */
|
|
|
+static uint16_t pf_mera_vlan_index_alloc (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ for (i = 0; i < NELEMENTS (handle->vlan_index.used); i++)
|
|
|
+ {
|
|
|
+ if (handle->vlan_index.used[i] == false)
|
|
|
+ {
|
|
|
+ handle->vlan_index.used[i] = true;
|
|
|
+ return handle->vlan_index.base_id + i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to alloc vlan index\n", __LINE__);
|
|
|
+ return PF_MERA_INVALID_ID;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a vlan index
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param id In: vlan index
|
|
|
+ */
|
|
|
+static void pf_mera_vlan_index_free (pf_mera_t * handle, uint16_t id)
|
|
|
+{
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ if (id != PF_MERA_INVALID_ID)
|
|
|
+ {
|
|
|
+ handle->vlan_index.used[id - handle->vlan_index.base_id] = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a RTE ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @return RTP ID, PF_MERA_INVALID_ID on error
|
|
|
+ */
|
|
|
+static uint16_t pf_mera_rtp_id_alloc (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+
|
|
|
+ for (i = 0; i < NELEMENTS (handle->rtp.used); i++)
|
|
|
+ {
|
|
|
+ if (handle->rtp.used[i] == false)
|
|
|
+ {
|
|
|
+ handle->rtp.used[i] = true;
|
|
|
+ return handle->rtp.base_id + i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to allocate RTP ID\n", __LINE__);
|
|
|
+ return PF_MERA_INVALID_ID;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a RTP ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param id In: RTP ID
|
|
|
+ */
|
|
|
+static void pf_mera_rtp_id_free (pf_mera_t * handle, uint16_t id)
|
|
|
+{
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ if (id != PF_MERA_INVALID_ID)
|
|
|
+ {
|
|
|
+ handle->rtp.used[id - handle->rtp.base_id] = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a Read Action List (RAL) ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @return ral ID, PF_MERA_INVALID_ID on error
|
|
|
+ */
|
|
|
+static uint16_t pf_mera_ral_id_alloc (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+
|
|
|
+ for (i = 0; i < NELEMENTS (handle->ral.used); i++)
|
|
|
+ {
|
|
|
+ if (handle->ral.used[i] == false)
|
|
|
+ {
|
|
|
+ handle->ral.used[i] = true;
|
|
|
+ return handle->ral.base_id + i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_PPM_LOG, "MERA(%d): Failed to alloc RAL ID \n", __LINE__);
|
|
|
+ return PF_MERA_INVALID_ID;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a Read Action List (RAL) ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param id In: ral ID
|
|
|
+ */
|
|
|
+static void pf_mera_ral_id_free (pf_mera_t * handle, uint16_t id)
|
|
|
+{
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ if (id != PF_MERA_INVALID_ID)
|
|
|
+ {
|
|
|
+ handle->ral.used[id - handle->ral.base_id] = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a Write Action List (WAL) ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @return wal ID, PF_MERA_INVALID_ID on error
|
|
|
+ */
|
|
|
+static uint16_t pf_mera_wal_id_alloc (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+
|
|
|
+ for (i = 0; i < NELEMENTS (handle->wal.used); i++)
|
|
|
+ {
|
|
|
+ if (handle->wal.used[i] == false)
|
|
|
+ {
|
|
|
+ handle->wal.used[i] = true;
|
|
|
+ return handle->wal.base_id + i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_PPM_LOG, "MERA(%d): Failed to alloc WAL ID \n", __LINE__);
|
|
|
+ return PF_MERA_INVALID_ID;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a Write Action List (WAL) ID
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param id In: wal ID
|
|
|
+ */
|
|
|
+static void pf_mera_wal_id_free (pf_mera_t * handle, uint16_t id)
|
|
|
+{
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ if (id != PF_MERA_INVALID_ID)
|
|
|
+ {
|
|
|
+ handle->wal.used[id - handle->wal.base_id] = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get the wal id from a CPM frame using the iocr ref.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @param iocr In: IOCR reference
|
|
|
+ * @param wal_id Out: Write Action List Id
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_get_cpm_wal_id (
|
|
|
+ pf_mera_t * handle,
|
|
|
+ pf_iocr_t * iocr,
|
|
|
+ mera_ob_wal_id_t * wal_id)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ for (i = 0; i < PNET_LAN9662_MAX_FRAMES; i++)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ handle->frame[i].used == true &&
|
|
|
+ handle->frame[i].config.p_iocr->p_ar == iocr->p_ar &&
|
|
|
+ handle->frame[i].is_cpm)
|
|
|
+ {
|
|
|
+ *wal_id = handle->frame[i].ob_wal_id;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Add RTE data group for an iodata object.
|
|
|
+ * Maps the data source to frame/pdu offset.
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ib_add_dg (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ mera_ib_dg_conf_t ib_dg_cfg;
|
|
|
+
|
|
|
+ err = mera_ib_dg_init (&ib_dg_cfg);
|
|
|
+ if (err)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to init data group (dg)\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ib_dg_cfg.rtp_id = frame->rtp_id;
|
|
|
+ ib_dg_cfg.pdu_offset = entry->iodata->data_offset + frame->rte_data_offset;
|
|
|
+ ib_dg_cfg.valid_offset = entry->iodata->iops_offset + frame->rte_data_offset;
|
|
|
+ if (entry->io_interface_type == MERA_IO_INTF_SRAM)
|
|
|
+ {
|
|
|
+ /* In SRAM mode the IOPS is handled by SW */
|
|
|
+ ib_dg_cfg.valid_update = false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ib_dg_cfg.valid_update = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ib_dg_cfg.opc_seq_update = false;
|
|
|
+ ib_dg_cfg.opc_code_update = false;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): mera_ib_dg_add "
|
|
|
+ "ral_id:%d "
|
|
|
+ "ra_id:%d "
|
|
|
+ "cfg.rtp_id:%d "
|
|
|
+ "cfg.pdu_offset:%d "
|
|
|
+ "cfg.valid_offset:%d\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->ib_ral_id,
|
|
|
+ entry->ib_ra_id,
|
|
|
+ ib_dg_cfg.rtp_id,
|
|
|
+ ib_dg_cfg.pdu_offset,
|
|
|
+ ib_dg_cfg.valid_offset);
|
|
|
+
|
|
|
+ err =
|
|
|
+ mera_ib_dg_add (mera_lib, entry->ib_ral_id, entry->ib_ra_id, &ib_dg_cfg);
|
|
|
+ if (err)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): Failed to add inbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Convert P-Net interface data type to mera lib type.
|
|
|
+ * @param pnet_if_type In: P-Net interface type
|
|
|
+ * @return mera lib interface type
|
|
|
+ */
|
|
|
+static mera_io_intf_t pf_mera_interface_type (
|
|
|
+ pnet_mera_rte_data_type_t pnet_if_type)
|
|
|
+{
|
|
|
+ switch (pnet_if_type)
|
|
|
+ {
|
|
|
+ case PNET_MERA_DATA_TYPE_SRAM:
|
|
|
+ return MERA_IO_INTF_SRAM;
|
|
|
+ case PNET_MERA_DATA_TYPE_QSPI:
|
|
|
+ return MERA_IO_INTF_QSPI;
|
|
|
+ default:
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Unsupported interface type\n",
|
|
|
+ __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add RTE read action for an iodata object.
|
|
|
+ * Configures the data source
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ib_add_ra (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ib_ra_conf_t ib_ra_cfg;
|
|
|
+ mera_ib_ra_ctrl_t ctrl;
|
|
|
+
|
|
|
+ if (mera_ib_ra_init (&ib_ra_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_PPM_LOG, "MERA(%d): Failed to init read action\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ib_ra_cfg.ra_id = entry->ib_ra_id;
|
|
|
+ ib_ra_cfg.rd_addr.intf = entry->io_interface_type;
|
|
|
+ ib_ra_cfg.rd_addr.addr = entry->sram_address;
|
|
|
+ if (entry->io_interface_type == MERA_IO_INTF_QSPI)
|
|
|
+ {
|
|
|
+ ib_ra_cfg.rd_addr.addr = entry->qspi_address;
|
|
|
+ }
|
|
|
+ ib_ra_cfg.length = entry->iodata->data_length;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): mera_ib_ra_add "
|
|
|
+ "ral_id:%d "
|
|
|
+ "cfg.ra_id:%d "
|
|
|
+ "cfg.rd_addr.intf:%d-%s "
|
|
|
+ "cfg.rd_addr.addr: 0x%x "
|
|
|
+ "cfg.length:%d\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->ib_ral_id,
|
|
|
+ entry->ib_ra_id,
|
|
|
+ ib_ra_cfg.rd_addr.intf,
|
|
|
+ pf_mera_interface_type_to_str (ib_ra_cfg.rd_addr.intf),
|
|
|
+ ib_ra_cfg.rd_addr.addr,
|
|
|
+ ib_ra_cfg.length);
|
|
|
+
|
|
|
+ if (mera_ib_ra_add (mera_lib, entry->ib_ral_id, &ib_ra_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to add read action\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ib_ra_cfg.rd_addr.intf == MERA_IO_INTF_QSPI)
|
|
|
+ {
|
|
|
+ ctrl.enable = true;
|
|
|
+ if (
|
|
|
+ mera_ib_ra_ctrl_set (
|
|
|
+ mera_lib,
|
|
|
+ entry->ib_ral_id,
|
|
|
+ entry->ib_ra_id,
|
|
|
+ &ctrl) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): mera_ib_ra_ctrl_set() error\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add RTE read action list for an iodata object.
|
|
|
+ * Configures when data source shall be read.
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @param interval_in_ns In: Read interval in nanoseconds
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ib_add_ral (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_rte_object_t * entry,
|
|
|
+ uint32_t interval_in_ns)
|
|
|
+{
|
|
|
+ mera_ib_ral_conf_t ral_cfg;
|
|
|
+
|
|
|
+ ral_cfg.time.offset = PF_MERA_RAL_TIME_OFFSET * entry->ib_ral_id;
|
|
|
+ ral_cfg.time.interval = interval_in_ns;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): mera_ib_ral_conf_set "
|
|
|
+ "ral_id:%d "
|
|
|
+ "cfg.time.offset:%d(ns) "
|
|
|
+ "cfg.time.interval:%d(ns)\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->ib_ral_id,
|
|
|
+ ral_cfg.time.offset,
|
|
|
+ ral_cfg.time.interval);
|
|
|
+
|
|
|
+ if (mera_ib_ral_conf_set (mera_lib, entry->ib_ral_id, &ral_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set read action configuration\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Add RTE configuration for an inbound iodata object.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_add_ib_entry (
|
|
|
+ pf_mera_t * handle,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ob_wa_conf_t wa_cfg;
|
|
|
+ entry->in_use = true;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Configure inbound data entry\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->iodata->slot_nbr,
|
|
|
+ entry->iodata->subslot_nbr);
|
|
|
+
|
|
|
+ entry->ib_ral_id = pf_mera_ral_id_alloc (handle);
|
|
|
+
|
|
|
+ if (pf_mera_ib_add_ra (handle->mera_lib, entry) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed ta add read action\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_ib_add_dg (handle->mera_lib, frame, entry) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed ta add data group\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_ib_add_ral (handle->mera_lib, entry, frame->interval) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed ta add read action list\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry->io_interface_type == MERA_IO_INTF_QSPI)
|
|
|
+ {
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Add internal transfer QSPI 0x%x -> SRAM 0x%x\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->iodata->slot_nbr,
|
|
|
+ entry->iodata->subslot_nbr,
|
|
|
+ entry->qspi_address,
|
|
|
+ entry->sram_address);
|
|
|
+
|
|
|
+ if (mera_ob_wa_init (&wa_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed init internal write action\n",
|
|
|
+ __LINE__);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ wa_cfg.internal = true;
|
|
|
+ /* wa_cfg.rtp_id not used for internal transfers */
|
|
|
+ /* wa_cfg.grp_id not used for internal transfers */
|
|
|
+ /* wa_cfg.dg_id not used for internal transfers */
|
|
|
+
|
|
|
+ /* Read address */
|
|
|
+ wa_cfg.rd_addr.intf = MERA_IO_INTF_QSPI;
|
|
|
+ wa_cfg.rd_addr.addr = entry->qspi_address;
|
|
|
+
|
|
|
+ /* Write address */
|
|
|
+ wa_cfg.wr_addr.intf = MERA_IO_INTF_SRAM;
|
|
|
+ wa_cfg.wr_addr.addr = entry->sram_address;
|
|
|
+
|
|
|
+ wa_cfg.length = entry->iodata->data_length;
|
|
|
+
|
|
|
+ if (mera_ob_wa_add (handle->mera_lib, frame->internal_wal_id, &wa_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add internal write action\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Set the general RTE configuration for a PPM frame.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ib_rtp_config (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ mera_ib_rtp_conf_t ib_rtp_config = {0};
|
|
|
+ pf_ppm_t * p_ppm = &frame->config.p_iocr->ppm;
|
|
|
+
|
|
|
+ ib_rtp_config.type = MERA_RTP_TYPE_PN;
|
|
|
+ ib_rtp_config.grp_id = PF_MERA_GROUP_ID_NONE;
|
|
|
+ ib_rtp_config.mode = MERA_RTP_IB_MODE_INJ;
|
|
|
+ ib_rtp_config.time.offset = MERA_TIME_OFFSET_NONE;
|
|
|
+ ib_rtp_config.time.interval = frame->interval;
|
|
|
+ ib_rtp_config.port = frame->port;
|
|
|
+ ib_rtp_config.length = ((pnal_buf_t *)p_ppm->p_send_buffer)->len;
|
|
|
+
|
|
|
+ memcpy (
|
|
|
+ ib_rtp_config.data,
|
|
|
+ ((pnal_buf_t *)p_ppm->p_send_buffer)->payload,
|
|
|
+ ((pnal_buf_t *)p_ppm->p_send_buffer)->len);
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): mera_ib_rtp_conf_set "
|
|
|
+ "rtp_id:%d "
|
|
|
+ "type: %d "
|
|
|
+ "grp_id:%d "
|
|
|
+ "mode:%d "
|
|
|
+ "time.offset:%d "
|
|
|
+ "time.interval:%d "
|
|
|
+ "port:%d "
|
|
|
+ "length:%d\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->rtp_id,
|
|
|
+ ib_rtp_config.type,
|
|
|
+ ib_rtp_config.grp_id,
|
|
|
+ ib_rtp_config.mode,
|
|
|
+ ib_rtp_config.time.offset,
|
|
|
+ ib_rtp_config.time.interval,
|
|
|
+ ib_rtp_config.port,
|
|
|
+ ib_rtp_config.length);
|
|
|
+
|
|
|
+ err = mera_ib_rtp_conf_set (handle->mera_lib, frame->rtp_id, &ib_rtp_config);
|
|
|
+ if (err)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set inbound RTP configuration\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Configure and start a RTE configuration for a PPM frame.
|
|
|
+ * Sets the general RTE configuration and the configuration
|
|
|
+ * for each iodata object in the communication relationship.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ppm_start_rte (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ pf_iocr_t * p_iocr = frame->config.p_iocr;
|
|
|
+ uint16_t slot, subslot;
|
|
|
+
|
|
|
+ err = pf_mera_ib_add_vcam_rule (
|
|
|
+ frame->vcam_id,
|
|
|
+ p_iocr->param.iocr_tag_header.vlan_id,
|
|
|
+ &frame->config.main_mac_addr, /* MAC of sending interface */
|
|
|
+ frame->vlan_idx,
|
|
|
+ p_iocr->param.frame_id,
|
|
|
+ frame->rtp_id);
|
|
|
+
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add inbound vcam rule\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = pf_mera_ib_rtp_config (handle, frame);
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set inbound RTP configuration\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = pf_mera_get_cpm_wal_id (
|
|
|
+ handle,
|
|
|
+ frame->config.p_iocr,
|
|
|
+ &frame->internal_wal_id);
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to get PPM internal WAL id from CPM\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (slot = 0; slot < PNET_MAX_SLOTS; slot++)
|
|
|
+ {
|
|
|
+ for (subslot = 0; subslot < PNET_MAX_SUBSLOTS; subslot++)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ frame->rte_object[slot][subslot].iodata != NULL &&
|
|
|
+ frame->rte_object[slot][subslot].iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ err = pf_mera_add_ib_entry (
|
|
|
+ handle,
|
|
|
+ frame,
|
|
|
+ &frame->rte_object[slot][subslot]);
|
|
|
+
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->active = true;
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_driver_init (pnet_t * net)
|
|
|
+{
|
|
|
+ pf_mera_t * handle;
|
|
|
+ mera_cb_t mera_lib_cb = {
|
|
|
+ .reg_rd = pf_rte_uio_reg_read,
|
|
|
+ .reg_wr = pf_rte_uio_reg_write,
|
|
|
+ .lock = NULL,
|
|
|
+ .unlock = NULL,
|
|
|
+ .trace_printf = pf_mera_callout_trace_printf,
|
|
|
+ .trace_hex_dump = NULL};
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_MERA_LOG, "MERA(%d): Init RTE UIO driver\n", __LINE__);
|
|
|
+
|
|
|
+ if (pf_rte_uio_init() != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): RTE UIO driver initialization error\n",
|
|
|
+ __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_MERA_LOG, "MERA(%d): Init SRAM UIO driver\n", __LINE__);
|
|
|
+ if (pf_sram_init() != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): SRAM UIO driver initialization error\n",
|
|
|
+ __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle = (pf_mera_t *)malloc (sizeof (pf_mera_t));
|
|
|
+ CC_ASSERT (handle != NULL);
|
|
|
+ memset (handle, 0, sizeof (pf_mera_t));
|
|
|
+
|
|
|
+ handle->vcam_id.base_id =
|
|
|
+ net->p_fspm_default_cfg->driver_config.mera.vcam_base_id;
|
|
|
+ handle->rtp.base_id =
|
|
|
+ net->p_fspm_default_cfg->driver_config.mera.rtp_base_id;
|
|
|
+ handle->ral.base_id =
|
|
|
+ net->p_fspm_default_cfg->driver_config.mera.ral_base_id;
|
|
|
+ handle->wal.base_id =
|
|
|
+ net->p_fspm_default_cfg->driver_config.mera.wal_base_id;
|
|
|
+
|
|
|
+ handle->mera_lib = mera_create (&mera_lib_cb);
|
|
|
+ if (handle->mera_lib == NULL)
|
|
|
+ {
|
|
|
+ LOG_FATAL (PF_MERA_LOG, "MERA(%d): Failed to init MERA lib\n", __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Start mera poll timeout */
|
|
|
+ pf_scheduler_init_handle (&handle->poll_handle, "mera_poll");
|
|
|
+ if (
|
|
|
+ pf_scheduler_add (
|
|
|
+ net,
|
|
|
+ PF_MERA_POLL_INTERVAL_IN_US,
|
|
|
+ pf_mera_poll,
|
|
|
+ handle,
|
|
|
+ &handle->poll_handle) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to start poll timer\n",
|
|
|
+ __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle->hwo_drv.initialized = true;
|
|
|
+ net->hwo_drv = (pf_drv_t *)handle;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Allocate a mera frame
|
|
|
+ * The frame contains all required RTE configurations for a PPM or CPM.
|
|
|
+ * Iodata interface type is initialized to SRAM.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @return Allocated frame, NULL on error
|
|
|
+ */
|
|
|
+static pf_mera_frame_t * pf_mera_alloc_frame (pf_mera_t * handle)
|
|
|
+{
|
|
|
+ uint16_t i, j, k;
|
|
|
+ pf_mera_frame_t * frame = NULL;
|
|
|
+
|
|
|
+ for (i = 0; i < PNET_LAN9662_MAX_FRAMES; i++)
|
|
|
+ {
|
|
|
+ if (handle->frame[i].used == false)
|
|
|
+ {
|
|
|
+ frame = &handle->frame[i];
|
|
|
+ memset (frame, 0, sizeof (*frame));
|
|
|
+ frame->drv_frame.initialized = true;
|
|
|
+ frame->used = true;
|
|
|
+ frame->active = false;
|
|
|
+ frame->ob_dg_count = 1;
|
|
|
+
|
|
|
+ for (j = 0; j < PNET_MAX_SLOTS; j++)
|
|
|
+ {
|
|
|
+ for (k = 0; k < PNET_MAX_SUBSLOTS; k++)
|
|
|
+ {
|
|
|
+ frame->rte_object[j][k].ib_ral_id = PF_MERA_INVALID_ID;
|
|
|
+ frame->rte_object[j][k].io_interface_type = MERA_IO_INTF_SRAM;
|
|
|
+ frame->rte_object[j][k].sram_address = PF_SRAM_INVALID_ADDRESS;
|
|
|
+ frame->mera_lib = handle->mera_lib;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Frame allocated (index=%d)\n",
|
|
|
+ __LINE__,
|
|
|
+ i);
|
|
|
+ return frame;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_FATAL (PF_MERA_LOG, "MERA(%d): Failed to allocate frame\n", __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+bool pf_mera_is_active_frame (pf_drv_frame_t * frame)
|
|
|
+{
|
|
|
+ return ((pf_mera_frame_t *)frame)->active;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Free a mera frame
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param frame In: The frame to free
|
|
|
+ */
|
|
|
+static void pf_mera_free_frame (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ if (frame != NULL)
|
|
|
+ {
|
|
|
+ frame->used = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to free frame\n", __LINE__);
|
|
|
+}
|
|
|
+
|
|
|
+pf_drv_frame_t * pf_mera_ppm_alloc (
|
|
|
+ pnet_t * net,
|
|
|
+ const pf_mera_frame_cfg_t * cfg)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ pf_mera_frame_t * frame = NULL;
|
|
|
+ pf_iodata_object_t * p_iodata;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+ uint16_t i;
|
|
|
+ pf_ppm_t * ppm;
|
|
|
+
|
|
|
+ if (cfg == NULL || cfg->p_iocr == NULL || handle == NULL)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ frame = pf_mera_alloc_frame (handle);
|
|
|
+ if (frame == NULL)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->is_ppm = true;
|
|
|
+
|
|
|
+ frame->sram_frame_address = pf_sram_frame_alloc();
|
|
|
+ if (frame->sram_frame_address == 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to allocate SRAM frame\n",
|
|
|
+ __LINE__);
|
|
|
+ pf_mera_free_frame (handle, frame);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Allocated PPM SRAM frame at 0x%x\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->sram_frame_address);
|
|
|
+
|
|
|
+ frame->config = *cfg;
|
|
|
+ frame->port = cfg->port;
|
|
|
+
|
|
|
+ ppm = &frame->config.p_iocr->ppm;
|
|
|
+ frame->interval =
|
|
|
+ (1000000 * ppm->send_clock_factor * ppm->reduction_ratio) / 32;
|
|
|
+
|
|
|
+ for (i = 0; i < frame->config.p_iocr->nbr_data_desc; i++)
|
|
|
+ {
|
|
|
+ p_iodata = &frame->config.p_iocr->data_desc[i];
|
|
|
+ if (p_iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ entry =
|
|
|
+ get_rte_object (frame, p_iodata->slot_nbr, p_iodata->subslot_nbr);
|
|
|
+ entry->iodata = p_iodata;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->vcam_id = pf_mera_vcam_id_alloc (handle);
|
|
|
+ frame->rtp_id = pf_mera_rtp_id_alloc (handle);
|
|
|
+ /* frame->internal_wal_id assigned later */
|
|
|
+ frame->vlan_idx = pf_mera_vlan_index_alloc (handle);
|
|
|
+ frame->rte_data_offset = PF_MERA_PPM_IODATA_OFFSET;
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_MERA_LOG, "MERA(%d): PPM frame allocated\n", __LINE__);
|
|
|
+ return (pf_drv_frame_t *)frame;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_free (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ LOG_DEBUG (PF_PPM_LOG, "MERA(%d): Free PPM frame\n", __LINE__);
|
|
|
+ if (frame != NULL)
|
|
|
+ {
|
|
|
+ pf_mera_vcam_id_free (handle, frame->vcam_id);
|
|
|
+ pf_mera_vlan_index_free (handle, frame->vlan_idx);
|
|
|
+ pf_mera_rtp_id_free (handle, frame->rtp_id);
|
|
|
+ pf_sram_frame_free (frame->sram_frame_address);
|
|
|
+ pf_mera_free_frame (handle, frame);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to free PPM frame\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Generate RTE configurations for all iodata objects in a PPM type
|
|
|
+ * of communication relation.
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param frame InOut: The PPM frame
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ppm_config (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ uint16_t slot, subslot;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+ const pf_mera_rte_cfg_t * entry_rte_data_cfg; /* qspi address */
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_PPM_LOG, "MERA(%d): Apply RTE configuration (PPM)\n", __LINE__);
|
|
|
+
|
|
|
+ for (slot = 0; slot < PNET_MAX_SLOTS; slot++)
|
|
|
+ {
|
|
|
+ for (subslot = 0; subslot < PNET_MAX_SUBSLOTS; subslot++)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ frame->rte_object[slot][subslot].iodata != NULL &&
|
|
|
+ frame->rte_object[slot][subslot].iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ entry = &frame->rte_object[slot][subslot];
|
|
|
+ entry_rte_data_cfg = &handle->rte_data_cfg[slot][subslot];
|
|
|
+
|
|
|
+ entry->ib_ra_id = frame->ib_ra_id_count++;
|
|
|
+
|
|
|
+ if (entry_rte_data_cfg->valid)
|
|
|
+ {
|
|
|
+ entry->io_interface_type =
|
|
|
+ pf_mera_interface_type (entry_rte_data_cfg->cfg.type);
|
|
|
+
|
|
|
+#if PF_MERA_ALLOW_APPLICATION_SRAM
|
|
|
+ if (entry_rte_data_cfg->cfg.type == PNET_MERA_DATA_TYPE_SRAM)
|
|
|
+ {
|
|
|
+ entry->sram_address = entry_rte_data_cfg->cfg.address;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ entry->qspi_address = entry_rte_data_cfg->cfg.address;
|
|
|
+ entry->default_data = entry_rte_data_cfg->cfg.default_data;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry->sram_address == PF_SRAM_INVALID_ADDRESS)
|
|
|
+ {
|
|
|
+ entry->sram_address = frame->sram_frame_address +
|
|
|
+ frame->rte_data_offset +
|
|
|
+ entry->iodata->data_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Interface: %s Start address: 0x%x Size: %d\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->iodata->slot_nbr,
|
|
|
+ entry->iodata->subslot_nbr,
|
|
|
+ pf_mera_interface_type_to_str (entry->io_interface_type),
|
|
|
+ entry->io_interface_type == MERA_IO_INTF_QSPI
|
|
|
+ ? entry->qspi_address
|
|
|
+ : entry->sram_address,
|
|
|
+ entry->iodata->data_length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_start (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ if (handle == NULL || frame == NULL || frame->config.p_iocr == NULL)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): Failed to start RTE - parameter error\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_ppm_config (handle, frame) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_PPM_LOG, "MERA(%d): Failed to configure RTE\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_ppm_start_rte (handle, frame) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_PPM_LOG, "MERA(%d): Failed to start RTE\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+#if PNET_OPTION_LAN9662_SHOW_RTE_INFO
|
|
|
+ pf_scheduler_init_handle (&handle->sched_handle, "mera_show");
|
|
|
+ if (
|
|
|
+ pf_scheduler_add (
|
|
|
+ net,
|
|
|
+ 2000000,
|
|
|
+ pf_mera_rte_show_periodic,
|
|
|
+ handle,
|
|
|
+ &handle->sched_handle) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (PF_MERA_LOG, "MERA(%d): Failed to add timer\n", __LINE__);
|
|
|
+ exit (EXIT_FAILURE);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_write (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ uint32_t offset,
|
|
|
+ const uint8_t * data,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ uint16_t i;
|
|
|
+ mera_ib_rtp_data_t write_req;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (frame->active)
|
|
|
+ {
|
|
|
+ for (i = 0; i < len; i++)
|
|
|
+ {
|
|
|
+ write_req.value = data[i];
|
|
|
+ write_req.offset = offset + i;
|
|
|
+ ret =
|
|
|
+ mera_ib_rtp_data_set (handle->mera_lib, frame->rtp_id, &write_req);
|
|
|
+
|
|
|
+ if (ret != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to write frame RTP frame buffer\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_write_input (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ const pf_iodata_object_t * p_iodata,
|
|
|
+ const uint8_t * data,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ int ret = -1;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+
|
|
|
+ if (!frame->active)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry = get_rte_object (frame, p_iodata->slot_nbr, p_iodata->subslot_nbr);
|
|
|
+
|
|
|
+ switch (entry->io_interface_type)
|
|
|
+ {
|
|
|
+ case MERA_IO_INTF_SRAM:
|
|
|
+ if (
|
|
|
+ mera_ib_ral_req (
|
|
|
+ handle->mera_lib,
|
|
|
+ entry->ib_ral_id,
|
|
|
+ &entry->ib_ral_buf) == 0)
|
|
|
+ {
|
|
|
+ ret = pf_sram_write (
|
|
|
+ entry->sram_address + entry->ib_ral_buf.addr,
|
|
|
+ data,
|
|
|
+ len);
|
|
|
+
|
|
|
+ if (mera_ib_ral_rel (handle->mera_lib, entry->ib_ral_id) != 0)
|
|
|
+ {
|
|
|
+ ret = -1;
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Releasing RAL buffer failed\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ret = -1;
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Request for RAL buffer failed\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case PNET_MERA_DATA_TYPE_QSPI:
|
|
|
+ default:
|
|
|
+ /* Write not supported */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_read_data_and_iops (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ const pf_iodata_object_t * p_iodata,
|
|
|
+ uint8_t * p_data,
|
|
|
+ uint16_t data_len,
|
|
|
+ uint8_t * p_iops,
|
|
|
+ uint8_t iops_len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ int err = 0;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+ mera_buf_t internal_wal_buf;
|
|
|
+
|
|
|
+ *p_iops = PNET_IOXS_GOOD;
|
|
|
+
|
|
|
+ if (!frame->active)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p_iodata->slot_nbr == PNET_SLOT_DAP_IDENT)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data_len == 0 || iops_len == 0)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry = get_rte_object (frame, p_iodata->slot_nbr, p_iodata->subslot_nbr);
|
|
|
+
|
|
|
+ switch (entry->io_interface_type)
|
|
|
+ {
|
|
|
+ case MERA_IO_INTF_SRAM:
|
|
|
+ if (pf_sram_read (entry->sram_address, p_data, data_len) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Failed to read SRAM (input) \n",
|
|
|
+ __LINE__,
|
|
|
+ p_iodata->slot_nbr,
|
|
|
+ p_iodata->subslot_nbr);
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MERA_IO_INTF_QSPI:
|
|
|
+ err = mera_ob_wal_req (
|
|
|
+ handle->mera_lib,
|
|
|
+ frame->internal_wal_id,
|
|
|
+ &internal_wal_buf);
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to req wal buffer for internal transfer\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ pf_sram_read (
|
|
|
+ entry->sram_address + internal_wal_buf.addr,
|
|
|
+ p_data,
|
|
|
+ data_len) != 0)
|
|
|
+ {
|
|
|
+ mera_ob_wal_rel (handle->mera_lib, frame->internal_wal_id);
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Failed to read SRAM (input) \n",
|
|
|
+ __LINE__,
|
|
|
+ p_iodata->slot_nbr,
|
|
|
+ p_iodata->subslot_nbr);
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ mera_ob_wal_rel (handle->mera_lib, frame->internal_wal_id);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] unsupported interface type\n",
|
|
|
+ __LINE__,
|
|
|
+ p_iodata->slot_nbr,
|
|
|
+ p_iodata->subslot_nbr);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_write_iops (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ const pf_iodata_object_t * p_iodata,
|
|
|
+ const uint8_t * iops,
|
|
|
+ uint8_t len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+
|
|
|
+ if (p_iodata->slot_nbr == PNET_SLOT_DAP_IDENT)
|
|
|
+ {
|
|
|
+ /* Setting only supported on data submodules
|
|
|
+ * DAP iops set during initial RTE configuration
|
|
|
+ * and never changed.
|
|
|
+ */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!frame->active)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry = get_rte_object (frame, p_iodata->slot_nbr, p_iodata->subslot_nbr);
|
|
|
+
|
|
|
+ switch (entry->io_interface_type)
|
|
|
+ {
|
|
|
+ case MERA_IO_INTF_SRAM:
|
|
|
+ return pf_mera_ppm_write (
|
|
|
+ net,
|
|
|
+ (pf_drv_frame_t *)frame,
|
|
|
+ frame->config.p_iocr->ppm.buffer_pos + p_iodata->iops_offset,
|
|
|
+ iops,
|
|
|
+ len);
|
|
|
+
|
|
|
+ case MERA_IO_INTF_QSPI:
|
|
|
+ default:
|
|
|
+ /* Writing IOPS is not supported
|
|
|
+ * Automatically updated by RTE
|
|
|
+ */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_write_iocs (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ const pf_iodata_object_t * p_iodata,
|
|
|
+ const uint8_t * iops,
|
|
|
+ uint8_t len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+
|
|
|
+ if (!frame->active)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pf_mera_ppm_write (
|
|
|
+ net,
|
|
|
+ drv_frame,
|
|
|
+ frame->config.p_iocr->ppm.buffer_pos + p_iodata->iocs_offset,
|
|
|
+ iops,
|
|
|
+ len);
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_write_data_status (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ uint8_t data_status)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ if (frame == NULL || !frame->active)
|
|
|
+ {
|
|
|
+ /* Ignore writes during ppm initialization */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pf_mera_ppm_write (
|
|
|
+ net,
|
|
|
+ drv_frame,
|
|
|
+ frame->config.p_iocr->ppm.data_status_offset,
|
|
|
+ &data_status,
|
|
|
+ 1);
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_ppm_stop (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ uint16_t i, j;
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_PPM_LOG, "MERA(%d): Stop PPM\n", __LINE__);
|
|
|
+ if (frame->active)
|
|
|
+ {
|
|
|
+ mera_ib_flush (handle->mera_lib);
|
|
|
+ pf_mera_delete_vcam_rule (frame->vcam_id);
|
|
|
+
|
|
|
+ for (i = 0; i < PNET_MAX_SLOTS; i++)
|
|
|
+ {
|
|
|
+ for (j = 0; j < PNET_MAX_SUBSLOTS; j++)
|
|
|
+ {
|
|
|
+ pf_mera_ral_id_free (handle, frame->rte_object[i][j].ib_ral_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): No action - PPM is not started\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Set the general RTE configuration for a CPM frame.
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ob_rtp_config (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ mera_ob_rtp_conf_t ob_rtp_config = {0};
|
|
|
+
|
|
|
+ ob_rtp_config.type = MERA_RTP_TYPE_PN;
|
|
|
+ ob_rtp_config.grp_id = PF_MERA_GROUP_ID_NONE;
|
|
|
+ ob_rtp_config.length = sizeof (uint16_t) + /* frame_id */
|
|
|
+ frame->config.p_iocr->param.c_sdu_length + /* Profinet
|
|
|
+ data
|
|
|
+ length
|
|
|
+ */
|
|
|
+ sizeof (uint16_t) + /* cycle counter */
|
|
|
+ 1 + /* data status */
|
|
|
+ 1; /* transfer status */
|
|
|
+
|
|
|
+ ob_rtp_config.pn_ds = PF_MERA_DATA_STATUS_MASK;
|
|
|
+ ob_rtp_config.pn_discard = false;
|
|
|
+ ob_rtp_config.opc_grp_ver = 0;
|
|
|
+ ob_rtp_config.wal_enable = true;
|
|
|
+ ob_rtp_config.wal_id = frame->ob_wal_id;
|
|
|
+
|
|
|
+ ob_rtp_config.time.offset = PF_MERA_OB_RTP_TIME_OFFSET;
|
|
|
+ ob_rtp_config.time.interval = 0;
|
|
|
+ ob_rtp_config.time_cnt = 0;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): mera_ob_rtp_conf_set "
|
|
|
+ "type:%d "
|
|
|
+ "grp_id:%d "
|
|
|
+ "length:%d "
|
|
|
+ "pn_ds:%d "
|
|
|
+ "pn_discard:%d "
|
|
|
+ "opc_grp_ver:%d "
|
|
|
+ "wal_enable:%d "
|
|
|
+ "wal_id:%d "
|
|
|
+ "time.offset:%d "
|
|
|
+ "time.interval:%d "
|
|
|
+ "time_cnt:%d\n",
|
|
|
+ __LINE__,
|
|
|
+ ob_rtp_config.type,
|
|
|
+ ob_rtp_config.grp_id,
|
|
|
+ ob_rtp_config.length,
|
|
|
+ ob_rtp_config.pn_ds,
|
|
|
+ ob_rtp_config.pn_discard,
|
|
|
+ ob_rtp_config.opc_grp_ver,
|
|
|
+ ob_rtp_config.wal_enable,
|
|
|
+ ob_rtp_config.wal_id,
|
|
|
+ ob_rtp_config.time.offset,
|
|
|
+ ob_rtp_config.time.interval,
|
|
|
+ ob_rtp_config.time_cnt);
|
|
|
+
|
|
|
+ err = mera_ob_rtp_conf_set (mera_lib, frame->rtp_id, &ob_rtp_config);
|
|
|
+ if (err)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set RTP configuration\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Set the data group (DG) configuration for an outbound iodata object
|
|
|
+ * part of a CPM frame.
|
|
|
+ * Sets the frame data offset and length.
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ob_add_dg (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ob_dg_conf_t dg_cfg;
|
|
|
+ mera_ob_dg_ctrl_t dg_ctrl;
|
|
|
+
|
|
|
+ if (mera_ob_dg_init (&dg_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to init outbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ dg_cfg.dg_id = entry->ob_dg_id;
|
|
|
+ dg_cfg.pdu_offset = entry->iodata->data_offset + frame->rte_data_offset;
|
|
|
+ dg_cfg.length = entry->iodata->data_length;
|
|
|
+ dg_cfg.valid_offset = entry->iodata->iops_offset + frame->rte_data_offset;
|
|
|
+
|
|
|
+ dg_cfg.valid_chk = true;
|
|
|
+ dg_cfg.opc_seq_chk = false;
|
|
|
+ dg_cfg.opc_code_chk = false;
|
|
|
+ dg_cfg.invalid_default = true;
|
|
|
+ if (entry->default_data != NULL)
|
|
|
+ {
|
|
|
+ memcpy (dg_cfg.data, entry->default_data, entry->iodata->data_length);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memset (dg_cfg.data, 0, entry->iodata->data_length);
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): mera_ob_dg_add "
|
|
|
+ "rtp_id:%d "
|
|
|
+ "cfg.dg_id:%d "
|
|
|
+ "cfg.pdu_offset:%d "
|
|
|
+ "cfg.length:%d "
|
|
|
+ "cfg.valid_offset:%d "
|
|
|
+ "cfg.valid_chk:%d "
|
|
|
+ "cfg.opc_seq_chk:%d "
|
|
|
+ "cfg.opc_code_chk:%d "
|
|
|
+ "cfg.invalid_default:%d\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->rtp_id,
|
|
|
+ dg_cfg.dg_id,
|
|
|
+ dg_cfg.pdu_offset,
|
|
|
+ dg_cfg.length,
|
|
|
+ dg_cfg.valid_offset,
|
|
|
+ dg_cfg.valid_chk,
|
|
|
+ dg_cfg.opc_seq_chk,
|
|
|
+ dg_cfg.opc_code_chk,
|
|
|
+ dg_cfg.invalid_default);
|
|
|
+
|
|
|
+ if (mera_ob_dg_add (mera_lib, frame->rtp_id, &dg_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add outbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ dg_ctrl.enable = true;
|
|
|
+
|
|
|
+ if (mera_ob_dg_ctrl_set (mera_lib, frame->rtp_id, entry->ob_dg_id, &dg_ctrl) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to enable outbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Set the Write Action (WA) for an outbound iodata object
|
|
|
+ * part of a CPM frame.
|
|
|
+ * Sets the data sink (SRAM/QSPI address).
|
|
|
+ * @param mera_lib In: Ref to mera instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_ob_add_wa (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ob_wa_conf_t wa_cfg;
|
|
|
+ if (mera_ob_wa_init (&wa_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed init outbound write action\n",
|
|
|
+ __LINE__);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ wa_cfg.internal = false;
|
|
|
+ wa_cfg.rtp_id = frame->rtp_id;
|
|
|
+ wa_cfg.grp_id = PF_MERA_GROUP_ID_NONE;
|
|
|
+ wa_cfg.dg_id = entry->ob_dg_id;
|
|
|
+ wa_cfg.wr_addr.intf = MERA_IO_INTF_SRAM;
|
|
|
+ wa_cfg.wr_addr.addr = entry->sram_address;
|
|
|
+
|
|
|
+ wa_cfg.length = entry->iodata->data_length;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): mera_ob_wa_add "
|
|
|
+ "wal_id:%d "
|
|
|
+ "cfg.internal:%d "
|
|
|
+ "cfg.rtp_id:%d "
|
|
|
+ "cfg.grp_id:%d "
|
|
|
+ "cfg.dg_id:%d "
|
|
|
+ "cfg.length:%d "
|
|
|
+ "cfg.wr_addr.intf:%d-%s "
|
|
|
+ "cfg.wr_addr.addr:0x%x\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->ob_wal_id,
|
|
|
+ wa_cfg.internal,
|
|
|
+ wa_cfg.rtp_id,
|
|
|
+ wa_cfg.grp_id,
|
|
|
+ wa_cfg.dg_id,
|
|
|
+ wa_cfg.length,
|
|
|
+ wa_cfg.wr_addr.intf,
|
|
|
+ pf_mera_interface_type_to_str (wa_cfg.wr_addr.intf),
|
|
|
+ wa_cfg.wr_addr.addr);
|
|
|
+
|
|
|
+ if (mera_ob_wa_add (mera_lib, frame->ob_wal_id, &wa_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add outbound read action\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry->io_interface_type == MERA_IO_INTF_QSPI)
|
|
|
+ {
|
|
|
+ wa_cfg.wr_addr.addr = entry->qspi_address;
|
|
|
+ wa_cfg.wr_addr.intf = MERA_IO_INTF_QSPI;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): mera_ob_wa_add "
|
|
|
+ "wal_id:%d "
|
|
|
+ "cfg.internal:%d "
|
|
|
+ "cfg.rtp_id:%d "
|
|
|
+ "cfg.grp_id:%d "
|
|
|
+ "cfg.dg_id:%d "
|
|
|
+ "cfg.length:%d "
|
|
|
+ "cfg.wr_addr.intf:%d-%s "
|
|
|
+ "cfg.wr_addr.addr:0x%x\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->ob_wal_id,
|
|
|
+ wa_cfg.internal,
|
|
|
+ wa_cfg.rtp_id,
|
|
|
+ wa_cfg.grp_id,
|
|
|
+ wa_cfg.dg_id,
|
|
|
+ wa_cfg.length,
|
|
|
+ wa_cfg.wr_addr.intf,
|
|
|
+ pf_mera_interface_type_to_str (wa_cfg.wr_addr.intf),
|
|
|
+ wa_cfg.wr_addr.addr);
|
|
|
+
|
|
|
+ if (mera_ob_wa_add (mera_lib, frame->ob_wal_id, &wa_cfg) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add outbound read action\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Set the RTE configuration for an outbound iodata object
|
|
|
+ * part of a CPM frame. Sets datagroup and write action.
|
|
|
+ * @param mera_lib In: Ref to mera lib instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_add_ob_entry (
|
|
|
+ struct mera_inst * mera_lib,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Configure outbound data entry\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->iodata->slot_nbr,
|
|
|
+ entry->iodata->subslot_nbr);
|
|
|
+
|
|
|
+ entry->in_use = true;
|
|
|
+
|
|
|
+ if (pf_mera_ob_add_dg (mera_lib, frame, entry) != 0)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_ob_add_wa (mera_lib, frame, entry) != 0)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Generate RTE configurations for all iodata objects in a CPM type
|
|
|
+ * of communication relation.
|
|
|
+ * @param handle InOut: Ref to mera instance
|
|
|
+ * @param frame InOut: The PPM frame
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_cpm_config (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ uint16_t slot, subslot;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+ const pf_mera_rte_cfg_t * entry_rte_data_cfg; /* qspi address */
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_CPM_LOG, "MERA(%d): Apply RTE configuration (CMP)\n", __LINE__);
|
|
|
+
|
|
|
+ for (slot = 0; slot < PNET_MAX_SLOTS; slot++)
|
|
|
+ {
|
|
|
+ for (subslot = 0; subslot < PNET_MAX_SUBSLOTS; subslot++)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ frame->rte_object[slot][subslot].iodata != NULL &&
|
|
|
+ frame->rte_object[slot][subslot].iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ entry = &frame->rte_object[slot][subslot];
|
|
|
+ entry_rte_data_cfg = &handle->rte_data_cfg[slot][subslot];
|
|
|
+ entry->ob_dg_id = frame->ob_dg_count++;
|
|
|
+
|
|
|
+ if (entry_rte_data_cfg->valid)
|
|
|
+ {
|
|
|
+ entry->io_interface_type =
|
|
|
+ pf_mera_interface_type (entry_rte_data_cfg->cfg.type);
|
|
|
+
|
|
|
+#if PF_MERA_ALLOW_APPLICATION_SRAM
|
|
|
+ if (entry_rte_data_cfg->cfg.type == PNET_MERA_DATA_TYPE_SRAM)
|
|
|
+ {
|
|
|
+ entry->sram_address = entry_rte_data_cfg->cfg.address;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ entry->qspi_address = entry_rte_data_cfg->cfg.address;
|
|
|
+ entry->default_data = entry_rte_data_cfg->cfg.default_data;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry->sram_address == PF_SRAM_INVALID_ADDRESS)
|
|
|
+ {
|
|
|
+ /* SRAM address has not been set by application
|
|
|
+ * use address from SRAM frame
|
|
|
+ */
|
|
|
+ entry->sram_address = frame->sram_frame_address +
|
|
|
+ frame->rte_data_offset +
|
|
|
+ entry->iodata->data_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u]: Interface: %s Start address: 0x%x Size: "
|
|
|
+ "%d\n",
|
|
|
+ __LINE__,
|
|
|
+ entry->iodata->slot_nbr,
|
|
|
+ entry->iodata->subslot_nbr,
|
|
|
+ pf_mera_interface_type_to_str (entry->io_interface_type),
|
|
|
+ entry->io_interface_type == MERA_IO_INTF_QSPI
|
|
|
+ ? entry->qspi_address
|
|
|
+ : entry->sram_address,
|
|
|
+ entry->iodata->data_length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Configure and start a RTE configuration for a CPM frame.
|
|
|
+ * Sets the general RTE configuration and the configuration
|
|
|
+ * for each iodata object in the communication relationship.
|
|
|
+ * @param handle In: Ref to mera instance
|
|
|
+ * @param frame In: Ref to frame
|
|
|
+ * @return 0 on success, -1 on error
|
|
|
+ */
|
|
|
+static int pf_mera_cpm_start_rte (pf_mera_t * handle, pf_mera_frame_t * frame)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ pf_iocr_t * p_iocr = frame->config.p_iocr;
|
|
|
+ uint16_t slot, subslot;
|
|
|
+ mera_ob_wal_conf_t wal_conf;
|
|
|
+ mera_ob_rtp_state_t state;
|
|
|
+
|
|
|
+ err = ob_add_vcam_rule (
|
|
|
+ frame->vcam_id,
|
|
|
+ p_iocr->param.iocr_tag_header.vlan_id,
|
|
|
+ &frame->config.main_mac_addr,
|
|
|
+ frame->vlan_idx,
|
|
|
+ p_iocr->param.frame_id,
|
|
|
+ frame->rtp_id);
|
|
|
+
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to add outbound vcam rule\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = pf_mera_ob_rtp_config (handle->mera_lib, frame);
|
|
|
+ if (err != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set outbound RTP configuration\n",
|
|
|
+ __LINE__);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (slot = 0; slot < PNET_MAX_SLOTS; slot++)
|
|
|
+ {
|
|
|
+ for (subslot = 0; subslot < PNET_MAX_SUBSLOTS; subslot++)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ frame->rte_object[slot][subslot].iodata != NULL &&
|
|
|
+ frame->rte_object[slot][subslot].iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ pf_mera_add_ob_entry (
|
|
|
+ handle->mera_lib,
|
|
|
+ frame,
|
|
|
+ &frame->rte_object[slot][subslot]) != 0)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add WAL to trigger reset to default value on DHT watchdog timeout. */
|
|
|
+ mera_ob_wal_conf_get (handle->mera_lib, frame->ob_wal_id, &wal_conf);
|
|
|
+ wal_conf.time.offset = 10000;
|
|
|
+ wal_conf.time.interval = frame->config.p_iocr->cpm.control_interval * 1000;
|
|
|
+
|
|
|
+ if (mera_ob_wal_conf_set (handle->mera_lib, frame->ob_wal_id, &wal_conf) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to set outbound RTP WAL \n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Activate rtp id. Needed if DHT has expired in previous connection. */
|
|
|
+ state.active = true;
|
|
|
+ if (mera_ob_rtp_state_set (handle->mera_lib, frame->rtp_id, &state) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to set RTP state \n", __LINE__);
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->active = true;
|
|
|
+
|
|
|
+ if (
|
|
|
+ mera_event_enable (
|
|
|
+ handle->mera_lib,
|
|
|
+ (MERA_EVENT_RTP_STATE_STOPPED | MERA_EVENT_PN_DS_MISMATCH |
|
|
|
+ MERA_EVENT_DG_INVALID),
|
|
|
+ true) != 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to enable outbound events\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+pf_drv_frame_t * pf_mera_cpm_alloc (
|
|
|
+ pnet_t * net,
|
|
|
+ const pf_mera_frame_cfg_t * cfg)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ pf_mera_frame_t * frame = NULL;
|
|
|
+ pf_iodata_object_t * p_iodata;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+ uint16_t i;
|
|
|
+
|
|
|
+ if (cfg == NULL || cfg->p_iocr == NULL || handle == NULL)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ frame = pf_mera_alloc_frame (handle);
|
|
|
+ if (frame == NULL)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->is_cpm = true;
|
|
|
+
|
|
|
+ frame->sram_frame_address = pf_sram_frame_alloc();
|
|
|
+ if (frame->sram_frame_address == 0)
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to alloc SRAM for CPM frame\n",
|
|
|
+ __LINE__);
|
|
|
+ pf_mera_free_frame (handle, frame);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Allocated CPM SRAM frame at 0x%x\n",
|
|
|
+ __LINE__,
|
|
|
+ frame->sram_frame_address);
|
|
|
+
|
|
|
+ frame->config = *cfg;
|
|
|
+ frame->port = cfg->port;
|
|
|
+
|
|
|
+ for (i = 0; i < frame->config.p_iocr->nbr_data_desc; i++)
|
|
|
+ {
|
|
|
+ p_iodata = &frame->config.p_iocr->data_desc[i];
|
|
|
+ if (p_iodata->data_length > 0)
|
|
|
+ {
|
|
|
+ entry =
|
|
|
+ get_rte_object (frame, p_iodata->slot_nbr, p_iodata->subslot_nbr);
|
|
|
+ entry->iodata = p_iodata;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ frame->vcam_id = pf_mera_vcam_id_alloc (handle);
|
|
|
+ frame->vlan_idx = pf_mera_vlan_index_alloc (handle);
|
|
|
+ frame->rtp_id = pf_mera_rtp_id_alloc (handle);
|
|
|
+ frame->ob_wal_id = pf_mera_wal_id_alloc (handle);
|
|
|
+ frame->rte_data_offset = PF_MERA_CPM_IODATA_OFFSET;
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_CPM_LOG, "MERA(%d): CPM frame allocated\n", __LINE__);
|
|
|
+
|
|
|
+ return (pf_drv_frame_t *)frame;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_start (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+
|
|
|
+ if (handle == NULL || frame == NULL || frame->config.p_iocr == NULL)
|
|
|
+ {
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Failed to start RTE - parameter error\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pf_mera_cpm_config (handle, frame) != 0)
|
|
|
+ {
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Failed to start RTE - data config error\n",
|
|
|
+ __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pf_mera_cpm_start_rte (handle, frame);
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_activate_rte_dht (pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ mera_ob_rtp_conf_t ob_rtp_config;
|
|
|
+
|
|
|
+ if (mera_ob_rtp_conf_get (frame->mera_lib, frame->rtp_id, &ob_rtp_config) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_CPM_LOG, "MERA(%d): Failed get CPM RTE config\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Configure CPM data hold timeout.
|
|
|
+ * RTP and group will stop when configured timeout expires.
|
|
|
+ * Default values will be applied to all DGs on
|
|
|
+ * writes triggered when group is stopped.
|
|
|
+ */
|
|
|
+
|
|
|
+ ob_rtp_config.time.offset = MERA_TIME_OFFSET_NONE;
|
|
|
+ ob_rtp_config.time.interval =
|
|
|
+ frame->config.p_iocr->cpm.control_interval * 1000;
|
|
|
+ ob_rtp_config.time_cnt = frame->config.p_iocr->cpm.data_hold_factor;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Reconfigure ob rtp dht timing =%uns cnt=%d\n",
|
|
|
+ __LINE__,
|
|
|
+ ob_rtp_config.time.interval,
|
|
|
+ ob_rtp_config.time_cnt);
|
|
|
+
|
|
|
+ if (mera_ob_rtp_conf_set (frame->mera_lib, frame->rtp_id, &ob_rtp_config) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_CPM_LOG, "MERA(%d): Failed set CPM RTE config\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_free (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ LOG_DEBUG (PF_MERA_LOG, "MERA(%d): Free CPM frame\n", __LINE__);
|
|
|
+ if (frame != NULL)
|
|
|
+ {
|
|
|
+ pf_mera_vcam_id_free (handle, frame->vcam_id);
|
|
|
+ pf_mera_vlan_index_free (handle, frame->vlan_idx);
|
|
|
+ pf_mera_rtp_id_free (handle, frame->rtp_id);
|
|
|
+ pf_mera_wal_id_free (handle, frame->ob_wal_id);
|
|
|
+ pf_sram_frame_free (frame->sram_frame_address);
|
|
|
+ pf_mera_free_frame (handle, frame);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ LOG_ERROR (PF_MERA_LOG, "MERA(%d): Failed to free CPM frame\n", __LINE__);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_stop (pnet_t * net, pf_drv_frame_t * drv_frame)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+
|
|
|
+ LOG_DEBUG (PF_PPM_LOG, "MERA(%d): Stop CPM\n", __LINE__);
|
|
|
+
|
|
|
+ mera_ob_wal_rel (handle->mera_lib, frame->ob_wal_id);
|
|
|
+
|
|
|
+ if (mera_ob_flush (handle->mera_lib) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_CPM_LOG, "MERA(%d): Failed to flush rtp\n", __LINE__);
|
|
|
+ }
|
|
|
+ if (pf_mera_delete_vcam_rule (frame->vcam_id) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (PF_CPM_LOG, "MERA(%d): Failed to delete VCAM rule\n", __LINE__);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Stop periodic debug info */
|
|
|
+ pf_scheduler_remove_if_running (net, &handle->sched_handle);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Disable RTE write operations for an iodata object.
|
|
|
+ * Intended to be used while reading SRAM data groups.
|
|
|
+ * @param mera InOut: Ref to mera library instance
|
|
|
+ * @param frame In: CPM frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ */
|
|
|
+static void pf_mera_disable_ob_entry (
|
|
|
+ struct mera_inst * mera,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ob_dg_ctrl_t dg_ctrl;
|
|
|
+
|
|
|
+ dg_ctrl.enable = false;
|
|
|
+
|
|
|
+ if (mera_ob_dg_ctrl_set (mera, frame->rtp_id, entry->ob_dg_id, &dg_ctrl) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to disable outbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Enable RTE write operations for an iodata object.
|
|
|
+ * @param mera InOut: Ref to mera library instance
|
|
|
+ * @param frame In: CPM frame
|
|
|
+ * @param entry In: Iodata object configuration
|
|
|
+ */
|
|
|
+static void pf_mera_enable_ob_entry (
|
|
|
+ struct mera_inst * mera,
|
|
|
+ pf_mera_frame_t * frame,
|
|
|
+ pf_rte_object_t * entry)
|
|
|
+{
|
|
|
+ mera_ob_dg_ctrl_t dg_ctrl;
|
|
|
+
|
|
|
+ dg_ctrl.enable = true;
|
|
|
+
|
|
|
+ if (mera_ob_dg_ctrl_set (mera, frame->rtp_id, entry->ob_dg_id, &dg_ctrl) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): Failed to enable outbound data group\n",
|
|
|
+ __LINE__);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_read_data_and_iops (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ uint16_t slot_nbr,
|
|
|
+ uint16_t subslot_nbr,
|
|
|
+ bool * p_new_flag,
|
|
|
+ uint8_t * p_data,
|
|
|
+ uint16_t data_len,
|
|
|
+ uint8_t * p_iops,
|
|
|
+ uint8_t iops_len)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ mera_ob_dg_status_t status;
|
|
|
+ pf_rte_object_t * entry;
|
|
|
+
|
|
|
+ *p_iops = PNET_IOXS_BAD;
|
|
|
+
|
|
|
+ if (!frame->active)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (slot_nbr == PNET_SLOT_DAP_IDENT)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data_len == 0 || iops_len == 0)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry = get_rte_object (frame, slot_nbr, subslot_nbr);
|
|
|
+
|
|
|
+ switch (entry->io_interface_type)
|
|
|
+ {
|
|
|
+ case MERA_IO_INTF_SRAM:
|
|
|
+ case MERA_IO_INTF_QSPI:
|
|
|
+ if (
|
|
|
+ mera_ob_dg_status_get (
|
|
|
+ handle->mera_lib,
|
|
|
+ frame->rtp_id,
|
|
|
+ entry->ob_dg_id,
|
|
|
+ &status) != 0)
|
|
|
+ {
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Failed to read data group status "
|
|
|
+ "(output)\n",
|
|
|
+ __LINE__,
|
|
|
+ slot_nbr,
|
|
|
+ subslot_nbr);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status.valid_chk)
|
|
|
+ {
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] IOPS BAD, Invalid output data\n",
|
|
|
+ __LINE__,
|
|
|
+ slot_nbr,
|
|
|
+ subslot_nbr);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ *p_iops = PNET_IOXS_GOOD;
|
|
|
+ }
|
|
|
+
|
|
|
+ pf_mera_disable_ob_entry (handle->mera_lib, frame, entry);
|
|
|
+
|
|
|
+ if (pf_sram_read (entry->sram_address, p_data, data_len) != 0)
|
|
|
+ {
|
|
|
+ pf_mera_enable_ob_entry (handle->mera_lib, frame, entry);
|
|
|
+
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Failed to read SRAM (output) \n",
|
|
|
+ __LINE__,
|
|
|
+ slot_nbr,
|
|
|
+ subslot_nbr);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pf_mera_enable_ob_entry (handle->mera_lib, frame, entry);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ LOG_ERROR (
|
|
|
+ PF_MERA_LOG,
|
|
|
+ "MERA(%d): [%u,%u] unsupported interface type\n",
|
|
|
+ __LINE__,
|
|
|
+ slot_nbr,
|
|
|
+ subslot_nbr);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_read_iocs (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * frame,
|
|
|
+ uint16_t slot_nbr,
|
|
|
+ uint16_t subslot_nbr,
|
|
|
+ uint8_t * p_iocs,
|
|
|
+ uint8_t iocs_len)
|
|
|
+{
|
|
|
+ /* TODO - Figure out how this can be read from frame memory */
|
|
|
+ /* this is implemented in pf_mera_cpm_read_data_and_iops.
|
|
|
+ review this and figure out best implementation */
|
|
|
+ if (iocs_len > 0)
|
|
|
+ {
|
|
|
+ *p_iocs = PNET_IOXS_GOOD;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_poll_cpm_events (
|
|
|
+ pnet_t * net,
|
|
|
+ pf_drv_frame_t * frame,
|
|
|
+ pf_mera_event_t * evt)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ mera_event_t mera_event;
|
|
|
+
|
|
|
+ if (net == NULL || frame == NULL || evt == NULL)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset (evt, 0, sizeof (pf_mera_event_t));
|
|
|
+
|
|
|
+ if (mera_event_poll (handle->mera_lib, (mera_event_t *)&mera_event) == 0)
|
|
|
+ {
|
|
|
+ if ((MERA_EVENT_RTP_STATE_STOPPED & mera_event) != 0)
|
|
|
+ {
|
|
|
+ LOG_INFO (PF_MERA_LOG, "MERA(%d): CPM RTP stopped event\n", __LINE__);
|
|
|
+ evt->stopped = true;
|
|
|
+ }
|
|
|
+ if ((MERA_EVENT_PN_DS_MISMATCH & mera_event) != 0)
|
|
|
+ {
|
|
|
+ evt->data_status_mismatch = true;
|
|
|
+ }
|
|
|
+ if ((MERA_EVENT_DG_INVALID & mera_event) != 0)
|
|
|
+ {
|
|
|
+ evt->invalid_dg = true;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_read_data_status (
|
|
|
+ pf_drv_frame_t * drv_frame,
|
|
|
+ uint8_t * p_data_status)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ mera_ob_rtp_status_t status;
|
|
|
+
|
|
|
+ if (mera_ob_rtp_status_get (frame->mera_lib, frame->rtp_id, &status) == 0)
|
|
|
+ {
|
|
|
+ if (status.pn_ds_chk == 1)
|
|
|
+ {
|
|
|
+ /* RTE has a detected a data status mismatch.
|
|
|
+ Report RTE data status
|
|
|
+ */
|
|
|
+ *p_data_status = status.pn_ds;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Data status ok - report checked data status */
|
|
|
+ *p_data_status = PF_MERA_DATA_STATUS_MASK;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_cpm_read_rx_count (pf_drv_frame_t * drv_frame, uint64_t * rx_count)
|
|
|
+{
|
|
|
+ pf_mera_frame_t * frame = (pf_mera_frame_t *)drv_frame;
|
|
|
+ mera_ob_rtp_counters_t counters;
|
|
|
+
|
|
|
+ if (mera_ob_rtp_counters_get (frame->mera_lib, frame->rtp_id, &counters) == 0)
|
|
|
+ {
|
|
|
+ if (counters.rx_0 >= frame->rx_count)
|
|
|
+ {
|
|
|
+ *rx_count = counters.rx_0 - frame->rx_count;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Wrap around */
|
|
|
+ *rx_count = counters.rx_0 + (UINT64_MAX - counters.rx_0);
|
|
|
+ }
|
|
|
+ frame->rx_count = counters.rx_0;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ *rx_count = 0;
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+void pf_mera_show (pnet_t * net, bool cpm, bool ppm)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ mera_debug_info_t info;
|
|
|
+
|
|
|
+ info.group = MERA_DEBUG_GROUP_GEN;
|
|
|
+ info.rtp_id = 0; /* All RTP IDs */
|
|
|
+ info.full = false; /* Only active IDs */
|
|
|
+ info.clear = true;
|
|
|
+
|
|
|
+ if (cpm && ppm)
|
|
|
+ {
|
|
|
+ info.group = MERA_DEBUG_GROUP_ALL;
|
|
|
+ }
|
|
|
+ else if (cpm)
|
|
|
+ {
|
|
|
+ info.group = MERA_DEBUG_GROUP_OB;
|
|
|
+ }
|
|
|
+ else if (ppm)
|
|
|
+ {
|
|
|
+ info.group = MERA_DEBUG_GROUP_IB;
|
|
|
+ }
|
|
|
+
|
|
|
+ printf ("RTE Status:\n");
|
|
|
+ mera_debug_info_print (handle->mera_lib, pf_mera_printf_cb, &info);
|
|
|
+}
|
|
|
+
|
|
|
+int pf_mera_get_port_from_remote_mac (
|
|
|
+ pnet_ethaddr_t * mac_addr,
|
|
|
+ uint16_t * p_port)
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+ char cmd[128] = {0};
|
|
|
+ char result[100] = {0};
|
|
|
+ FILE * fd = NULL;
|
|
|
+ char mac_addr_str[PF_MERA_SCRIPT_ARG_LEN] = {0};
|
|
|
+
|
|
|
+ *p_port = 0;
|
|
|
+
|
|
|
+ snprintf (
|
|
|
+ mac_addr_str,
|
|
|
+ sizeof (mac_addr_str),
|
|
|
+ "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
+ mac_addr->addr[0],
|
|
|
+ mac_addr->addr[1],
|
|
|
+ mac_addr->addr[2],
|
|
|
+ mac_addr->addr[3],
|
|
|
+ mac_addr->addr[4],
|
|
|
+ mac_addr->addr[5]);
|
|
|
+
|
|
|
+ snprintf (
|
|
|
+ cmd,
|
|
|
+ sizeof (cmd),
|
|
|
+ "brctl showmacs br0 | grep %s | xargs | cut -c1-1",
|
|
|
+ mac_addr_str);
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Use brctl command to get active port: \"%s\"\n",
|
|
|
+ __LINE__,
|
|
|
+ cmd);
|
|
|
+
|
|
|
+ fd = popen (cmd, "r");
|
|
|
+ if (fd != NULL)
|
|
|
+ {
|
|
|
+ if (fgets (result, sizeof (result), fd) != NULL)
|
|
|
+ {
|
|
|
+ *p_port = atoi (result);
|
|
|
+ *p_port = *p_port - 1;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Found mac on bridge interface %u, using port index "
|
|
|
+ "%u\n",
|
|
|
+ __LINE__,
|
|
|
+ *p_port + 1,
|
|
|
+ *p_port);
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOG_FATAL (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): Failed to find mac on bridge, using port index %u\n",
|
|
|
+ __LINE__,
|
|
|
+ *p_port);
|
|
|
+ }
|
|
|
+ pclose (fd);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/* Public function in P-Net API
|
|
|
+ * For iodata objects not mapped to QSPI this operation
|
|
|
+ * is not used. Instead the iodata is automatically mapped
|
|
|
+ * to SRAM by the P-Net stack (this file).
|
|
|
+ *
|
|
|
+ * This config should be part of frame, but there is
|
|
|
+ * no suitable application event at which the configuration
|
|
|
+ * can be passed when CPM/PPM are created but not yet started.
|
|
|
+ */
|
|
|
+int pnet_mera_input_set_rte_config (
|
|
|
+ pnet_t * net,
|
|
|
+ uint32_t api,
|
|
|
+ uint16_t slot,
|
|
|
+ uint16_t subslot,
|
|
|
+ const pnet_mera_rte_data_cfg_t * rte_data_cfg)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_PPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Adding RTE configuration "
|
|
|
+ "%s at address 0x%x (inbound / iodata input)\n",
|
|
|
+ __LINE__,
|
|
|
+ slot,
|
|
|
+ subslot,
|
|
|
+ pf_mera_rte_data_type_to_str (rte_data_cfg->type),
|
|
|
+ rte_data_cfg->address);
|
|
|
+
|
|
|
+ handle->rte_data_cfg[slot][get_subslot_index (subslot)].valid = true;
|
|
|
+ handle->rte_data_cfg[slot][get_subslot_index (subslot)].cfg = *rte_data_cfg;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int pnet_mera_output_set_rte_config (
|
|
|
+ pnet_t * net,
|
|
|
+ uint32_t api,
|
|
|
+ uint16_t slot,
|
|
|
+ uint16_t subslot,
|
|
|
+ const pnet_mera_rte_data_cfg_t * rte_data_cfg)
|
|
|
+{
|
|
|
+ pf_mera_t * handle = (pf_mera_t *)net->hwo_drv;
|
|
|
+
|
|
|
+ LOG_DEBUG (
|
|
|
+ PF_CPM_LOG,
|
|
|
+ "MERA(%d): [%u,%u] Adding RTE configuration "
|
|
|
+ "%s at address 0x%x (outbound / iodata output)\n",
|
|
|
+ __LINE__,
|
|
|
+ slot,
|
|
|
+ subslot,
|
|
|
+ pf_mera_rte_data_type_to_str (rte_data_cfg->type),
|
|
|
+ rte_data_cfg->address);
|
|
|
+
|
|
|
+ handle->rte_data_cfg[slot][get_subslot_index (subslot)].valid = true;
|
|
|
+ handle->rte_data_cfg[slot][get_subslot_index (subslot)].cfg = *rte_data_cfg;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|