#include <linux/pkt_sched.h>
#include <linux/regmap.h>
#include <net/dsa.h>
+#include <net/dst_metadata.h>
#include <net/page_pool/helpers.h>
#include <net/switchdev.h>
struct phylink_config phylink_config;
const struct rteth_config *r;
u32 lastEvent;
+ struct metadata_dst *dsa_meta[RTETH_931X_CPU_PORT];
/* receive handling */
dma_addr_t rx_data_dma;
spinlock_t rx_lock;
static int rteth_hw_receive(struct net_device *dev, int ring, int budget)
{
- int slot, len, work_done = 0, rx_packets = 0, rx_bytes = 0;
+ int slot, work_done = 0, rx_packets = 0, rx_bytes = 0;
struct rteth_ctrl *ctrl = netdev_priv(dev);
- unsigned int new_offset, old_offset;
+ unsigned int len, new_offset, old_offset;
struct page *old_page, *new_page;
- bool dsa = netdev_uses_dsa(dev);
struct rteth_packet *packet;
dma_addr_t packet_dma;
struct sk_buff *skb;
break;
packet = &ctrl->rx_data[ring].packet[slot];
- len = packet->len;
+ len = packet->len - ETH_FCS_LEN;
- if (unlikely(len < ETH_FCS_LEN || len > RING_BUFFER)) {
+ if (unlikely(len > RING_BUFFER)) {
netdev_err(dev, "invalid packet with %d bytes received\n", len);
dev->stats.rx_errors++;
goto recycle;
packet->page_offset = new_offset;
packet->dma = page_pool_get_dma_addr(new_page) + new_offset + RTETH_SKB_HEADROOM;
- if (!dsa)
- len -= ETH_FCS_LEN;
-
page_pool_dma_sync_for_cpu(ctrl->rx_qs[ring].page_pool, old_page,
old_offset + RTETH_SKB_HEADROOM, len);
skb_put(skb, len);
ctrl->r->decode_tag(packet, &tag);
- if (dsa) {
- skb->data[len - 4] = 0x80;
- skb->data[len - 3] = tag.port;
- skb->data[len - 2] = 0x10;
- skb->data[len - 1] = 0x00;
+ if (netdev_uses_dsa(dev)) {
+ if (tag.port < ctrl->r->cpu_port)
+ skb_dst_set_noref(skb, &ctrl->dsa_meta[tag.port]->dst);
if (tag.l2_offloaded)
- skb->data[len - 3] |= 0x40;
+ skb->offload_fwd_mark = 1;
}
skb->protocol = eth_type_trans(skb, dev);
.set_link_ksettings = rteth_set_link_ksettings,
};
+static int rteth_metadata_dst_alloc(struct rteth_ctrl *ctrl)
+{
+ struct metadata_dst *md_dst;
+
+ for (int i = 0; i < ARRAY_SIZE(ctrl->dsa_meta); i++) {
+ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL);
+ if (!md_dst)
+ return -ENOMEM;
+
+ md_dst->u.port_info.port_id = i;
+ ctrl->dsa_meta[i] = md_dst;
+ }
+
+ return 0;
+}
+
+static void rteth_metadata_dst_free(struct rteth_ctrl *ctrl)
+{
+ for (int i = 0; i < ARRAY_SIZE(ctrl->dsa_meta); i++) {
+ if (!ctrl->dsa_meta[i])
+ continue;
+
+ metadata_dst_free(ctrl->dsa_meta[i]);
+ }
+}
+
static int rteth_probe(struct platform_device *pdev)
{
struct page_pool_params pp_params = {
}
}
+ err = rteth_metadata_dst_alloc(ctrl);
+ if (err)
+ goto cleanup;
+
err = register_netdev(dev);
if (err)
goto cleanup;
return 0;
cleanup:
+ rteth_metadata_dst_free(ctrl);
if (ctrl->phylink)
phylink_destroy(ctrl->phylink);
for (int i = 0; i < RTETH_RX_RINGS; i++) {
pr_info("Removing platform driver for rtl838x-eth\n");
unregister_netdev(dev);
+ rteth_metadata_dst_free(ctrl);
if (ctrl->phylink)
phylink_destroy(ctrl->phylink);
static struct sk_buff *rtl_otto_rcv(struct sk_buff *skb, struct net_device *dev)
{
- u8 *trailer;
- int source_port;
-
- if (skb_linearize(skb))
- return NULL;
-
- trailer = skb_tail_pointer(skb) - 4;
-
- if (trailer[0] != 0x80 || (trailer[1] & 0x80) != 0x00 ||
- (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
- return NULL;
-
- if (trailer[1] & 0x40)
- skb->offload_fwd_mark = 1;
-
- source_port = trailer[1] & 0x3f;
-
- skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
- return NULL;
-
- if (pskb_trim_rcsum(skb, skb->len - 4))
- return NULL;
+ /* RX path uses METADATA_HW_PORT_MUX. This function just makes netdev_uses_dsa() happy. */
+ netdev_err(dev, "ethernet driver did not set METADATA\n");
return skb;
}