brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 6eeeb0f Raw
312 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2017-2019 Netronome Systems, Inc. */3 4#include <linux/bitfield.h>5#include <linux/errno.h>6#include <linux/etherdevice.h>7#include <linux/if_link.h>8#include <linux/if_ether.h>9 10#include "nfpcore/nfp_cpp.h"11#include "nfp_app.h"12#include "nfp_main.h"13#include "nfp_net_ctrl.h"14#include "nfp_net.h"15#include "nfp_net_sriov.h"16 17static int18nfp_net_sriov_check(struct nfp_app *app, int vf, u16 cap, const char *msg, bool warn)19{20	u16 cap_vf;21 22	if (!app || !app->pf->vfcfg_tbl2)23		return -EOPNOTSUPP;24 25	cap_vf = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_CAP);26	if ((cap_vf & cap) != cap) {27		if (warn)28			nfp_warn(app->pf->cpp, "ndo_set_vf_%s not supported\n", msg);29		return -EOPNOTSUPP;30	}31 32	if (vf < 0 || vf >= app->pf->num_vfs) {33		if (warn)34			nfp_warn(app->pf->cpp, "invalid VF id %d\n", vf);35		return -EINVAL;36	}37 38	return 0;39}40 41static int42nfp_net_sriov_update(struct nfp_app *app, int vf, u16 update, const char *msg)43{44	struct nfp_net *nn;45	int ret;46 47	/* Write update info to mailbox in VF config symbol */48	writeb(vf, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_VF_NUM);49	writew(update, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_UPD);50 51	nn = list_first_entry(&app->pf->vnics, struct nfp_net, vnic_list);52	/* Signal VF reconfiguration */53	ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_VF);54	if (ret)55		return ret;56 57	ret = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_RET);58	if (ret)59		nfp_warn(app->pf->cpp,60			 "FW refused VF %s update with errno: %d\n", msg, ret);61	return -ret;62}63 64int nfp_app_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)65{66	struct nfp_app *app = nfp_app_from_netdev(netdev);67	unsigned int vf_offset;68	int err;69 70	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_MAC, "mac", true);71	if (err)72		return err;73 74	if (is_multicast_ether_addr(mac)) {75		nfp_warn(app->pf->cpp,76			 "invalid Ethernet address %pM for VF id %d\n",77			 mac, vf);78		return -EINVAL;79	}80 81	/* Write MAC to VF entry in VF config symbol */82	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;83	writel(get_unaligned_be32(mac), app->pf->vfcfg_tbl2 + vf_offset);84	writew(get_unaligned_be16(mac + 4),85	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);86 87	err = nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_MAC, "MAC");88	if (!err)89		nfp_info(app->pf->cpp,90			 "MAC %pM set on VF %d, reload the VF driver to make this change effective.\n",91			 mac, vf);92 93	return err;94}95 96int nfp_app_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,97			__be16 vlan_proto)98{99	struct nfp_app *app = nfp_app_from_netdev(netdev);100	u16 update = NFP_NET_VF_CFG_MB_UPD_VLAN;101	bool is_proto_sup = true;102	unsigned int vf_offset;103	u32 vlan_tag;104	int err;105 106	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN, "vlan", true);107	if (err)108		return err;109 110	if (!eth_type_vlan(vlan_proto))111		return -EOPNOTSUPP;112 113	if (vlan > 4095 || qos > 7) {114		nfp_warn(app->pf->cpp,115			 "invalid vlan id or qos for VF id %d\n", vf);116		return -EINVAL;117	}118 119	/* Check if fw supports or not */120	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", true);121	if (err)122		is_proto_sup = false;123 124	if (vlan_proto != htons(ETH_P_8021Q)) {125		if (!is_proto_sup)126			return -EOPNOTSUPP;127		update |= NFP_NET_VF_CFG_MB_UPD_VLAN_PROTO;128	}129 130	/* Write VLAN tag to VF entry in VF config symbol */131	vlan_tag = FIELD_PREP(NFP_NET_VF_CFG_VLAN_VID, vlan) |132		FIELD_PREP(NFP_NET_VF_CFG_VLAN_QOS, qos);133 134	/* vlan_tag of 0 means that the configuration should be cleared and in135	 * such circumstances setting the TPID has no meaning when136	 * configuring firmware.137	 */138	if (vlan_tag && is_proto_sup)139		vlan_tag |= FIELD_PREP(NFP_NET_VF_CFG_VLAN_PROT, ntohs(vlan_proto));140 141	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;142	writel(vlan_tag, app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);143 144	return nfp_net_sriov_update(app, vf, update, "vlan");145}146 147int nfp_app_set_vf_rate(struct net_device *netdev, int vf,148			int min_tx_rate, int max_tx_rate)149{150	struct nfp_app *app = nfp_app_from_netdev(netdev);151	u32 vf_offset, ratevalue;152	int err;153 154	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", true);155	if (err)156		return err;157 158	if (max_tx_rate >= NFP_NET_VF_RATE_MAX ||159	    min_tx_rate >= NFP_NET_VF_RATE_MAX) {160		nfp_warn(app->cpp, "tx-rate exceeds %d.\n",161			 NFP_NET_VF_RATE_MAX);162		return -EINVAL;163	}164 165	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;166	ratevalue = FIELD_PREP(NFP_NET_VF_CFG_MAX_RATE,167			       max_tx_rate ? max_tx_rate :168			       NFP_NET_VF_RATE_MAX) |169		    FIELD_PREP(NFP_NET_VF_CFG_MIN_RATE, min_tx_rate);170 171	writel(ratevalue,172	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_RATE);173 174	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_RATE,175				    "rate");176}177 178int nfp_app_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)179{180	struct nfp_app *app = nfp_app_from_netdev(netdev);181	unsigned int vf_offset;182	u8 vf_ctrl;183	int err;184 185	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_SPOOF,186				  "spoofchk", true);187	if (err)188		return err;189 190	/* Write spoof check control bit to VF entry in VF config symbol */191	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +192		NFP_NET_VF_CFG_CTRL;193	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);194	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_SPOOF;195	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_SPOOF, enable);196	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);197 198	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_SPOOF,199				    "spoofchk");200}201 202int nfp_app_set_vf_trust(struct net_device *netdev, int vf, bool enable)203{204	struct nfp_app *app = nfp_app_from_netdev(netdev);205	unsigned int vf_offset;206	u8 vf_ctrl;207	int err;208 209	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_TRUST,210				  "trust", true);211	if (err)212		return err;213 214	/* Write trust control bit to VF entry in VF config symbol */215	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +216		NFP_NET_VF_CFG_CTRL;217	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);218	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_TRUST;219	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_TRUST, enable);220	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);221 222	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_TRUST,223				    "trust");224}225 226int nfp_app_set_vf_link_state(struct net_device *netdev, int vf,227			      int link_state)228{229	struct nfp_app *app = nfp_app_from_netdev(netdev);230	unsigned int vf_offset;231	u8 vf_ctrl;232	int err;233 234	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_LINK_STATE,235				  "link_state", true);236	if (err)237		return err;238 239	switch (link_state) {240	case IFLA_VF_LINK_STATE_AUTO:241	case IFLA_VF_LINK_STATE_ENABLE:242	case IFLA_VF_LINK_STATE_DISABLE:243		break;244	default:245		return -EINVAL;246	}247 248	/* Write link state to VF entry in VF config symbol */249	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +250		NFP_NET_VF_CFG_CTRL;251	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);252	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_LINK_STATE;253	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_LINK_STATE, link_state);254	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);255 256	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_LINK_STATE,257				    "link state");258}259 260int nfp_app_get_vf_config(struct net_device *netdev, int vf,261			  struct ifla_vf_info *ivi)262{263	struct nfp_app *app = nfp_app_from_netdev(netdev);264	u32 vf_offset, mac_hi, rate;265	u32 vlan_tag;266	u16 mac_lo;267	u8 flags;268	int err;269 270	err = nfp_net_sriov_check(app, vf, 0, "", true);271	if (err)272		return err;273 274	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;275 276	mac_hi = readl(app->pf->vfcfg_tbl2 + vf_offset);277	mac_lo = readw(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);278 279	flags = readb(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_CTRL);280	vlan_tag = readl(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);281 282	memset(ivi, 0, sizeof(*ivi));283	ivi->vf = vf;284 285	put_unaligned_be32(mac_hi, &ivi->mac[0]);286	put_unaligned_be16(mac_lo, &ivi->mac[4]);287 288	ivi->vlan = FIELD_GET(NFP_NET_VF_CFG_VLAN_VID, vlan_tag);289	ivi->qos = FIELD_GET(NFP_NET_VF_CFG_VLAN_QOS, vlan_tag);290	if (!nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", false))291		ivi->vlan_proto = htons(FIELD_GET(NFP_NET_VF_CFG_VLAN_PROT, vlan_tag));292	ivi->spoofchk = FIELD_GET(NFP_NET_VF_CFG_CTRL_SPOOF, flags);293	ivi->trusted = FIELD_GET(NFP_NET_VF_CFG_CTRL_TRUST, flags);294	ivi->linkstate = FIELD_GET(NFP_NET_VF_CFG_CTRL_LINK_STATE, flags);295 296	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", false);297	if (!err) {298		rate = readl(app->pf->vfcfg_tbl2 + vf_offset +299			     NFP_NET_VF_CFG_RATE);300 301		ivi->max_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MAX_RATE, rate);302		ivi->min_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MIN_RATE, rate);303 304		if (ivi->max_tx_rate == NFP_NET_VF_RATE_MAX)305			ivi->max_tx_rate = 0;306		if (ivi->min_tx_rate == NFP_NET_VF_RATE_MAX)307			ivi->min_tx_rate = 0;308	}309 310	return 0;311}312