Commit 146f3ef4 authored by Jack Morgenstein's avatar Jack Morgenstein Committed by David S. Miller

net/mlx4_core: Implement resource quota enforcement

Implements resource quota grant decision when resources are requested,
for the following resources:  QPs, CQs, SRQs, MPTs, MTTs, vlans, MACs,
and Counters.

When granting a resource, the quota system increases the allocated-count
for that slave.

When the slave later frees the resource, its allocated-count is reduced.

A spinlock is used to protect the integrity of each resource's free-pool counter.
(One slave may be in the process of being granted a resource while another
slave has crashed, initiating cleanup of that slave's resource quotas).
Signed-off-by: default avatarJack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eb456a68
...@@ -505,6 +505,7 @@ struct slave_list { ...@@ -505,6 +505,7 @@ struct slave_list {
}; };
struct resource_allocator { struct resource_allocator {
spinlock_t alloc_lock; /* protect quotas */
union { union {
int res_reserved; int res_reserved;
int res_port_rsvd[MLX4_MAX_PORTS]; int res_port_rsvd[MLX4_MAX_PORTS];
......
...@@ -284,6 +284,85 @@ static const char *ResourceType(enum mlx4_resource rt) ...@@ -284,6 +284,85 @@ static const char *ResourceType(enum mlx4_resource rt)
} }
static void rem_slave_vlans(struct mlx4_dev *dev, int slave); static void rem_slave_vlans(struct mlx4_dev *dev, int slave);
static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
enum mlx4_resource res_type, int count,
int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct resource_allocator *res_alloc =
&priv->mfunc.master.res_tracker.res_alloc[res_type];
int err = -EINVAL;
int allocated, free, reserved, guaranteed, from_free;
if (slave > dev->num_vfs)
return -EINVAL;
spin_lock(&res_alloc->alloc_lock);
allocated = (port > 0) ?
res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] :
res_alloc->allocated[slave];
free = (port > 0) ? res_alloc->res_port_free[port - 1] :
res_alloc->res_free;
reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :
res_alloc->res_reserved;
guaranteed = res_alloc->guaranteed[slave];
if (allocated + count > res_alloc->quota[slave])
goto out;
if (allocated + count <= guaranteed) {
err = 0;
} else {
/* portion may need to be obtained from free area */
if (guaranteed - allocated > 0)
from_free = count - (guaranteed - allocated);
else
from_free = count;
if (free - from_free > reserved)
err = 0;
}
if (!err) {
/* grant the request */
if (port > 0) {
res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count;
res_alloc->res_port_free[port - 1] -= count;
} else {
res_alloc->allocated[slave] += count;
res_alloc->res_free -= count;
}
}
out:
spin_unlock(&res_alloc->alloc_lock);
return err;
}
static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
enum mlx4_resource res_type, int count,
int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct resource_allocator *res_alloc =
&priv->mfunc.master.res_tracker.res_alloc[res_type];
if (slave > dev->num_vfs)
return;
spin_lock(&res_alloc->alloc_lock);
if (port > 0) {
res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count;
res_alloc->res_port_free[port - 1] += count;
} else {
res_alloc->allocated[slave] -= count;
res_alloc->res_free += count;
}
spin_unlock(&res_alloc->alloc_lock);
return;
}
static inline void initialize_res_quotas(struct mlx4_dev *dev, static inline void initialize_res_quotas(struct mlx4_dev *dev,
struct resource_allocator *res_alloc, struct resource_allocator *res_alloc,
enum mlx4_resource res_type, enum mlx4_resource res_type,
...@@ -373,6 +452,7 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) ...@@ -373,6 +452,7 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
!res_alloc->allocated) !res_alloc->allocated)
goto no_mem_err; goto no_mem_err;
spin_lock_init(&res_alloc->alloc_lock);
for (t = 0; t < dev->num_vfs + 1; t++) { for (t = 0; t < dev->num_vfs + 1; t++) {
switch (i) { switch (i) {
case RES_QP: case RES_QP:
...@@ -1399,12 +1479,19 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1399,12 +1479,19 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
case RES_OP_RESERVE: case RES_OP_RESERVE:
count = get_param_l(&in_param); count = get_param_l(&in_param);
align = get_param_h(&in_param); align = get_param_h(&in_param);
err = __mlx4_qp_reserve_range(dev, count, align, &base); err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
if (err) if (err)
return err; return err;
err = __mlx4_qp_reserve_range(dev, count, align, &base);
if (err) {
mlx4_release_resource(dev, slave, RES_QP, count, 0);
return err;
}
err = add_res_range(dev, slave, base, count, RES_QP, 0); err = add_res_range(dev, slave, base, count, RES_QP, 0);
if (err) { if (err) {
mlx4_release_resource(dev, slave, RES_QP, count, 0);
__mlx4_qp_release_range(dev, base, count); __mlx4_qp_release_range(dev, base, count);
return err; return err;
} }
...@@ -1452,15 +1539,24 @@ static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1452,15 +1539,24 @@ static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err; return err;
order = get_param_l(&in_param); order = get_param_l(&in_param);
err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);
if (err)
return err;
base = __mlx4_alloc_mtt_range(dev, order); base = __mlx4_alloc_mtt_range(dev, order);
if (base == -1) if (base == -1) {
mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
return -ENOMEM; return -ENOMEM;
}
err = add_res_range(dev, slave, base, 1, RES_MTT, order); err = add_res_range(dev, slave, base, 1, RES_MTT, order);
if (err) if (err) {
mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
__mlx4_free_mtt_range(dev, base, order); __mlx4_free_mtt_range(dev, base, order);
else } else {
set_param_l(out_param, base); set_param_l(out_param, base);
}
return err; return err;
} }
...@@ -1475,13 +1571,20 @@ static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1475,13 +1571,20 @@ static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
switch (op) { switch (op) {
case RES_OP_RESERVE: case RES_OP_RESERVE:
err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);
if (err)
break;
index = __mlx4_mpt_reserve(dev); index = __mlx4_mpt_reserve(dev);
if (index == -1) if (index == -1) {
mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
break; break;
}
id = index & mpt_mask(dev); id = index & mpt_mask(dev);
err = add_res_range(dev, slave, id, 1, RES_MPT, index); err = add_res_range(dev, slave, id, 1, RES_MPT, index);
if (err) { if (err) {
mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
__mlx4_mpt_release(dev, index); __mlx4_mpt_release(dev, index);
break; break;
} }
...@@ -1515,12 +1618,19 @@ static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1515,12 +1618,19 @@ static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
switch (op) { switch (op) {
case RES_OP_RESERVE_AND_MAP: case RES_OP_RESERVE_AND_MAP:
err = __mlx4_cq_alloc_icm(dev, &cqn); err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);
if (err) if (err)
break; break;
err = __mlx4_cq_alloc_icm(dev, &cqn);
if (err) {
mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
break;
}
err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);
if (err) { if (err) {
mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
__mlx4_cq_free_icm(dev, cqn); __mlx4_cq_free_icm(dev, cqn);
break; break;
} }
...@@ -1543,12 +1653,19 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1543,12 +1653,19 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
switch (op) { switch (op) {
case RES_OP_RESERVE_AND_MAP: case RES_OP_RESERVE_AND_MAP:
err = __mlx4_srq_alloc_icm(dev, &srqn); err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);
if (err) if (err)
break; break;
err = __mlx4_srq_alloc_icm(dev, &srqn);
if (err) {
mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
break;
}
err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
if (err) { if (err) {
mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
__mlx4_srq_free_icm(dev, srqn); __mlx4_srq_free_icm(dev, srqn);
break; break;
} }
...@@ -1569,9 +1686,13 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) ...@@ -1569,9 +1686,13 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
struct mac_res *res; struct mac_res *res;
if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
return -EINVAL;
res = kzalloc(sizeof *res, GFP_KERNEL); res = kzalloc(sizeof *res, GFP_KERNEL);
if (!res) if (!res) {
mlx4_release_resource(dev, slave, RES_MAC, 1, port);
return -ENOMEM; return -ENOMEM;
}
res->mac = mac; res->mac = mac;
res->port = (u8) port; res->port = (u8) port;
list_add_tail(&res->list, list_add_tail(&res->list,
...@@ -1591,6 +1712,7 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, ...@@ -1591,6 +1712,7 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
list_for_each_entry_safe(res, tmp, mac_list, list) { list_for_each_entry_safe(res, tmp, mac_list, list) {
if (res->mac == mac && res->port == (u8) port) { if (res->mac == mac && res->port == (u8) port) {
list_del(&res->list); list_del(&res->list);
mlx4_release_resource(dev, slave, RES_MAC, 1, port);
kfree(res); kfree(res);
break; break;
} }
...@@ -1608,6 +1730,7 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave) ...@@ -1608,6 +1730,7 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
list_for_each_entry_safe(res, tmp, mac_list, list) { list_for_each_entry_safe(res, tmp, mac_list, list) {
list_del(&res->list); list_del(&res->list);
__mlx4_unregister_mac(dev, res->port, res->mac); __mlx4_unregister_mac(dev, res->port, res->mac);
mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
kfree(res); kfree(res);
} }
} }
...@@ -1656,9 +1779,13 @@ static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, ...@@ -1656,9 +1779,13 @@ static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,
} }
} }
if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))
return -EINVAL;
res = kzalloc(sizeof(*res), GFP_KERNEL); res = kzalloc(sizeof(*res), GFP_KERNEL);
if (!res) if (!res) {
mlx4_release_resource(dev, slave, RES_VLAN, 1, port);
return -ENOMEM; return -ENOMEM;
}
res->vlan = vlan; res->vlan = vlan;
res->port = (u8) port; res->port = (u8) port;
res->vlan_index = vlan_index; res->vlan_index = vlan_index;
...@@ -1682,6 +1809,8 @@ static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, ...@@ -1682,6 +1809,8 @@ static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,
if (res->vlan == vlan && res->port == (u8) port) { if (res->vlan == vlan && res->port == (u8) port) {
if (!--res->ref_count) { if (!--res->ref_count) {
list_del(&res->list); list_del(&res->list);
mlx4_release_resource(dev, slave, RES_VLAN,
1, port);
kfree(res); kfree(res);
} }
break; break;
...@@ -1703,6 +1832,7 @@ static void rem_slave_vlans(struct mlx4_dev *dev, int slave) ...@@ -1703,6 +1832,7 @@ static void rem_slave_vlans(struct mlx4_dev *dev, int slave)
/* dereference the vlan the num times the slave referenced it */ /* dereference the vlan the num times the slave referenced it */
for (i = 0; i < res->ref_count; i++) for (i = 0; i < res->ref_count; i++)
__mlx4_unregister_vlan(dev, res->port, res->vlan); __mlx4_unregister_vlan(dev, res->port, res->vlan);
mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);
kfree(res); kfree(res);
} }
} }
...@@ -1749,15 +1879,23 @@ static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1749,15 +1879,23 @@ static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
if (op != RES_OP_RESERVE) if (op != RES_OP_RESERVE)
return -EINVAL; return -EINVAL;
err = __mlx4_counter_alloc(dev, &index); err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);
if (err) if (err)
return err; return err;
err = __mlx4_counter_alloc(dev, &index);
if (err) {
mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
return err;
}
err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0); err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0);
if (err) if (err) {
__mlx4_counter_free(dev, index); __mlx4_counter_free(dev, index);
else mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
} else {
set_param_l(out_param, index); set_param_l(out_param, index);
}
return err; return err;
} }
...@@ -1864,6 +2002,7 @@ static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1864,6 +2002,7 @@ static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
err = rem_res_range(dev, slave, base, count, RES_QP, 0); err = rem_res_range(dev, slave, base, count, RES_QP, 0);
if (err) if (err)
break; break;
mlx4_release_resource(dev, slave, RES_QP, count, 0);
__mlx4_qp_release_range(dev, base, count); __mlx4_qp_release_range(dev, base, count);
break; break;
case RES_OP_MAP_ICM: case RES_OP_MAP_ICM:
...@@ -1901,8 +2040,10 @@ static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1901,8 +2040,10 @@ static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
base = get_param_l(&in_param); base = get_param_l(&in_param);
order = get_param_h(&in_param); order = get_param_h(&in_param);
err = rem_res_range(dev, slave, base, 1, RES_MTT, order); err = rem_res_range(dev, slave, base, 1, RES_MTT, order);
if (!err) if (!err) {
mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
__mlx4_free_mtt_range(dev, base, order); __mlx4_free_mtt_range(dev, base, order);
}
return err; return err;
} }
...@@ -1927,6 +2068,7 @@ static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1927,6 +2068,7 @@ static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);
if (err) if (err)
break; break;
mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
__mlx4_mpt_release(dev, index); __mlx4_mpt_release(dev, index);
break; break;
case RES_OP_MAP_ICM: case RES_OP_MAP_ICM:
...@@ -1961,6 +2103,7 @@ static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1961,6 +2103,7 @@ static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
if (err) if (err)
break; break;
mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
__mlx4_cq_free_icm(dev, cqn); __mlx4_cq_free_icm(dev, cqn);
break; break;
...@@ -1985,6 +2128,7 @@ static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1985,6 +2128,7 @@ static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
if (err) if (err)
break; break;
mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
__mlx4_srq_free_icm(dev, srqn); __mlx4_srq_free_icm(dev, srqn);
break; break;
...@@ -2056,6 +2200,7 @@ static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -2056,6 +2200,7 @@ static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err; return err;
__mlx4_counter_free(dev, index); __mlx4_counter_free(dev, index);
mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
return err; return err;
} }
...@@ -3785,6 +3930,11 @@ static void rem_slave_qps(struct mlx4_dev *dev, int slave) ...@@ -3785,6 +3930,11 @@ static void rem_slave_qps(struct mlx4_dev *dev, int slave)
&tracker->res_tree[RES_QP]); &tracker->res_tree[RES_QP]);
list_del(&qp->com.list); list_del(&qp->com.list);
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
if (!valid_reserved(dev, slave, qpn)) {
__mlx4_qp_release_range(dev, qpn, 1);
mlx4_release_resource(dev, slave,
RES_QP, 1, 0);
}
kfree(qp); kfree(qp);
state = 0; state = 0;
break; break;
...@@ -3856,6 +4006,8 @@ static void rem_slave_srqs(struct mlx4_dev *dev, int slave) ...@@ -3856,6 +4006,8 @@ static void rem_slave_srqs(struct mlx4_dev *dev, int slave)
&tracker->res_tree[RES_SRQ]); &tracker->res_tree[RES_SRQ]);
list_del(&srq->com.list); list_del(&srq->com.list);
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
mlx4_release_resource(dev, slave,
RES_SRQ, 1, 0);
kfree(srq); kfree(srq);
state = 0; state = 0;
break; break;
...@@ -3922,6 +4074,8 @@ static void rem_slave_cqs(struct mlx4_dev *dev, int slave) ...@@ -3922,6 +4074,8 @@ static void rem_slave_cqs(struct mlx4_dev *dev, int slave)
&tracker->res_tree[RES_CQ]); &tracker->res_tree[RES_CQ]);
list_del(&cq->com.list); list_del(&cq->com.list);
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
mlx4_release_resource(dev, slave,
RES_CQ, 1, 0);
kfree(cq); kfree(cq);
state = 0; state = 0;
break; break;
...@@ -3985,6 +4139,8 @@ static void rem_slave_mrs(struct mlx4_dev *dev, int slave) ...@@ -3985,6 +4139,8 @@ static void rem_slave_mrs(struct mlx4_dev *dev, int slave)
&tracker->res_tree[RES_MPT]); &tracker->res_tree[RES_MPT]);
list_del(&mpt->com.list); list_del(&mpt->com.list);
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
mlx4_release_resource(dev, slave,
RES_MPT, 1, 0);
kfree(mpt); kfree(mpt);
state = 0; state = 0;
break; break;
...@@ -4054,6 +4210,8 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave) ...@@ -4054,6 +4210,8 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
&tracker->res_tree[RES_MTT]); &tracker->res_tree[RES_MTT]);
list_del(&mtt->com.list); list_del(&mtt->com.list);
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
mlx4_release_resource(dev, slave, RES_MTT,
1 << mtt->order, 0);
kfree(mtt); kfree(mtt);
state = 0; state = 0;
break; break;
...@@ -4212,6 +4370,7 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave) ...@@ -4212,6 +4370,7 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave)
list_del(&counter->com.list); list_del(&counter->com.list);
kfree(counter); kfree(counter);
__mlx4_counter_free(dev, index); __mlx4_counter_free(dev, index);
mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
} }
} }
spin_unlock_irq(mlx4_tlock(dev)); spin_unlock_irq(mlx4_tlock(dev));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment