Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,280 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Texas Instruments ICSSM Ethernet driver
*
* Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
*
*/
#ifndef __NET_TI_PRUETH_H
#define __NET_TI_PRUETH_H
#include <linux/phy.h>
#include <linux/types.h>
#include <linux/pruss_driver.h>
#include <linux/remoteproc/pruss.h>
#include "icssm_switch.h"
#include "icssm_prueth_ptp.h"
#include "icssm_prueth_fdb_tbl.h"
/* ICSSM size of redundancy tag */
#define ICSSM_LRE_TAG_SIZE 6
/* PRUSS local memory map */
#define ICSS_LOCAL_SHARED_RAM 0x00010000
#define EMAC_MAX_PKTLEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
/* Below macro is for 1528 Byte Frame support, to Allow even with
* Redundancy tag
*/
#define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \
ICSSM_LRE_TAG_SIZE)
/* PRU Ethernet Type - Ethernet functionality (protocol
* implemented) provided by the PRU firmware being loaded.
*/
enum pruss_ethtype {
PRUSS_ETHTYPE_EMAC = 0,
PRUSS_ETHTYPE_HSR,
PRUSS_ETHTYPE_PRP,
PRUSS_ETHTYPE_SWITCH,
PRUSS_ETHTYPE_MAX,
};
#define PRUETH_IS_EMAC(p) ((p)->eth_type == PRUSS_ETHTYPE_EMAC)
#define PRUETH_IS_SWITCH(p) ((p)->eth_type == PRUSS_ETHTYPE_SWITCH)
/**
* struct prueth_queue_desc - Queue descriptor
* @rd_ptr: Read pointer, points to a buffer descriptor in Shared PRU RAM.
* @wr_ptr: Write pointer, points to a buffer descriptor in Shared PRU RAM.
* @busy_s: Slave queue busy flag, set by slave(us) to request access from
* master(PRU).
* @status: Bit field status register, Bits:
* 0: Master queue busy flag.
* 1: Packet has been placed in collision queue.
* 2: Packet has been discarded due to overflow.
* @max_fill_level: Maximum queue usage seen.
* @overflow_cnt: Count of queue overflows.
*
* Each port has up to 4 queues with variable length. The queue is processed
* as ring buffer with read and write pointers. Both pointers are address
* pointers and increment by 4 for each buffer descriptor position. Queue has
* a length defined in constants and a status.
*/
struct prueth_queue_desc {
u16 rd_ptr;
u16 wr_ptr;
u8 busy_s;
u8 status;
u8 max_fill_level;
u8 overflow_cnt;
};
/**
* struct prueth_queue_info - Information about a queue in memory
* @buffer_offset: buffer offset in OCMC RAM
* @queue_desc_offset: queue descriptor offset in Shared RAM
* @buffer_desc_offset: buffer descriptors offset in Shared RAM
* @buffer_desc_end: end address of buffer descriptors in Shared RAM
*/
struct prueth_queue_info {
u16 buffer_offset;
u16 queue_desc_offset;
u16 buffer_desc_offset;
u16 buffer_desc_end;
};
/**
* struct prueth_packet_info - Info about a packet in buffer
* @shadow: this packet is stored in the collision queue
* @port: port packet is on
* @length: length of packet
* @broadcast: this packet is a broadcast packet
* @error: this packet has an error
* @lookup_success: src mac found in FDB
* @flood: packet is to be flooded
* @timestamp: Specifies if timestamp is appended to the packet
*/
struct prueth_packet_info {
bool shadow;
unsigned int port;
unsigned int length;
bool broadcast;
bool error;
bool lookup_success;
bool flood;
bool timestamp;
};
/* In switch mode there are 3 real ports i.e. 3 mac addrs.
* however Linux sees only the host side port. The other 2 ports
* are the switch ports.
* In emac mode there are 2 real ports i.e. 2 mac addrs.
* Linux sees both the ports.
*/
enum prueth_port {
PRUETH_PORT_HOST = 0, /* host side port */
PRUETH_PORT_MII0, /* physical port MII 0 */
PRUETH_PORT_MII1, /* physical port MII 1 */
PRUETH_PORT_INVALID, /* Invalid prueth port */
};
enum prueth_mac {
PRUETH_MAC0 = 0,
PRUETH_MAC1,
PRUETH_NUM_MACS,
PRUETH_MAC_INVALID,
};
/* In both switch & emac modes there are 3 port queues
* EMAC mode:
* RX packets for both MII0 & MII1 ports come on
* QUEUE_HOST.
* TX packets for MII0 go on QUEUE_MII0, TX packets
* for MII1 go on QUEUE_MII1.
* Switch mode:
* Host port RX packets come on QUEUE_HOST
* TX packets might have to go on MII0 or MII1 or both.
* MII0 TX queue is QUEUE_MII0 and MII1 TX queue is
* QUEUE_MII1.
*/
enum prueth_port_queue_id {
PRUETH_PORT_QUEUE_HOST = 0,
PRUETH_PORT_QUEUE_MII0,
PRUETH_PORT_QUEUE_MII1,
PRUETH_PORT_QUEUE_MAX,
};
/* Each port queue has 4 queues and 1 collision queue */
enum prueth_queue_id {
PRUETH_QUEUE1 = 0,
PRUETH_QUEUE2,
PRUETH_QUEUE3,
PRUETH_QUEUE4,
PRUETH_COLQUEUE, /* collision queue */
};
/**
* struct prueth_firmware - PRU Ethernet FW data
* @fw_name: firmware names of firmware to run on PRU
*/
struct prueth_firmware {
const char *fw_name[PRUSS_ETHTYPE_MAX];
};
/* PRUeth memory range identifiers */
enum prueth_mem {
PRUETH_MEM_DRAM0 = 0,
PRUETH_MEM_DRAM1,
PRUETH_MEM_SHARED_RAM,
PRUETH_MEM_OCMC,
PRUETH_MEM_MAX,
};
enum pruss_device {
PRUSS_AM57XX = 0,
PRUSS_AM43XX,
PRUSS_AM33XX,
PRUSS_K2G
};
/**
* struct prueth_private_data - PRU Ethernet private data
* @driver_data: PRU Ethernet device name
* @fw_pru: firmware names to be used for PRUSS ethernet usecases
* @support_switch: boolean to indicate if switch is enabled
*/
struct prueth_private_data {
enum pruss_device driver_data;
const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS];
bool support_switch;
};
struct prueth_emac_stats {
u64 tx_packets;
u64 tx_dropped;
u64 tx_bytes;
u64 rx_packets;
u64 rx_bytes;
u64 rx_length_errors;
u64 rx_over_errors;
};
/* data for each emac port */
struct prueth_emac {
struct prueth *prueth;
struct net_device *ndev;
struct napi_struct napi;
struct rproc *pru;
struct phy_device *phydev;
struct prueth_queue_desc __iomem *rx_queue_descs;
struct prueth_queue_desc __iomem *tx_queue_descs;
int link;
int speed;
int duplex;
int rx_irq;
enum prueth_port_queue_id tx_port_queue;
enum prueth_queue_id rx_queue_start;
enum prueth_queue_id rx_queue_end;
enum prueth_port port_id;
enum prueth_mem dram;
const char *phy_id;
u32 msg_enable;
u8 mac_addr[6];
unsigned char mc_filter_mask[ETH_ALEN]; /* for multicast filtering */
phy_interface_t phy_if;
/* spin lock used to protect
* during link configuration
*/
spinlock_t lock;
spinlock_t addr_lock; /* serialize access to VLAN/MC filter table */
struct hrtimer tx_hrtimer;
struct prueth_emac_stats stats;
int offload_fwd_mark;
};
struct prueth {
struct device *dev;
struct pruss *pruss;
struct rproc *pru0, *pru1;
struct pruss_mem_region mem[PRUETH_MEM_MAX];
struct gen_pool *sram_pool;
struct regmap *mii_rt;
struct icss_iep *iep;
const struct prueth_private_data *fw_data;
struct prueth_fw_offsets *fw_offsets;
struct device_node *eth_node[PRUETH_NUM_MACS];
struct prueth_emac *emac[PRUETH_NUM_MACS];
struct net_device *registered_netdevs[PRUETH_NUM_MACS];
struct net_device *hw_bridge_dev;
struct fdb_tbl *fdb_tbl;
struct notifier_block prueth_netdevice_nb;
struct notifier_block prueth_switchdev_nb;
struct notifier_block prueth_switchdev_bl_nb;
unsigned int eth_type;
size_t ocmc_ram_size;
u8 emac_configured;
u8 br_members;
};
extern const struct prueth_queue_desc queue_descs[][NUM_QUEUES];
void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
struct prueth_packet_info *pkt_info);
int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
struct prueth_packet_info *pkt_info,
const struct prueth_queue_info *rxqueue);
void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash);
void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash);
u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask);
#endif /* __NET_TI_PRUETH_H */
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2019-2021 Texas Instruments Incorporated - https://www.ti.com */
#ifndef __NET_TI_PRUSS_FDB_TBL_H
#define __NET_TI_PRUSS_FDB_TBL_H
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include "icssm_prueth.h"
/* 4 bytes */
struct fdb_index_tbl_entry {
/* Bucket Table index of first Bucket with this MAC address */
u16 bucket_idx;
u16 bucket_entries; /* Number of entries in this bucket */
};
/* 4 * 256 = 1024 = 0x200 bytes */
struct fdb_index_array {
struct fdb_index_tbl_entry index_tbl_entry[FDB_INDEX_TBL_MAX_ENTRIES];
};
/* 10 bytes */
struct fdb_mac_tbl_entry {
u8 mac[ETH_ALEN];
u16 age;
u8 port; /* 0 based: 0=port1, 1=port2 */
union {
struct {
u8 is_static:1;
u8 active:1;
};
u8 flags;
};
};
/* 10 * 256 = 2560 = 0xa00 bytes */
struct fdb_mac_tbl_array {
struct fdb_mac_tbl_entry mac_tbl_entry[FDB_MAC_TBL_MAX_ENTRIES];
};
/* 1 byte */
struct fdb_stp_config {
u8 state; /* per-port STP state (defined in FW header) */
};
/* 1 byte */
struct fdb_flood_config {
u8 host_flood_enable:1;
u8 port1_flood_enable:1;
u8 port2_flood_enable:1;
};
/* 2 byte */
struct fdb_arbitration {
u8 host_lock;
u8 pru_locks;
};
struct fdb_tbl {
/* fdb index table */
struct fdb_index_array __iomem *index_a;
/* fdb MAC table */
struct fdb_mac_tbl_array __iomem *mac_tbl_a;
/* port 1 stp config */
struct fdb_stp_config __iomem *port1_stp_cfg;
/* port 2 stp config */
struct fdb_stp_config __iomem *port2_stp_cfg;
/* per-port flood enable */
struct fdb_flood_config __iomem *flood_enable_flags;
/* fdb locking mechanism */
struct fdb_arbitration __iomem *locks;
/* total number of entries in hash table */
u16 total_entries;
};
#endif
@@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef PRUETH_PTP_H
#define PRUETH_PTP_H
#define RX_SYNC_TIMESTAMP_OFFSET_P1 0x8 /* 8 bytes */
#define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x14 /* 12 bytes */
#define DISABLE_PTP_FRAME_FORWARDING_CTRL_OFFSET 0x14 /* 1 byte */
#define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x20 /* 12 bytes */
#define RX_SYNC_TIMESTAMP_OFFSET_P2 0x2c /* 12 bytes */
#define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0x38 /* 12 bytes */
#define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0x44 /* 12 bytes */
#define TIMESYNC_DOMAIN_NUMBER_LIST 0x50 /* 2 bytes */
#define P1_SMA_LINE_DELAY_OFFSET 0x52 /* 4 bytes */
#define P2_SMA_LINE_DELAY_OFFSET 0x56 /* 4 bytes */
#define TIMESYNC_SECONDS_COUNT_OFFSET 0x5a /* 6 bytes */
#define TIMESYNC_TC_RCF_OFFSET 0x60 /* 4 bytes */
#define DUT_IS_MASTER_OFFSET 0x64 /* 1 byte */
#define MASTER_PORT_NUM_OFFSET 0x65 /* 1 byte */
#define SYNC_MASTER_MAC_OFFSET 0x66 /* 6 bytes */
#define TX_TS_NOTIFICATION_OFFSET_SYNC_P1 0x6c /* 1 byte */
#define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P1 0x6d /* 1 byte */
#define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P1 0x6e /* 1 byte */
#define TX_TS_NOTIFICATION_OFFSET_SYNC_P2 0x6f /* 1 byte */
#define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P2 0x70 /* 1 byte */
#define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P2 0x71 /* 1 byte */
#define TX_SYNC_TIMESTAMP_OFFSET_P1 0x72 /* 12 bytes */
#define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x7e /* 12 bytes */
#define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x8a /* 12 bytes */
#define TX_SYNC_TIMESTAMP_OFFSET_P2 0x96 /* 12 bytes */
#define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0xa2 /* 12 bytes */
#define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0xae /* 12 bytes */
#define TIMESYNC_CTRL_VAR_OFFSET 0xba /* 1 byte */
#define DISABLE_SWITCH_SYNC_RELAY_OFFSET 0xbb /* 1 byte */
#define MII_RX_CORRECTION_OFFSET 0xbc /* 2 bytes */
#define MII_TX_CORRECTION_OFFSET 0xbe /* 2 bytes */
#define TIMESYNC_CMP1_CMP_OFFSET 0xc0 /* 8 bytes */
#define TIMESYNC_SYNC0_CMP_OFFSET 0xc8 /* 8 bytes */
#define TIMESYNC_CMP1_PERIOD_OFFSET 0xd0 /* 4 bytes */
#define TIMESYNC_SYNC0_WIDTH_OFFSET 0xd4 /* 4 bytes */
#define SINGLE_STEP_IEP_OFFSET_P1 0xd8 /* 8 bytes */
#define SINGLE_STEP_SECONDS_OFFSET_P1 0xe0 /* 8 bytes */
#define SINGLE_STEP_IEP_OFFSET_P2 0xe8 /* 8 bytes */
#define SINGLE_STEP_SECONDS_OFFSET_P2 0xf0 /* 8 bytes */
#define LINK_LOCAL_FRAME_HAS_HSR_TAG 0xf8 /* 1 bytes */
#define PTP_PREV_TX_TIMESTAMP_P1 0xf9 /* 8 bytes */
#define PTP_PREV_TX_TIMESTAMP_P2 0x101 /* 8 bytes */
#define PTP_CLK_IDENTITY_OFFSET 0x109 /* 8 bytes */
#define PTP_SCRATCH_MEM 0x111 /* 16 byte */
#define PTP_IPV4_UDP_E2E_ENABLE 0x121 /* 1 byte */
enum {
PRUETH_PTP_SYNC,
PRUETH_PTP_DLY_REQ,
PRUETH_PTP_DLY_RESP,
PRUETH_PTP_TS_EVENTS,
};
#define PRUETH_PTP_TS_SIZE 12
#define PRUETH_PTP_TS_NOTIFY_SIZE 1
#define PRUETH_PTP_TS_NOTIFY_MASK 0xff
/* Bit definitions for TIMESYNC_CTRL */
#define TIMESYNC_CTRL_BG_ENABLE BIT(0)
#define TIMESYNC_CTRL_FORCED_2STEP BIT(1)
static inline u32 icssm_prueth_tx_ts_offs_get(u8 port, u8 event)
{
return TX_SYNC_TIMESTAMP_OFFSET_P1 + port *
PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_SIZE +
event * PRUETH_PTP_TS_SIZE;
}
static inline u32 icssm_prueth_tx_ts_notify_offs_get(u8 port, u8 event)
{
return TX_TS_NOTIFICATION_OFFSET_SYNC_P1 +
PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_NOTIFY_SIZE * port +
event * PRUETH_PTP_TS_NOTIFY_SIZE;
}
#endif /* PRUETH_PTP_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef __NET_TI_PRUETH_SWITCH_H
#define __NET_TI_PRUETH_SWITCH_H
#include <net/switchdev.h>
#include "icssm_prueth.h"
#include "icssm_prueth_fdb_tbl.h"
#include "icssm_switchdev.h"
void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
enum prueth_port port, u8 state);
u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth,
enum prueth_port port);
extern const struct prueth_queue_info sw_queue_infos[][4];
void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
void icssm_prueth_sw_free_fdb_table(struct prueth *prueth);
int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac);
void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
struct switchdev_notifier_fdb_info *fdb);
void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
struct switchdev_notifier_fdb_info *fdb);
int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac);
int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac);
void icssm_prueth_sw_hostconfig(struct prueth *prueth);
int icssm_prueth_sw_emac_config(struct prueth_emac *emac);
int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev);
int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
struct net_device *ndev);
#endif /* __NET_TI_PRUETH_SWITCH_H */
@@ -0,0 +1,360 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef __ICSS_SWITCH_H
#define __ICSS_SWITCH_H
/* Basic Switch Parameters
* Used to auto compute offset addresses on L3 OCMC RAM. Do not modify these
* without changing firmware accordingly
*/
#define SWITCH_BUFFER_SIZE (64 * 1024) /* L3 buffer */
#define ICSS_BLOCK_SIZE 32 /* data bytes per BD */
#define BD_SIZE 4 /* byte buffer descriptor */
#define NUM_QUEUES 4 /* Queues on Port 0/1/2 */
#define PORT_LINK_MASK 0x1
#define PORT_IS_HD_MASK 0x2
/* Physical Port queue size (number of BDs). Same for both ports */
#define QUEUE_1_SIZE 97 /* Network Management high */
#define QUEUE_2_SIZE 97 /* Network Management low */
#define QUEUE_3_SIZE 97 /* Protocol specific */
#define QUEUE_4_SIZE 97 /* NRT (IP,ARP, ICMP) */
/* Host queue size (number of BDs). Each BD points to data buffer of 32 bytes.
* HOST PORT QUEUES can buffer up to 4 full sized frames per queue
*/
#define HOST_QUEUE_1_SIZE 194 /* Protocol and VLAN priority 7 & 6 */
#define HOST_QUEUE_2_SIZE 194 /* Protocol mid */
#define HOST_QUEUE_3_SIZE 194 /* Protocol low */
#define HOST_QUEUE_4_SIZE 194 /* NRT (IP, ARP, ICMP) */
#define COL_QUEUE_SIZE 0
/* NRT Buffer descriptor definition
* Each buffer descriptor points to a max 32 byte block and has 32 bit in size
* to have atomic operation.
* PRU can address bytewise into memory.
* Definition of 32 bit descriptor is as follows
*
* Bits Name Meaning
* =============================================================================
* 0..7 Index points to index in buffer queue, max 256 x 32
* byte blocks can be addressed
* 6 LookupSuccess For switch, FDB lookup was successful (source
* MAC address found in FDB).
* For RED, NodeTable lookup was successful.
* 7 Flood Packet should be flooded (destination MAC
* address found in FDB). For switch only.
* 8..12 Block_length number of valid bytes in this specific block.
* Will be <=32 bytes on last block of packet
* 13 More "More" bit indicating that there are more blocks
* 14 Shadow indicates that "index" is pointing into shadow
* buffer
* 15 TimeStamp indicates that this packet has time stamp in
* separate buffer - only needed if PTP runs on
* host
* 16..17 Port different meaning for ingress and egress,
* Ingress: Port = 0 indicates phy port 1 and
* Port = 1 indicates phy port 2.
* Egress: 0 sends on phy port 1 and 1 sends on
* phy port 2. Port = 2 goes over MAC table
* look-up
* 18..28 Length 11 bit of total packet length which is put into
* first BD only so that host access only one BD
* 29 VlanTag indicates that packet has Length/Type field of
* 0x08100 with VLAN tag in following byte
* 30 Broadcast indicates that packet goes out on both physical
* ports, there will be two bd but only one buffer
* 31 Error indicates there was an error in the packet
*/
#define PRUETH_BD_START_FLAG_MASK BIT(0)
#define PRUETH_BD_START_FLAG_SHIFT 0
#define PRUETH_BD_HSR_FRAME_MASK BIT(4)
#define PRUETH_BD_HSR_FRAME_SHIFT 4
#define PRUETH_BD_SUP_HSR_FRAME_MASK BIT(5)
#define PRUETH_BD_SUP_HSR_FRAME_SHIFT 5
#define PRUETH_BD_LOOKUP_SUCCESS_MASK BIT(6)
#define PRUETH_BD_LOOKUP_SUCCESS_SHIFT 6
#define PRUETH_BD_SW_FLOOD_MASK BIT(7)
#define PRUETH_BD_SW_FLOOD_SHIFT 7
#define PRUETH_BD_SHADOW_MASK BIT(14)
#define PRUETH_BD_SHADOW_SHIFT 14
#define PRUETH_BD_TIMESTAMP_MASK BIT(15)
#define PRUETH_BD_TIMESTAMP_SHIFT 15
#define PRUETH_BD_PORT_MASK GENMASK(17, 16)
#define PRUETH_BD_PORT_SHIFT 16
#define PRUETH_BD_LENGTH_MASK GENMASK(28, 18)
#define PRUETH_BD_LENGTH_SHIFT 18
#define PRUETH_BD_BROADCAST_MASK BIT(30)
#define PRUETH_BD_BROADCAST_SHIFT 30
#define PRUETH_BD_ERROR_MASK BIT(31)
#define PRUETH_BD_ERROR_SHIFT 31
/* The following offsets indicate which sections of the memory are used
* for EMAC internal tasks
*/
#define DRAM_START_OFFSET 0x1E98
#define SRAM_START_OFFSET 0x400
/* General Purpose Statistics
* These are present on both PRU0 and PRU1 DRAM
*/
/* base statistics offset */
#define STATISTICS_OFFSET 0x1F00
#define STAT_SIZE 0x98
/* The following offsets indicate which sections of the memory are used
* for switch internal tasks
*/
#define SWITCH_SPECIFIC_DRAM0_START_SIZE 0x100
#define SWITCH_SPECIFIC_DRAM0_START_OFFSET 0x1F00
#define SWITCH_SPECIFIC_DRAM1_START_SIZE 0x300
#define SWITCH_SPECIFIC_DRAM1_START_OFFSET 0x1D00
/* Offset for storing
* 1. Storm Prevention Params
* 2. PHY Speed Offset
* 3. Port Status Offset
* These are present on both PRU0 and PRU1
*/
/* 4 bytes */
#define STORM_PREVENTION_OFFSET_BC (STATISTICS_OFFSET + STAT_SIZE)
/* 4 bytes */
#define PHY_SPEED_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 4)
/* 1 byte */
#define PORT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 8)
/* 1 byte */
#define COLLISION_COUNTER (STATISTICS_OFFSET + STAT_SIZE + 9)
/* 4 bytes */
#define RX_PKT_SIZE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 10)
/* 4 bytes */
#define PORT_CONTROL_ADDR (STATISTICS_OFFSET + STAT_SIZE + 14)
/* 6 bytes */
#define PORT_MAC_ADDR (STATISTICS_OFFSET + STAT_SIZE + 18)
/* 1 byte */
#define RX_INT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 24)
/* 4 bytes */
#define STORM_PREVENTION_OFFSET_MC (STATISTICS_OFFSET + STAT_SIZE + 25)
/* 4 bytes */
#define STORM_PREVENTION_OFFSET_UC (STATISTICS_OFFSET + STAT_SIZE + 29)
/* 4 bytes ? */
#define STP_INVALID_STATE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 33)
/* DRAM1 Offsets for Switch */
/* 4 queue descriptors for port 0 (host receive) */
#define P0_QUEUE_DESC_OFFSET 0x1E7C
#define P1_QUEUE_DESC_OFFSET 0x1E9C
#define P2_QUEUE_DESC_OFFSET 0x1EBC
/* collision descriptor of port 0 */
#define P0_COL_QUEUE_DESC_OFFSET 0x1E64
#define P1_COL_QUEUE_DESC_OFFSET 0x1E6C
#define P2_COL_QUEUE_DESC_OFFSET 0x1E74
/* Collision Status Register
* P0: bit 0 is pending flag, bit 1..2 indicates which queue,
* P1: bit 8 is pending flag, 9..10 is queue number
* P2: bit 16 is pending flag, 17..18 is queue number, remaining bits are 0.
*/
#define COLLISION_STATUS_ADDR 0x1E60
#define INTERFACE_MAC_ADDR 0x1E58
#define P2_MAC_ADDR 0x1E50
#define P1_MAC_ADDR 0x1E48
#define QUEUE_SIZE_ADDR 0x1E30
#define QUEUE_OFFSET_ADDR 0x1E18
#define QUEUE_DESCRIPTOR_OFFSET_ADDR 0x1E00
#define COL_RX_CONTEXT_P2_OFFSET_ADDR (COL_RX_CONTEXT_P1_OFFSET_ADDR + 12)
#define COL_RX_CONTEXT_P1_OFFSET_ADDR (COL_RX_CONTEXT_P0_OFFSET_ADDR + 12)
#define COL_RX_CONTEXT_P0_OFFSET_ADDR (P2_Q4_RX_CONTEXT_OFFSET + 8)
/* Port 2 Rx Context */
#define P2_Q4_RX_CONTEXT_OFFSET (P2_Q3_RX_CONTEXT_OFFSET + 8)
#define P2_Q3_RX_CONTEXT_OFFSET (P2_Q2_RX_CONTEXT_OFFSET + 8)
#define P2_Q2_RX_CONTEXT_OFFSET (P2_Q1_RX_CONTEXT_OFFSET + 8)
#define P2_Q1_RX_CONTEXT_OFFSET RX_CONTEXT_P2_Q1_OFFSET_ADDR
#define RX_CONTEXT_P2_Q1_OFFSET_ADDR (P1_Q4_RX_CONTEXT_OFFSET + 8)
/* Port 1 Rx Context */
#define P1_Q4_RX_CONTEXT_OFFSET (P1_Q3_RX_CONTEXT_OFFSET + 8)
#define P1_Q3_RX_CONTEXT_OFFSET (P1_Q2_RX_CONTEXT_OFFSET + 8)
#define P1_Q2_RX_CONTEXT_OFFSET (P1_Q1_RX_CONTEXT_OFFSET + 8)
#define P1_Q1_RX_CONTEXT_OFFSET (RX_CONTEXT_P1_Q1_OFFSET_ADDR)
#define RX_CONTEXT_P1_Q1_OFFSET_ADDR (P0_Q4_RX_CONTEXT_OFFSET + 8)
/* Host Port Rx Context */
#define P0_Q4_RX_CONTEXT_OFFSET (P0_Q3_RX_CONTEXT_OFFSET + 8)
#define P0_Q3_RX_CONTEXT_OFFSET (P0_Q2_RX_CONTEXT_OFFSET + 8)
#define P0_Q2_RX_CONTEXT_OFFSET (P0_Q1_RX_CONTEXT_OFFSET + 8)
#define P0_Q1_RX_CONTEXT_OFFSET RX_CONTEXT_P0_Q1_OFFSET_ADDR
#define RX_CONTEXT_P0_Q1_OFFSET_ADDR (COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR + 8)
/* Port 2 Tx Collision Context */
#define COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR (COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR + 8)
/* Port 1 Tx Collision Context */
#define COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR (P2_Q4_TX_CONTEXT_OFFSET + 8)
/* Port 2 */
#define P2_Q4_TX_CONTEXT_OFFSET (P2_Q3_TX_CONTEXT_OFFSET + 8)
#define P2_Q3_TX_CONTEXT_OFFSET (P2_Q2_TX_CONTEXT_OFFSET + 8)
#define P2_Q2_TX_CONTEXT_OFFSET (P2_Q1_TX_CONTEXT_OFFSET + 8)
#define P2_Q1_TX_CONTEXT_OFFSET TX_CONTEXT_P2_Q1_OFFSET_ADDR
#define TX_CONTEXT_P2_Q1_OFFSET_ADDR (P1_Q4_TX_CONTEXT_OFFSET + 8)
/* Port 1 */
#define P1_Q4_TX_CONTEXT_OFFSET (P1_Q3_TX_CONTEXT_OFFSET + 8)
#define P1_Q3_TX_CONTEXT_OFFSET (P1_Q2_TX_CONTEXT_OFFSET + 8)
#define P1_Q2_TX_CONTEXT_OFFSET (P1_Q1_TX_CONTEXT_OFFSET + 8)
#define P1_Q1_TX_CONTEXT_OFFSET TX_CONTEXT_P1_Q1_OFFSET_ADDR
#define TX_CONTEXT_P1_Q1_OFFSET_ADDR SWITCH_SPECIFIC_DRAM1_START_OFFSET
/* DRAM Offsets for EMAC
* Present on Both DRAM0 and DRAM1
*/
/* 4 queue descriptors for port tx = 32 bytes */
#define TX_CONTEXT_Q1_OFFSET_ADDR (PORT_QUEUE_DESC_OFFSET + 32)
#define PORT_QUEUE_DESC_OFFSET (ICSS_EMAC_TTS_CYC_TX_SOF + 8)
/* EMAC Time Triggered Send Offsets */
#define ICSS_EMAC_TTS_CYC_TX_SOF (ICSS_EMAC_TTS_PREV_TX_SOF + 8)
#define ICSS_EMAC_TTS_PREV_TX_SOF \
(ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET + 4)
#define ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET (ICSS_EMAC_TTS_STATUS_OFFSET \
+ 4)
#define ICSS_EMAC_TTS_STATUS_OFFSET (ICSS_EMAC_TTS_CFG_TIME_OFFSET + 4)
#define ICSS_EMAC_TTS_CFG_TIME_OFFSET (ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET + 4)
#define ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET \
(ICSS_EMAC_TTS_CYCLE_START_OFFSET + 8)
#define ICSS_EMAC_TTS_CYCLE_START_OFFSET ICSS_EMAC_TTS_BASE_OFFSET
#define ICSS_EMAC_TTS_BASE_OFFSET DRAM_START_OFFSET
/* Shared RAM offsets for EMAC */
/* Queue Descriptors */
/* 4 queue descriptors for port 0 (host receive). 32 bytes */
#define HOST_QUEUE_DESC_OFFSET (HOST_QUEUE_SIZE_ADDR + 16)
/* table offset for queue size:
* 3 ports * 4 Queues * 1 byte offset = 12 bytes
*/
#define HOST_QUEUE_SIZE_ADDR (HOST_QUEUE_OFFSET_ADDR + 8)
/* table offset for queue:
* 4 Queues * 2 byte offset = 8 bytes
*/
#define HOST_QUEUE_OFFSET_ADDR (HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR + 8)
/* table offset for Host queue descriptors:
* 1 ports * 4 Queues * 2 byte offset = 8 bytes
*/
#define HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR (HOST_Q4_RX_CONTEXT_OFFSET + 8)
/* Host Port Rx Context */
#define HOST_Q4_RX_CONTEXT_OFFSET (HOST_Q3_RX_CONTEXT_OFFSET + 8)
#define HOST_Q3_RX_CONTEXT_OFFSET (HOST_Q2_RX_CONTEXT_OFFSET + 8)
#define HOST_Q2_RX_CONTEXT_OFFSET (HOST_Q1_RX_CONTEXT_OFFSET + 8)
#define HOST_Q1_RX_CONTEXT_OFFSET (EMAC_PROMISCUOUS_MODE_OFFSET + 4)
/* Promiscuous mode control */
#define EMAC_P1_PROMISCUOUS_BIT BIT(0)
#define EMAC_P2_PROMISCUOUS_BIT BIT(1)
#define EMAC_PROMISCUOUS_MODE_OFFSET (EMAC_RESERVED + 4)
#define EMAC_RESERVED EOF_48K_BUFFER_BD
/* allow for max 48k buffer which spans the descriptors up to 0x1800 6kB */
#define EOF_48K_BUFFER_BD (P0_BUFFER_DESC_OFFSET + HOST_BD_SIZE + \
PORT_BD_SIZE)
#define HOST_BD_SIZE ((HOST_QUEUE_1_SIZE + \
HOST_QUEUE_2_SIZE + HOST_QUEUE_3_SIZE + \
HOST_QUEUE_4_SIZE) * BD_SIZE)
#define PORT_BD_SIZE ((QUEUE_1_SIZE + QUEUE_2_SIZE + \
QUEUE_3_SIZE + QUEUE_4_SIZE) * 2 * BD_SIZE)
#define END_OF_BD_POOL (P2_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE)
#define P2_Q4_BD_OFFSET (P2_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE)
#define P2_Q3_BD_OFFSET (P2_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE)
#define P2_Q2_BD_OFFSET (P2_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE)
#define P2_Q1_BD_OFFSET (P1_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE)
#define P1_Q4_BD_OFFSET (P1_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE)
#define P1_Q3_BD_OFFSET (P1_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE)
#define P1_Q2_BD_OFFSET (P1_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE)
#define P1_Q1_BD_OFFSET (P0_Q4_BD_OFFSET + HOST_QUEUE_4_SIZE * BD_SIZE)
#define P0_Q4_BD_OFFSET (P0_Q3_BD_OFFSET + HOST_QUEUE_3_SIZE * BD_SIZE)
#define P0_Q3_BD_OFFSET (P0_Q2_BD_OFFSET + HOST_QUEUE_2_SIZE * BD_SIZE)
#define P0_Q2_BD_OFFSET (P0_Q1_BD_OFFSET + HOST_QUEUE_1_SIZE * BD_SIZE)
#define P0_Q1_BD_OFFSET P0_BUFFER_DESC_OFFSET
#define P0_BUFFER_DESC_OFFSET SRAM_START_OFFSET
/* Memory Usage of L3 OCMC RAM */
/* L3 64KB Memory - mainly buffer Pool */
#define END_OF_BUFFER_POOL (P2_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \
ICSS_BLOCK_SIZE)
#define P2_Q4_BUFFER_OFFSET (P2_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \
ICSS_BLOCK_SIZE)
#define P2_Q3_BUFFER_OFFSET (P2_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \
ICSS_BLOCK_SIZE)
#define P2_Q2_BUFFER_OFFSET (P2_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \
ICSS_BLOCK_SIZE)
#define P2_Q1_BUFFER_OFFSET (P1_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \
ICSS_BLOCK_SIZE)
#define P1_Q4_BUFFER_OFFSET (P1_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \
ICSS_BLOCK_SIZE)
#define P1_Q3_BUFFER_OFFSET (P1_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \
ICSS_BLOCK_SIZE)
#define P1_Q2_BUFFER_OFFSET (P1_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \
ICSS_BLOCK_SIZE)
#define P1_Q1_BUFFER_OFFSET (P0_Q4_BUFFER_OFFSET + HOST_QUEUE_4_SIZE * \
ICSS_BLOCK_SIZE)
#define P0_Q4_BUFFER_OFFSET (P0_Q3_BUFFER_OFFSET + HOST_QUEUE_3_SIZE * \
ICSS_BLOCK_SIZE)
#define P0_Q3_BUFFER_OFFSET (P0_Q2_BUFFER_OFFSET + HOST_QUEUE_2_SIZE * \
ICSS_BLOCK_SIZE)
#define P0_Q2_BUFFER_OFFSET (P0_Q1_BUFFER_OFFSET + HOST_QUEUE_1_SIZE * \
ICSS_BLOCK_SIZE)
#define P0_COL_BUFFER_OFFSET 0xEE00
#define P0_Q1_BUFFER_OFFSET 0x0000
#define V2_1_FDB_TBL_LOC PRUETH_MEM_SHARED_RAM
#define V2_1_FDB_TBL_OFFSET 0x2000
#define FDB_INDEX_TBL_MAX_ENTRIES 256
#define FDB_MAC_TBL_MAX_ENTRIES 256
#define FDB_INDEX_TBL_OFFSET V2_1_FDB_TBL_OFFSET
#define FDB_INDEX_TBL_SIZE (FDB_INDEX_TBL_MAX_ENTRIES * \
sizeof(struct fdb_index_tbl_entry))
#define FDB_MAC_TBL_OFFSET (FDB_INDEX_TBL_OFFSET + FDB_INDEX_TBL_SIZE)
#define FDB_MAC_TBL_SIZE (FDB_MAC_TBL_MAX_ENTRIES * \
sizeof(struct fdb_mac_tbl_entry))
#define FDB_PORT1_STP_CFG_OFFSET (FDB_MAC_TBL_OFFSET + FDB_MAC_TBL_SIZE)
#define FDB_PORT_STP_CFG_SIZE sizeof(struct fdb_stp_config)
#define FDB_PORT2_STP_CFG_OFFSET (FDB_PORT1_STP_CFG_OFFSET + \
FDB_PORT_STP_CFG_SIZE)
#define FDB_FLOOD_ENABLE_FLAGS_OFFSET (FDB_PORT2_STP_CFG_OFFSET + \
FDB_PORT_STP_CFG_SIZE)
#define FDB_FLOOD_ENABLE_FLAGS_SIZE sizeof(struct fdb_flood_config)
#define FDB_LOCKS_OFFSET (FDB_FLOOD_ENABLE_FLAGS_OFFSET + \
FDB_FLOOD_ENABLE_FLAGS_SIZE)
#endif /* __ICSS_SWITCH_H */
@@ -0,0 +1,333 @@
// SPDX-License-Identifier: GPL-2.0
/* Texas Instruments ICSSM Ethernet Driver
*
* Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
*
*/
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/remoteproc.h>
#include <net/switchdev.h>
#include "icssm_prueth.h"
#include "icssm_prueth_switch.h"
#include "icssm_prueth_fdb_tbl.h"
/* switchev event work */
struct icssm_sw_event_work {
netdevice_tracker ndev_tracker;
struct work_struct work;
struct switchdev_notifier_fdb_info fdb_info;
struct prueth_emac *emac;
unsigned long event;
};
void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
enum prueth_port port, u8 state)
{
struct fdb_tbl *t = prueth->fdb_tbl;
writeb(state, port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
(void __iomem *)&t->port1_stp_cfg->state);
}
u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth, enum prueth_port port)
{
struct fdb_tbl *t = prueth->fdb_tbl;
u8 state;
state = readb(port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
(void __iomem *)&t->port1_stp_cfg->state);
return state;
}
static int icssm_prueth_sw_attr_set(struct net_device *ndev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
struct prueth_emac *emac = netdev_priv(ndev);
struct prueth *prueth = emac->prueth;
int err = 0;
u8 o_state;
/* Interface is not up */
if (!prueth->fdb_tbl)
return 0;
switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
o_state = icssm_prueth_sw_get_stp_state(prueth, emac->port_id);
icssm_prueth_sw_set_stp_state(prueth, emac->port_id,
attr->u.stp_state);
if (o_state != attr->u.stp_state)
icssm_prueth_sw_purge_fdb(emac);
dev_dbg(prueth->dev, "attr set: stp state:%u port:%u\n",
attr->u.stp_state, emac->port_id);
break;
default:
err = -EOPNOTSUPP;
break;
}
return err;
}
static void icssm_prueth_sw_fdb_offload(struct net_device *ndev,
struct switchdev_notifier_fdb_info *rcv)
{
struct switchdev_notifier_fdb_info info;
info.addr = rcv->addr;
info.vid = rcv->vid;
call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, ndev, &info.info,
NULL);
}
/**
* icssm_sw_event_work - insert/delete fdb entry
*
* @work: work structure
*
*/
static void icssm_sw_event_work(struct work_struct *work)
{
struct icssm_sw_event_work *switchdev_work =
container_of(work, struct icssm_sw_event_work, work);
struct prueth_emac *emac = switchdev_work->emac;
struct switchdev_notifier_fdb_info *fdb;
struct prueth *prueth = emac->prueth;
int port = emac->port_id;
rtnl_lock();
/* Interface is not up */
if (!emac->prueth->fdb_tbl)
goto free;
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
fdb = &switchdev_work->fdb_info;
dev_dbg(prueth->dev,
"prueth fdb add: MACID = %pM vid = %u flags = %u -- port %d\n",
fdb->addr, fdb->vid, fdb->added_by_user, port);
if (!fdb->added_by_user)
break;
if (fdb->is_local)
break;
icssm_prueth_sw_fdb_add(emac, fdb);
icssm_prueth_sw_fdb_offload(emac->ndev, fdb);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
fdb = &switchdev_work->fdb_info;
dev_dbg(prueth->dev,
"prueth fdb del: MACID = %pM vid = %u flags = %u -- port %d\n",
fdb->addr, fdb->vid, fdb->added_by_user, port);
if (fdb->is_local)
break;
icssm_prueth_sw_fdb_del(emac, fdb);
break;
default:
break;
}
free:
rtnl_unlock();
netdev_put(emac->ndev, &switchdev_work->ndev_tracker);
kfree(switchdev_work->fdb_info.addr);
kfree(switchdev_work);
}
/* called under rcu_read_lock() */
static int icssm_prueth_sw_switchdev_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
struct switchdev_notifier_fdb_info *fdb_info = ptr;
struct prueth_emac *emac = netdev_priv(ndev);
struct icssm_sw_event_work *switchdev_work;
int err;
if (!icssm_prueth_sw_port_dev_check(ndev))
return NOTIFY_DONE;
if (event == SWITCHDEV_PORT_ATTR_SET) {
err = switchdev_handle_port_attr_set
(ndev, ptr, icssm_prueth_sw_port_dev_check,
icssm_prueth_sw_attr_set);
return notifier_from_errno(err);
}
switchdev_work = kzalloc_obj(*switchdev_work, GFP_ATOMIC);
if (WARN_ON(!switchdev_work))
return NOTIFY_BAD;
INIT_WORK(&switchdev_work->work, icssm_sw_event_work);
switchdev_work->emac = emac;
switchdev_work->event = event;
switch (event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
memcpy(&switchdev_work->fdb_info, ptr,
sizeof(switchdev_work->fdb_info));
switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
if (!switchdev_work->fdb_info.addr)
goto err_addr_alloc;
ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
fdb_info->addr);
netdev_hold(ndev, &switchdev_work->ndev_tracker, GFP_ATOMIC);
break;
default:
kfree(switchdev_work);
return NOTIFY_DONE;
}
queue_work(system_long_wq, &switchdev_work->work);
return NOTIFY_DONE;
err_addr_alloc:
kfree(switchdev_work);
return NOTIFY_BAD;
}
static int icssm_prueth_switchdev_obj_add(struct net_device *ndev,
const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
struct prueth_emac *emac = netdev_priv(ndev);
struct prueth *prueth = emac->prueth;
int ret = 0;
u8 hash;
switch (obj->id) {
case SWITCHDEV_OBJ_ID_HOST_MDB:
dev_dbg(prueth->dev, "MDB add: %s: vid %u:%pM port: %x\n",
ndev->name, mdb->vid, mdb->addr, emac->port_id);
hash = icssm_emac_get_mc_hash(mdb->addr, emac->mc_filter_mask);
icssm_emac_mc_filter_bin_allow(emac, hash);
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static int icssm_prueth_switchdev_obj_del(struct net_device *ndev,
const void *ctx,
const struct switchdev_obj *obj)
{
struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
struct prueth_emac *emac = netdev_priv(ndev);
struct prueth *prueth = emac->prueth;
struct netdev_hw_addr *ha;
u8 hash, tmp_hash;
int ret = 0;
u8 *mask;
switch (obj->id) {
case SWITCHDEV_OBJ_ID_HOST_MDB:
dev_dbg(prueth->dev, "MDB del: %s: vid %u:%pM port: %x\n",
ndev->name, mdb->vid, mdb->addr, emac->port_id);
if (prueth->hw_bridge_dev) {
mask = emac->mc_filter_mask;
hash = icssm_emac_get_mc_hash(mdb->addr, mask);
netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
tmp_hash = icssm_emac_get_mc_hash(ha->addr,
mask);
/* Another MC address is in the bin.
* Don't disable.
*/
if (tmp_hash == hash)
return 0;
}
icssm_emac_mc_filter_bin_disallow(emac, hash);
}
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
/* switchdev notifiers */
static int icssm_prueth_sw_blocking_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
int err;
switch (event) {
case SWITCHDEV_PORT_OBJ_ADD:
err = switchdev_handle_port_obj_add
(ndev, ptr, icssm_prueth_sw_port_dev_check,
icssm_prueth_switchdev_obj_add);
return notifier_from_errno(err);
case SWITCHDEV_PORT_OBJ_DEL:
err = switchdev_handle_port_obj_del
(ndev, ptr, icssm_prueth_sw_port_dev_check,
icssm_prueth_switchdev_obj_del);
return notifier_from_errno(err);
case SWITCHDEV_PORT_ATTR_SET:
err = switchdev_handle_port_attr_set
(ndev, ptr, icssm_prueth_sw_port_dev_check,
icssm_prueth_sw_attr_set);
return notifier_from_errno(err);
default:
break;
}
return NOTIFY_DONE;
}
int icssm_prueth_sw_register_notifiers(struct prueth *prueth)
{
int ret = 0;
prueth->prueth_switchdev_nb.notifier_call =
&icssm_prueth_sw_switchdev_event;
ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb);
if (ret) {
dev_err(prueth->dev,
"register switchdev notifier failed ret:%d\n", ret);
return ret;
}
prueth->prueth_switchdev_bl_nb.notifier_call =
&icssm_prueth_sw_blocking_event;
ret = register_switchdev_blocking_notifier
(&prueth->prueth_switchdev_bl_nb);
if (ret) {
dev_err(prueth->dev,
"register switchdev blocking notifier failed ret:%d\n",
ret);
unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
}
return ret;
}
void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth)
{
unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
}
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef __NET_TI_ICSSM_SWITCHDEV_H
#define __NET_TI_ICSSM_SWITCHDEV_H
#include "icssm_prueth.h"
int icssm_prueth_sw_register_notifiers(struct prueth *prueth);
void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth);
bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev);
#endif /* __NET_TI_ICSSM_SWITCHDEV_H */
@@ -0,0 +1,120 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com
*
* This file contains VLAN/Multicast filtering feature memory map
*
*/
#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
#define ICSS_VLAN_MULTICAST_FILTER_MM_H
/* VLAN/Multicast filter defines & offsets,
* present on both PRU0 and PRU1 DRAM
*/
/* Feature enable/disable values for multicast filtering */
#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED 0x00
#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED 0x01
/* Feature enable/disable values for VLAN filtering */
#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED 0x00
#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED 0x01
/* Add/remove multicast mac id for filtering bin */
#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED 0x01
#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED 0x00
/* Default HASH value for the multicast filtering Mask */
#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL 0xFF
/* Size requirements for Multicast filtering feature */
#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES 256
#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES 6
#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES 1
#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES 1
#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES 4
/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES 512
#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES 1
#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES 4
/* Mask override set status */
#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET 1
/* Mask override not set status */
#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET 0
/* 6 bytes HASH Mask for the MAC */
#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET 0xF4
/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET \
(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET + \
ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS \
(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET + \
ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
/* Multicast drop statistics */
#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET \
(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
/* Multicast table */
#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE \
(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
/* Multicast filter defines & offsets for LRE
*/
#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT 0xE0
/* one byte field :
* 0 -> multicast filtering disabled
* 1 -> multicast filtering enabled
*/
#define ICSS_LRE_FW_MULTICAST_FILTER_MASK 0xE4
#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE 0x100
/* VLAN table Offsets */
#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR 0x200
#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET 0xEF
#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET \
(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET + \
ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
/* VLAN filter Control Bit maps */
/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
* 1: VLAN filter enabled
*/
#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT 0
/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
* 1: untagged host rcv not allowed
*/
#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT 1
/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
* 1: priotag host rcv not allowed
*/
#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT 2
/* one bit field, bit 1: | 0 : skip sv vlan flow
* :1 : take sv vlan flow (not applicable for dual emac )
*/
#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT 3
/* VLAN IDs */
#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID 0
#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN 0x0000
#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX 0x0FFF
/* VLAN Filtering Commands */
#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD 0x00
#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD 0x01
/* Switch defines for VLAN/MC filtering */
/* SRAM
* VLAN filter defines & offsets
*/
#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE 0x1FE
/* one bit field | 0 : VLAN filter disabled
* | 1 : VLAN filter enabled
*/
#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR 0x200
#endif /* ICSS_MULTICAST_FILTER_MM_H */