162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * switchdev.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	Authors:
662306a36Sopenharmony_ci *	Hans J. Schultz		<netdev@kapio-technology.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <net/switchdev.h>
1162306a36Sopenharmony_ci#include "chip.h"
1262306a36Sopenharmony_ci#include "global1.h"
1362306a36Sopenharmony_ci#include "switchdev.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct mv88e6xxx_fid_search_ctx {
1662306a36Sopenharmony_ci	u16 fid_search;
1762306a36Sopenharmony_ci	u16 vid_found;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int __mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip,
2162306a36Sopenharmony_ci				const struct mv88e6xxx_vtu_entry *entry,
2262306a36Sopenharmony_ci				void *priv)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct mv88e6xxx_fid_search_ctx *ctx = priv;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if (ctx->fid_search == entry->fid) {
2762306a36Sopenharmony_ci		ctx->vid_found = entry->vid;
2862306a36Sopenharmony_ci		return 1;
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip, u16 fid, u16 *vid)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct mv88e6xxx_fid_search_ctx ctx;
3762306a36Sopenharmony_ci	int err;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ctx.fid_search = fid;
4062306a36Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
4162306a36Sopenharmony_ci	err = mv88e6xxx_vtu_walk(chip, __mv88e6xxx_find_vid, &ctx);
4262306a36Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
4362306a36Sopenharmony_ci	if (err < 0)
4462306a36Sopenharmony_ci		return err;
4562306a36Sopenharmony_ci	if (err == 1)
4662306a36Sopenharmony_ci		*vid = ctx.vid_found;
4762306a36Sopenharmony_ci	else
4862306a36Sopenharmony_ci		return -ENOENT;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	return 0;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciint mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,
5462306a36Sopenharmony_ci				    struct mv88e6xxx_atu_entry *entry, u16 fid)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct switchdev_notifier_fdb_info info = {
5762306a36Sopenharmony_ci		.addr = entry->mac,
5862306a36Sopenharmony_ci		.locked = true,
5962306a36Sopenharmony_ci	};
6062306a36Sopenharmony_ci	struct net_device *brport;
6162306a36Sopenharmony_ci	struct dsa_port *dp;
6262306a36Sopenharmony_ci	u16 vid;
6362306a36Sopenharmony_ci	int err;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	err = mv88e6xxx_find_vid(chip, fid, &vid);
6662306a36Sopenharmony_ci	if (err)
6762306a36Sopenharmony_ci		return err;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	info.vid = vid;
7062306a36Sopenharmony_ci	dp = dsa_to_port(chip->ds, port);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	rtnl_lock();
7362306a36Sopenharmony_ci	brport = dsa_port_to_bridge_port(dp);
7462306a36Sopenharmony_ci	if (!brport) {
7562306a36Sopenharmony_ci		rtnl_unlock();
7662306a36Sopenharmony_ci		return -ENODEV;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
7962306a36Sopenharmony_ci				       brport, &info.info, NULL);
8062306a36Sopenharmony_ci	rtnl_unlock();
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return err;
8362306a36Sopenharmony_ci}
84