blob: df72a61796ad5f41bca04cf765218b06a0094fe0 [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2025-2026 NXP
*/
#include <linux/dsa/tag_netc.h>
#include "tag.h"
#define NETC_NAME "nxp_netc"
/* Forward NXP switch tag */
#define NETC_TAG_FORWARD 0
/* To_Port NXP switch tag */
#define NETC_TAG_TO_PORT 1
/* SubType0: No request to perform timestamping */
#define NETC_TAG_TP_SUBTYPE0 0
/* To_Host NXP switch tag */
#define NETC_TAG_TO_HOST 2
/* SubType0: frames redirected or copied to CPU port */
#define NETC_TAG_TH_SUBTYPE0 0
/* SubType1: frames redirected or copied to CPU port with timestamp */
#define NETC_TAG_TH_SUBTYPE1 1
/* SubType2: Transmit timestamp response (two-step timestamping) */
#define NETC_TAG_TH_SUBTYPE2 2
/* NETC switch tag lengths */
#define NETC_TAG_FORWARD_LEN 6
#define NETC_TAG_TP_SUBTYPE0_LEN 6
#define NETC_TAG_TH_SUBTYPE0_LEN 6
#define NETC_TAG_TH_SUBTYPE1_LEN 14
#define NETC_TAG_TH_SUBTYPE2_LEN 14
#define NETC_TAG_CMN_LEN 5
#define NETC_TAG_SUBTYPE GENMASK(3, 0)
#define NETC_TAG_TYPE GENMASK(7, 4)
#define NETC_TAG_QV BIT(0)
#define NETC_TAG_IPV GENMASK(4, 2)
#define NETC_TAG_SWITCH GENMASK(2, 0)
#define NETC_TAG_PORT GENMASK(7, 3)
struct netc_tag_cmn {
__be16 tpid;
u8 type;
u8 qos;
u8 switch_port;
} __packed;
static void netc_fill_common_tag(struct netc_tag_cmn *tag, u8 type,
u8 subtype, u8 sw_id, u8 port, u8 ipv)
{
tag->tpid = htons(ETH_P_NXP_NETC);
tag->type = FIELD_PREP(NETC_TAG_TYPE, type) |
FIELD_PREP(NETC_TAG_SUBTYPE, subtype);
tag->qos = NETC_TAG_QV | FIELD_PREP(NETC_TAG_IPV, ipv);
tag->switch_port = FIELD_PREP(NETC_TAG_SWITCH, sw_id) |
FIELD_PREP(NETC_TAG_PORT, port);
}
static void *netc_fill_common_tp_tag(struct sk_buff *skb,
struct net_device *ndev,
u8 subtype, int tag_len)
{
struct dsa_port *dp = dsa_user_to_port(ndev);
u16 queue = skb_get_queue_mapping(skb);
s8 ipv = netdev_txq_to_tc(ndev, queue);
void *tag;
if (unlikely(ipv < 0))
ipv = 0;
skb_push(skb, tag_len);
dsa_alloc_etype_header(skb, tag_len);
tag = dsa_etype_header_pos_tx(skb);
memset(tag + NETC_TAG_CMN_LEN, 0, tag_len - NETC_TAG_CMN_LEN);
/* As 'dsa,member' is a required property for NETC switch, the member
* is used to specify the switch ID (thus the hardware switch ID and
* the software switch ID are consistent), its range is 1 ~ 7. The
* NETC switch driver will check this value, and if it is invalid,
* the switch driver will fail the probe.
* In addition, according to the nxp,netc-switch.yaml doc, the port
* index will not be greater than 0xf.
*/
netc_fill_common_tag(tag, NETC_TAG_TO_PORT, subtype,
dp->ds->index, dp->index, ipv);
return tag;
}
static void netc_fill_tp_tag_subtype0(struct sk_buff *skb,
struct net_device *ndev)
{
netc_fill_common_tp_tag(skb, ndev, NETC_TAG_TP_SUBTYPE0,
NETC_TAG_TP_SUBTYPE0_LEN);
}
/* Currently only support To_Port tag, subtype 0 */
static struct sk_buff *netc_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
netc_fill_tp_tag_subtype0(skb, ndev);
return skb;
}
static int netc_get_rx_tag_len(int type, int subtype)
{
/* Only NETC_TAG_TO_HOST and NETC_TAG_FORWARD are expected in RX,
* NETC_TAG_TO_PORT is a TX switch tag that does not exist in RX.
*/
if (type == NETC_TAG_TO_HOST) {
if (subtype == NETC_TAG_TH_SUBTYPE1)
return NETC_TAG_TH_SUBTYPE1_LEN;
else if (subtype == NETC_TAG_TH_SUBTYPE2)
return NETC_TAG_TH_SUBTYPE2_LEN;
else
return NETC_TAG_TH_SUBTYPE0_LEN;
}
return NETC_TAG_FORWARD_LEN;
}
static struct sk_buff *netc_rcv(struct sk_buff *skb,
struct net_device *ndev)
{
struct netc_tag_cmn *tag_cmn;
int tag_len, sw_id, port;
int type, subtype;
if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN)))
goto err_free_skb;
tag_cmn = dsa_etype_header_pos_rx(skb);
if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) {
dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n",
ntohs(tag_cmn->tpid));
goto err_free_skb;
}
if (tag_cmn->qos & NETC_TAG_QV)
skb->priority = FIELD_GET(NETC_TAG_IPV, tag_cmn->qos);
sw_id = FIELD_GET(NETC_TAG_SWITCH, tag_cmn->switch_port);
/* ENETC VEPA switch ID (0) is not supported yet */
if (!sw_id) {
dev_warn_ratelimited(&ndev->dev,
"VEPA switch ID is not supported yet\n");
goto err_free_skb;
}
port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port);
skb->dev = dsa_conduit_find_user(ndev, sw_id, port);
if (!skb->dev)
goto err_free_skb;
type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type);
subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type);
if (type == NETC_TAG_FORWARD) {
dsa_default_offload_fwd_mark(skb);
} else if (type == NETC_TAG_TO_HOST) {
/* Currently only subtype0 supported */
if (subtype != NETC_TAG_TH_SUBTYPE0)
goto err_free_skb;
} else {
dev_warn_ratelimited(&ndev->dev,
"Unexpected tag type %d\n", type);
goto err_free_skb;
}
/* Remove Switch tag from the frame */
tag_len = netc_get_rx_tag_len(type, subtype);
skb_pull_rcsum(skb, tag_len);
dsa_strip_etype_header(skb, tag_len);
return skb;
err_free_skb:
kfree_skb(skb);
return NULL;
}
static void netc_flow_dissect(const struct sk_buff *skb, __be16 *proto,
int *offset)
{
struct netc_tag_cmn *tag_cmn = (struct netc_tag_cmn *)(skb->data - 2);
int subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type);
int type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type);
int tag_len = netc_get_rx_tag_len(type, subtype);
/* The RX minimum frame length of the NETC switch port is 64 bytes,
* and the frame is received by the ENETC driver. From the hardware
* perspective, the receive buffer of RX BD is at least 128 bytes,
* so the switch tag header is guaranteed to be in the linear region
* of the skb.
*/
*offset = tag_len;
*proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
}
static const struct dsa_device_ops netc_netdev_ops = {
.name = NETC_NAME,
.proto = DSA_TAG_PROTO_NETC,
.xmit = netc_xmit,
.rcv = netc_rcv,
.needed_headroom = NETC_TAG_MAX_LEN,
.flow_dissect = netc_flow_dissect,
};
MODULE_DESCRIPTION("DSA tag driver for NXP NETC switch family");
MODULE_LICENSE("GPL");
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NETC, NETC_NAME);
module_dsa_tag_driver(netc_netdev_ops);