diff --git a/Documentation/networking/devlink/devlink-port.rst b/Documentation/networking/devlink/devlink-port.rst
index 3da590953ce8..5c3996bce6d9 100644
--- a/Documentation/networking/devlink/devlink-port.rst
+++ b/Documentation/networking/devlink/devlink-port.rst
@@ -128,6 +128,9 @@ Users may also set the RoCE capability of the function using
 Users may also set the function as migratable using
 'devlink port function set migratable' command.
 
+Users may also assign VFs to physical ports using
+'devlink port function set vf_count' command.
+
 Function attributes
 ===================
 
@@ -240,6 +243,27 @@ Attach VF to the VM.
 Start the VM.
 Perform live migration.
 
+
+VF assignment setup
+---------------------------
+In some cases, NICs could have multiple physical ports per PF. Users can assign VFs to
+different ports.
+
+- Get count of VFs assigned to physical port::
+
+    $ devlink port show pci/0000:82:00.0/0
+    pci/0000:82:00.0/0: type eth netdev enp130s0np0 flavour physical port 0 splittable true lanes 4
+        function:
+            vf_count 0
+
+- Set count of VFs assigned to physical port::
+    $ devlink port function set pci/0000:82:00.0/0 vf_count 3
+
+    $ devlink port show pci/0000:82:00.0/0
+    pci/0000:82:00.0/0: type eth netdev enp130s0np0 flavour physical port 0 splittable true lanes 4
+        function:
+            vf_count 3
+
 Subfunction
 ============
 
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 2e85a5970a32..3e98fa3d251f 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1491,6 +1491,27 @@ struct devlink_ops {
 	int (*port_fn_migratable_set)(struct devlink_port *devlink_port,
 				      bool enable,
 				      struct netlink_ext_ack *extack);
+
+	/**
+	 * @port_fn_vf_count_get: Port function's VF count get function
+	 *
+	 * Get assigned VF count of a function managed by the devlink port,
+	 * should only be used for DEVLINK_PORT_FLAVOUR_PHYSICAL.
+	 * Return -EOPNOTSUPP if port function vf_count setup is not supported.
+	 */
+	int (*port_fn_vf_count_get)(struct devlink_port *port, u16 *vf_count,
+				    struct netlink_ext_ack *extack);
+
+	/**
+	 * @port_fn_vf_count_set: Port function's VF count set function
+	 *
+	 * Set assigned VF count of a function managed by the devlink port,
+	 * should only be used for DEVLINK_PORT_FLAVOUR_PHYSICAL.
+	 * Return -EOPNOTSUPP if port function vf_count setup is not supported.
+	 */
+	int (*port_fn_vf_count_set)(struct devlink_port *port, u16 vf_count,
+				    struct netlink_ext_ack *extack);
+
 	/**
 	 * port_new() - Add a new port function of a specified flavor
 	 * @devlink: Devlink instance
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 3782d4219ac9..774e17f6100b 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -676,6 +676,7 @@ enum devlink_port_function_attr {
 	DEVLINK_PORT_FN_ATTR_STATE,	/* u8 */
 	DEVLINK_PORT_FN_ATTR_OPSTATE,	/* u8 */
 	DEVLINK_PORT_FN_ATTR_CAPS,	/* bitfield32 */
+	DEVLINK_PORT_FN_ATTR_VF_COUNT,	/* u16 */
 
 	__DEVLINK_PORT_FUNCTION_ATTR_MAX,
 	DEVLINK_PORT_FUNCTION_ATTR_MAX = __DEVLINK_PORT_FUNCTION_ATTR_MAX - 1
diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c
index 97d30ea98b00..6dac8b562232 100644
--- a/net/devlink/leftover.c
+++ b/net/devlink/leftover.c
@@ -141,6 +141,7 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_
 				 DEVLINK_PORT_FN_STATE_ACTIVE),
 	[DEVLINK_PORT_FN_ATTR_CAPS] =
 		NLA_POLICY_BITFIELD32(DEVLINK_PORT_FN_CAPS_VALID_MASK),
+	[DEVLINK_PORT_FN_ATTR_VF_COUNT] = { .type = NLA_U16 },
 };
 
 #define ASSERT_DEVLINK_PORT_REGISTERED(devlink_port)				\
@@ -520,6 +521,35 @@ static int devlink_port_fn_caps_fill(const struct devlink_ops *ops,
 	return 0;
 }
 
+static int devlink_port_fn_vf_count_fill(const struct devlink_ops *ops,
+					 struct devlink_port *devlink_port,
+					 struct sk_buff *msg,
+					 struct netlink_ext_ack *extack,
+					 bool *msg_updated)
+{
+	u16 vf_count;
+	int err;
+
+	if (!ops->port_fn_vf_count_get ||
+	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL)
+		return 0;
+
+	err = ops->port_fn_vf_count_get(devlink_port, &vf_count, extack);
+	if (err) {
+		if (err == -EOPNOTSUPP)
+			return 0;
+		return err;
+	}
+
+	err = nla_put_u16(msg, DEVLINK_PORT_FN_ATTR_VF_COUNT, vf_count);
+	if (err)
+		return err;
+
+	*msg_updated = true;
+
+	return 0;
+}
+
 static int
 devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
 				  struct genl_info *info,
@@ -871,6 +901,16 @@ static int devlink_port_fn_caps_set(struct devlink_port *devlink_port,
 	return 0;
 }
 
+static int devlink_port_fn_vf_count_set(struct devlink_port *devlink_port,
+					const struct nlattr *attr,
+					struct netlink_ext_ack *extack)
+{
+	const struct devlink_ops *ops = devlink_port->devlink->ops;
+	u16 vf_count = nla_get_u16(attr);
+
+	return ops->port_fn_vf_count_set(devlink_port, vf_count, extack);
+}
+
 static int
 devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
 				   struct netlink_ext_ack *extack)
@@ -893,6 +933,11 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por
 					&msg_updated);
 	if (err)
 		goto out;
+
+	err = devlink_port_fn_vf_count_fill(ops, port, msg, extack, &msg_updated);
+	if (err)
+		goto out;
+
 	err = devlink_port_fn_state_fill(ops, port, msg, extack, &msg_updated);
 out:
 	if (err || !msg_updated)
@@ -1219,6 +1264,19 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port,
 				    "Function does not support state setting");
 		return -EOPNOTSUPP;
 	}
+	attr = tb[DEVLINK_PORT_FN_ATTR_VF_COUNT];
+	if (attr) {
+		if (!ops->port_fn_vf_count_set) {
+			NL_SET_ERR_MSG_ATTR(extack, attr,
+					    "Function doesn't support VF assignment");
+			return -EOPNOTSUPP;
+		}
+		if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL) {
+			NL_SET_ERR_MSG_ATTR(extack, attr,
+					    "VFs assignment supported for physical ports only");
+			return -EOPNOTSUPP;
+		}
+	}
 	attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
 	if (attr) {
 		struct nla_bitfield32 caps;
@@ -1278,6 +1336,13 @@ static int devlink_port_function_set(struct devlink_port *port,
 			return err;
 	}
 
+	attr = tb[DEVLINK_PORT_FN_ATTR_VF_COUNT];
+	if (attr) {
+		err = devlink_port_fn_vf_count_set(port, attr, extack);
+		if (err)
+			return err;
+	}
+
 	/* Keep this as the last function attribute set, so that when
 	 * multiple port function attributes are set along with state,
 	 * Those can be applied first before activating the state.
