|
@@ -1490,6 +1490,69 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
|
|
|
+{
|
|
|
+ int port, err;
|
|
|
+ struct mlx4_vport_state *vp_admin;
|
|
|
+ struct mlx4_vport_oper_state *vp_oper;
|
|
|
+
|
|
|
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
|
|
|
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
|
|
|
+ vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ vp_oper->state = *vp_admin;
|
|
|
+ if (MLX4_VGT != vp_admin->default_vlan) {
|
|
|
+ err = __mlx4_register_vlan(&priv->dev, port,
|
|
|
+ vp_admin->default_vlan, &(vp_oper->vlan_idx));
|
|
|
+ if (err) {
|
|
|
+ vp_oper->vlan_idx = NO_INDX;
|
|
|
+ mlx4_warn((&priv->dev),
|
|
|
+ "No vlan resorces slave %d, port %d\n",
|
|
|
+ slave, port);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n",
|
|
|
+ (int)(vp_oper->state.default_vlan),
|
|
|
+ vp_oper->vlan_idx, slave, port);
|
|
|
+ }
|
|
|
+ if (vp_admin->spoofchk) {
|
|
|
+ vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
|
|
|
+ port,
|
|
|
+ vp_admin->mac);
|
|
|
+ if (0 > vp_oper->mac_idx) {
|
|
|
+ err = vp_oper->mac_idx;
|
|
|
+ vp_oper->mac_idx = NO_INDX;
|
|
|
+ mlx4_warn((&priv->dev),
|
|
|
+ "No mac resorces slave %d, port %d\n",
|
|
|
+ slave, port);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n",
|
|
|
+ vp_oper->state.mac, vp_oper->mac_idx, slave, port);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
|
|
|
+{
|
|
|
+ int port;
|
|
|
+ struct mlx4_vport_oper_state *vp_oper;
|
|
|
+
|
|
|
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
|
|
|
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
|
|
|
+ if (NO_INDX != vp_oper->vlan_idx) {
|
|
|
+ __mlx4_unregister_vlan(&priv->dev,
|
|
|
+ port, vp_oper->vlan_idx);
|
|
|
+ vp_oper->vlan_idx = NO_INDX;
|
|
|
+ }
|
|
|
+ if (NO_INDX != vp_oper->mac_idx) {
|
|
|
+ __mlx4_unregister_mac(&priv->dev, port, vp_oper->mac_idx);
|
|
|
+ vp_oper->mac_idx = NO_INDX;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
|
|
|
u16 param, u8 toggle)
|
|
|
{
|
|
@@ -1510,6 +1573,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
|
|
|
if (cmd == MLX4_COMM_CMD_RESET) {
|
|
|
mlx4_warn(dev, "Received reset from slave:%d\n", slave);
|
|
|
slave_state[slave].active = false;
|
|
|
+ mlx4_master_deactivate_admin_state(priv, slave);
|
|
|
for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
|
|
|
slave_state[slave].event_eq[i].eqn = -1;
|
|
|
slave_state[slave].event_eq[i].token = 0;
|
|
@@ -1556,6 +1620,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
|
|
|
if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
|
|
|
goto reset_slave;
|
|
|
slave_state[slave].vhcr_dma |= param;
|
|
|
+ if (mlx4_master_activate_admin_state(priv, slave))
|
|
|
+ goto reset_slave;
|
|
|
slave_state[slave].active = true;
|
|
|
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
|
|
|
break;
|
|
@@ -1732,6 +1798,18 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
|
|
|
if (!priv->mfunc.master.slave_state)
|
|
|
goto err_comm;
|
|
|
|
|
|
+ priv->mfunc.master.vf_admin =
|
|
|
+ kzalloc(dev->num_slaves *
|
|
|
+ sizeof(struct mlx4_vf_admin_state), GFP_KERNEL);
|
|
|
+ if (!priv->mfunc.master.vf_admin)
|
|
|
+ goto err_comm_admin;
|
|
|
+
|
|
|
+ priv->mfunc.master.vf_oper =
|
|
|
+ kzalloc(dev->num_slaves *
|
|
|
+ sizeof(struct mlx4_vf_oper_state), GFP_KERNEL);
|
|
|
+ if (!priv->mfunc.master.vf_oper)
|
|
|
+ goto err_comm_oper;
|
|
|
+
|
|
|
for (i = 0; i < dev->num_slaves; ++i) {
|
|
|
s_state = &priv->mfunc.master.slave_state[i];
|
|
|
s_state->last_cmd = MLX4_COMM_CMD_RESET;
|
|
@@ -1752,6 +1830,10 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
|
|
|
goto err_slaves;
|
|
|
}
|
|
|
INIT_LIST_HEAD(&s_state->mcast_filters[port]);
|
|
|
+ priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
|
|
|
+ priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
|
|
|
+ priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
|
|
|
+ priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
|
|
|
}
|
|
|
spin_lock_init(&s_state->lock);
|
|
|
}
|
|
@@ -1800,6 +1882,10 @@ err_slaves:
|
|
|
for (port = 1; port <= MLX4_MAX_PORTS; port++)
|
|
|
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
|
|
|
}
|
|
|
+ kfree(priv->mfunc.master.vf_oper);
|
|
|
+err_comm_oper:
|
|
|
+ kfree(priv->mfunc.master.vf_admin);
|
|
|
+err_comm_admin:
|
|
|
kfree(priv->mfunc.master.slave_state);
|
|
|
err_comm:
|
|
|
iounmap(priv->mfunc.comm);
|
|
@@ -1874,6 +1960,8 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
|
|
|
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
|
|
|
}
|
|
|
kfree(priv->mfunc.master.slave_state);
|
|
|
+ kfree(priv->mfunc.master.vf_admin);
|
|
|
+ kfree(priv->mfunc.master.vf_oper);
|
|
|
}
|
|
|
|
|
|
iounmap(priv->mfunc.comm);
|
|
@@ -1984,3 +2072,115 @@ u32 mlx4_comm_get_version(void)
|
|
|
{
|
|
|
return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
|
|
|
}
|
|
|
+
|
|
|
+static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
|
|
|
+{
|
|
|
+ if ((vf < 0) || (vf >= dev->num_vfs)) {
|
|
|
+ mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return vf+1;
|
|
|
+}
|
|
|
+
|
|
|
+int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ struct mlx4_vport_state *s_info;
|
|
|
+ int slave;
|
|
|
+
|
|
|
+ if (!mlx4_is_master(dev))
|
|
|
+ return -EPROTONOSUPPORT;
|
|
|
+
|
|
|
+ slave = mlx4_get_slave_indx(dev, vf);
|
|
|
+ if (slave < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ s_info->mac = mac;
|
|
|
+ mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n",
|
|
|
+ vf, port, s_info->mac);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
|
|
|
+
|
|
|
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ struct mlx4_vport_state *s_info;
|
|
|
+ int slave;
|
|
|
+
|
|
|
+ if ((!mlx4_is_master(dev)) ||
|
|
|
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
|
|
|
+ return -EPROTONOSUPPORT;
|
|
|
+
|
|
|
+ if ((vlan > 4095) || (qos > 7))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ slave = mlx4_get_slave_indx(dev, vf);
|
|
|
+ if (slave < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ if ((0 == vlan) && (0 == qos))
|
|
|
+ s_info->default_vlan = MLX4_VGT;
|
|
|
+ else
|
|
|
+ s_info->default_vlan = vlan;
|
|
|
+ s_info->default_qos = qos;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
|
|
|
+
|
|
|
+int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ struct mlx4_vport_state *s_info;
|
|
|
+ int slave;
|
|
|
+
|
|
|
+ if ((!mlx4_is_master(dev)) ||
|
|
|
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM))
|
|
|
+ return -EPROTONOSUPPORT;
|
|
|
+
|
|
|
+ slave = mlx4_get_slave_indx(dev, vf);
|
|
|
+ if (slave < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ s_info->spoofchk = setting;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
|
|
|
+
|
|
|
+int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ struct mlx4_vport_state *s_info;
|
|
|
+ int slave;
|
|
|
+
|
|
|
+ if (!mlx4_is_master(dev))
|
|
|
+ return -EPROTONOSUPPORT;
|
|
|
+
|
|
|
+ slave = mlx4_get_slave_indx(dev, vf);
|
|
|
+ if (slave < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ ivf->vf = vf;
|
|
|
+
|
|
|
+ /* need to convert it to a func */
|
|
|
+ ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff);
|
|
|
+ ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff);
|
|
|
+ ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff);
|
|
|
+ ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff);
|
|
|
+ ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff);
|
|
|
+ ivf->mac[5] = ((s_info->mac) & 0xff);
|
|
|
+
|
|
|
+ ivf->vlan = s_info->default_vlan;
|
|
|
+ ivf->qos = s_info->default_qos;
|
|
|
+ ivf->tx_rate = s_info->tx_rate;
|
|
|
+ ivf->spoofchk = s_info->spoofchk;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mlx4_get_vf_config);
|