AM263Px MCU+ SDK: ICSS-EMAC

| AM263Px MCU+ SDK 26.00.00 |

ICSS-EMAC

# Introduction

The ICSS-EMAC (Industrial Communications Subsystem Ethernet Media Access Controller) driver provide APIs to transmit and receive packets with a firmware based Ethernet switch that has been implemented on PRUICSS cores.

ICSS-EMAC runs on the host processor, provides a well defined set of APIs to configure the firmware, send packets to the firmware and receive packet from the firmware. Industrial Communication Protocol specific firmware (running on PRUICSS cores) implements a 2 port ethernet switch supporting 802.1d at 100 Mbps.

Note
  ICSS-EMAC will be supported for use in Profinet Device, EtherNet/IP Adapter and PRP(Parallel Redundancy Protocol) examples only.
  ICSS firmware to support above protocols or EMAC (to add one or more Ethernet port) is not supported in this release.

# Features Supported

- Packet Receieve: Copying packet received from firmware and providing it to TCP/IP stack or upper layer protocols
- Packet Transmit: Providing packet from a TCP/IP stack or upper layer protocols to firmware
- Storm Prevention
- Host Statistics
- Learning/Forwarding Data Base
- Multicast/VLAN Filtering
- Interrupt handling for Rx, Tx and Link
- Task Creation for Rx, Tx and Link

# SysConfig Features

Note
  It is strongly recommend to use SysConfig where it is available instead of using direct SW API calls. This will help simplify the SW application and also catch common mistakes early in the development cycle.

- Selecting the PRU-ICSS instance
- Selecting port number
- Configuring PHY address for the ports
- Select queue threshold for separating real-time(RT) and non real-time(NRT) traffic
- Specify the size of buffer space
- Provide the task priorities for Rx, Tx and Link tasks

# Features not supported

- Time-triggered send (TTS)
- Firmware Learning mode
- Timer based Interrupt Pacing support

# Terms and Abbreviations

Abbreviation | Expansion
--- | ---
PRU-ICSS | Programmable Real-Time Unit Industrial Communication Subsystem
EMAC | Ethernet MAC
Rx/Tx | Packet Receive/Packet Transmit
INTC | Interrupt Controller
DLR | Device Level Ring (A redundancy protocol for EtherNet/IP)
Host/CPU/Cortex | Used interchangeably and refers to the Application Processor

# ICSS-EMAC Design

ICSS-EMAC Design explains the driver design in detail.

# ICSS-EMAC Queue Management Design

ICSS EMAC Queue Management Design explains the queue management design in detail.

# Usage

## Enable ICSS-EMAC in SysConfig

- Enable ICSS-EMAC via SysConfig, by selecting `ICSS-EMAC` under `TI NETWORKING` in the left pane in SysConfig.
- Parameters mentioned in SysConfig Features should be configured as required.

## Update linker command file

- A shared memory region between CPU and PRU-ICSS needs to be allocated for queues. The size of this region can be configured using "Queue Buffer Size (KB)" option in SysConfig. The value should be configured according to the firmware which will be loaded on PRU-ICSS's cores. Based on the configured size, following code is generated in `ti_drivers_config.c` file. (This is an example, and exact code will vary based on the configured value in SysConfig).

/* ICSS EMAC Packet Buffers */
#define ICSS_EMAC_PKT_BUF_1_MEM_SIZE (65536)
uint8_t gIcssEmacPktBufMem1[ICSS_EMAC_PKT_BUF_1_MEM_SIZE] __attribute__((aligned(128), section(".bss. icss_emac_pktbuf_mem")));

- The linker command file should include this `.bss.icss_emac_pktbuf_mem` section and and map it to a memory region, as shown in below snippet. (Only relevant code sections which should be added are shown)

MEMORY
{
/* shared memories that is used between ICCS and this core. MARK as cache+sharable */
ICSS_PKT_BUF_MEM : ORIGIN = 0x70000000, LENGTH = 0x00010000
}
SECTIONS
{
/* Packet buffer memory used by ICSS */
.bss.icss_emac_pktbuf_mem (NOLOAD): {} > ICSS_PKT_BUF_MEM
}

## Update MPU for the CPU

- The shared memory section (described in the above section) which was put in the linker command file needs to be mapped as `Cached+Sharable` for the CPU.

- This can be done via SysConfig, by adding additional MPU entries using the `MPU` module under `TI DRIVER PORTING LAYER (DPL)` in SysConfig. Following is an example:

## Including the header file

Include the below file to access the APIs

#include <networking/icss_emac/icss_emac.h>

## Initializing the Handle

- PRUICSS handle needs to be initialized before ICSS_EMAC_open and passed using ICSS_EMAC_Params.
- PRUICSS_IntcInitData should be passed based on the firmware. See PRUICSS Interrupt Controller page for more details.
- ICSS-EMAC needs information about the memory map of firmware which will be used. User needs to provide the same information in the form of ICSS_EMAC_FwStaticMmap and ICSS_EMAC_FwDynamicMmap while filling the ICSS_EMAC_Params structure. There are some other offsets related to VLAN filtering and multicast filtering, for which the structures ICSS_EMAC_FwVlanFilterParams and ICSS_EMAC_FwMulticastFilterParams should be passed if IOCTL for VLAN and multicast filtering are going to be called. For Profinet and EtherNet/IP firmware, these structures are defined in `${SDK_INSTALL_PATH}/source/industrial_comms/profinet_device/icss_fwhal/firmware/icss_emac_mmap.h` and `${SDK_INSTALL_PATH}/source/industrial_comms/ethernetip_adapter/icss_fwhal/firmware/icss_emac_mmap.h` respectively.
- Various callback functions can be set using ICSS_EMAC_CallBackObject structure.
- Please see ICSS_EMAC_Params for information on which members are mandatory. If mandatory options are not passed, DebugP_assert will fail in ICSS_EMAC_open.

PRUICSS_Handle pruicssHandle;
ICSS_EMAC_Params icssEmacParams;
ICSS_EMAC_Handle icssEmacHandle;
pruicssHandle = PRUICSS_open(CONFIG_PRU_ICSS1);
DebugP_assert(pruicssHandle != NULL);
ICSS_EMAC_Params_init(&icssEmacParams);
/* Fill the icssEmacParams as needed */
/*Use CONFIG_ICSS_EMAC1 (as configured in SysConfig) macro as parameter to ICSS_EMAC_open */
icssEmacHandle = ICSS_EMAC_open(CONFIG_ICSS_EMAC1, &icssEmacParams);
DebugP_assert(icssEmacHandle != NULL);

## Sending a Packet

ICSS_EMAC_TxArgument txArgs;
int32_t status;
txArgs.icssEmacHandle = icssEmacHandle;
txArgs.srcAddress = &testPacketArray[0];
txArgs.portNumber = ICSS_EMAC_PORT_1;
txArgs.queuePriority = ICSS_EMAC_QUEUE4;
txArgs.lengthOfPacket = sizeof(testPacketArray);
status = ICSS_EMAC_txPacket(&txArgs, NULL);
DebugP_assert(status == SystemP_SUCCESS);

## Receiving a Packet

ICSS_EMAC_rxPktGet is the API used for receving packets. Refer Rx Data Path for more details. Following is an example usage:

/*
Assume that following callback was registered while passing ICSS_EMAC_Params for ICSS_EMAC_open call
icssEmacParams.callBackObject.rxNRTCallBack.callBack = (ICSS_EMAC_CallBack)nrtCallbackRx;
*/
void nrtCallbackRx(void *icssEmacHandleVoidPtr, void *queueNum, void *userArg)
{
ICSS_EMAC_Handle icssEmacHandle = (ICSS_EMAC_Handle)icssEmacHandleVoidPtr;
ICSS_EMAC_RxArgument rxArgs;
int32_t packetLength;
uint8_t testPacketArray[ICSS_EMAC_MAXMTU];
rxArgs.icssEmacHandle = icssEmacHandle;
rxArgs.queueNumber = ((uint32_t)(queueNum));
rxArgs.more = 0; /* Returns more which is set to 1 if there are more frames in the queue */
rxArgs.port = 0; /* Returns port number on which frame was received */
rxArgs.destAddress = (uint32_t)(&testPacketArray[0]);
memset(testPacketArray, 0, ICSS_EMAC_MAXMTU);
packetLength = ICSS_EMAC_rxPktGet(&rxArgs, NULL);
/* Typically packetLength would be returned to caller. In example typecast to void to kill warning
* regarding variable set but not used
*/
(void)packetLength;
}

## IOCTL

IOCTL implementation is identical to the Unix/Linux based IOCTL calls. They provide the application a convenient method to access driver space parameters or modify them. Users are expected to familiarize themselves with the full list of IOCTL calls so that they can utilize all the features provided.

The API for IOCTL is ICSS_EMAC_ioctl. An IOCTL call uses two parameters to find out which driver function to call internally.

1. `ioctlCommand` : Used to locate the module which should be called. Allowed values are ICSS_EMAC_IOCTL_COMMANDS.
2. `ioctlParams` : Used to give module specific instructions. `ioctlParams` consists of
   - `command` : Indicates which specific command to execute. Allowed values for `ioctlParams.command` are ICSS_EMAC_IOCTL_STORM_PREV_CTRL_COMMANDS, ICSS_EMAC_IOCTL_LEARNING_CTRL_COMMANDS, ICSS_EMAC_IOCTL_STATISTICS_COMMANDS, ICSS_EMAC_IOCTL_MULTICAST_FILTER_CTRL_COMMANDS, ICSS_EMAC_IOCTL_VLAN_FILTER_CTRL_COMMANDS.
   - `ioctlVal` : Sometimes the command may require specific input, this is used to provide that.

For example, to disable receive functionality on a port, following code is used.

ICSS_EMAC_IoctlCmd ioctlParams;
uint8_t ioctlvalue = 0;
ioctlvalue = ICSS_EMAC_IOCTL_PORT_CTRL_DISABLE;
ioctlParams.ioctlVal = &ioctlvalue;
ICSS_EMAC_ioctl(icssEmacHandle, ICSS_EMAC_IOCTL_PORT_CTRL, (uint8_t)ICSS_EMAC_PORT_1, (void*)&ioctlParams);

# Dependencies

ICSS-EMAC is dependent on the Application/Transport layer for proper functioning. Following dependencies should be handled by the application layer (example) :

- MDIO Configuration : MDIO Initialization is not done by ICSS-EMAC.
- PHY Initialization/Configuration
- Learning Module Increment Counter Implementation : If learning is enabled, application needs to call IOCTL with ICSS_EMAC_LEARN_CTRL_INC_COUNTER periodically.

# Debug Guide

ICSS-EMAC Debug Guide covers the most obvious use cases and debug scenarios encountered while using ICSS-EMAC.

# API

APIs for ICSS-EMAC

# Dual EMAC and Switch Firmwares

Dual EMAC and Switch

ICSS_EMAC_QUEUE4
#define ICSS_EMAC_QUEUE4
Priority Queue 4.
Definition: icss_emac.h:151
ICSS_EMAC_TxArgument
Tx packet processing information block that needs to passed into call to ICSS_EMAC_txPacket.
Definition: icss_emac.h:834
ICSS_EMAC_Handle
struct ICSS_EMAC_Config_s * ICSS_EMAC_Handle
Alias for ICSS EMAC Handle containing base addresses and modules.
Definition: icss_emac.h:514
ICSS_EMAC_RxArgument
Rx packet processing information block that needs to passed into call to ICSS_EMAC_RxPktGet.
Definition: icss_emac.h:812
ICSS_EMAC_RxArgument::queueNumber
uint8_t queueNumber
Definition: icss_emac.h:817
ICSS_EMAC_txPacket
int32_t ICSS_EMAC_txPacket(const ICSS_EMAC_TxArgument *txArg, void *userArg)
API to queue a frame which has to be transmitted on the specified port queue.
ICSS_EMAC_RxArgument::port
uint8_t port
Definition: icss_emac.h:819
ICSS_EMAC_Params_init
void ICSS_EMAC_Params_init(ICSS_EMAC_Params *params)
Initialize the parmeters data structure with defaults.
ICSS_EMAC_ioctl
int32_t ICSS_EMAC_ioctl(ICSS_EMAC_Handle icssEmacHandle, uint32_t ioctlCommand, uint8_t portNo, void *ioctlParams)
IOCTL Function for ICSS EMAC.
ICSS_EMAC_IOCTL_PORT_CTRL
#define ICSS_EMAC_IOCTL_PORT_CTRL
IOCTL select port control APIs command.
Definition: icss_emac.h:397
ICSS_EMAC_RxArgument::more
uint32_t more
Definition: icss_emac.h:821
ICSS_EMAC_TxArgument::lengthOfPacket
uint16_t lengthOfPacket
Definition: icss_emac.h:843
ICSS_EMAC_TxArgument::portNumber
uint8_t portNumber
Definition: icss_emac.h:839
icss_emac.h
ICSS_EMAC_IoctlCmd::ioctlVal
void * ioctlVal
Definition: icss_emac.h:853
ICSS_EMAC_rxPktGet
int32_t ICSS_EMAC_rxPktGet(ICSS_EMAC_RxArgument *rxArg, void *userArg)
Retrieves a frame from a host queue and copies it in the allocated stack buffer.
ICSS_EMAC_IOCTL_PORT_CTRL_DISABLE
#define ICSS_EMAC_IOCTL_PORT_CTRL_DISABLE
ICSS_EMAC_IOCTL_PORT_CTRL options.
Definition: icss_emac.h:301
ICSS_EMAC_MAXMTU
#define ICSS_EMAC_MAXMTU
Maximum Valid size (incl header + VLAN TAG..., no CRC)
Definition: icss_emac.h:279
ICSS_EMAC_open
ICSS_EMAC_Handle ICSS_EMAC_open(uint32_t idx, const ICSS_EMAC_Params *params)
API to initialize and configure ICSS in MAC/Switch Mode.
SystemP_SUCCESS
#define SystemP_SUCCESS
Return status when the API execution was successful.
Definition: SystemP.h:56
PRUICSS_open
PRUICSS_Handle PRUICSS_open(uint32_t instance)
This function creates the handle for a PRUICSS instance.
ICSS_EMAC_TxArgument::srcAddress
const uint8_t * srcAddress
Definition: icss_emac.h:837
ICSS_EMAC_PORT_1
#define ICSS_EMAC_PORT_1
Used to specify physical port 1 MII 0 (tx)
Definition: icss_emac.h:291
ICSS_EMAC_RxArgument::destAddress
uint32_t destAddress
Definition: icss_emac.h:815
ICSS_EMAC_Params
ICSS_EMAC Parameters.
Definition: icss_emac.h:781
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:187
ICSS_EMAC_IoctlCmd
IOCTL command members for configuring switch/EMAC.
Definition: icss_emac.h:851
PRUICSS_Handle
struct PRUICSS_Config_s * PRUICSS_Handle
A handle that is returned from a PRUICSS_open() call. This handle is required for calling other APIs.
Definition: pruicss/m_v0/pruicss.h:226
ICSS_EMAC_TxArgument::icssEmacHandle
ICSS_EMAC_Handle icssEmacHandle
Definition: icss_emac.h:835
ICSS_EMAC_TxArgument::queuePriority
uint8_t queuePriority
Definition: icss_emac.h:841
ICSS_EMAC_RxArgument::icssEmacHandle
ICSS_EMAC_Handle icssEmacHandle
Definition: icss_emac.h:813