mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-22 09:19:56 +07:00
Merge branch 'mlx4-next'
Or Gerlitz says: ==================== mlx4 driver update This series from Matan, Jenny, Dotan and myself is mostly about adding support to a new performance optimized flow steering mode (patches 4-10). The 1st two patches are small fixes (one for VXLAN and one for SRIOV), and the third patch is a fix to avoid hard-lockup situation when many (hunderds) processes holding user-space QPs/CQs get events. Matan and Or. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
efef793926
@ -233,7 +233,10 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_dbmap;
|
goto err_dbmap;
|
||||||
|
|
||||||
cq->mcq.comp = mlx4_ib_cq_comp;
|
if (context)
|
||||||
|
cq->mcq.tasklet_ctx.comp = mlx4_ib_cq_comp;
|
||||||
|
else
|
||||||
|
cq->mcq.comp = mlx4_ib_cq_comp;
|
||||||
cq->mcq.event = mlx4_ib_cq_event;
|
cq->mcq.event = mlx4_ib_cq_event;
|
||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
|
@ -2227,7 +2227,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||||||
ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
|
ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
|
||||||
err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
|
err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
|
||||||
MLX4_IB_UC_STEER_QPN_ALIGN,
|
MLX4_IB_UC_STEER_QPN_ALIGN,
|
||||||
&ibdev->steer_qpn_base);
|
&ibdev->steer_qpn_base, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_counter;
|
goto err_counter;
|
||||||
|
|
||||||
|
@ -802,16 +802,21 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Raw packet QPNs must be aligned to 8 bits. If not, the WQE
|
/* Raw packet QPNs may not have bits 6,7 set in their qp_num;
|
||||||
* BlueFlame setup flow wrongly causes VLAN insertion. */
|
* otherwise, the WQE BlueFlame setup flow wrongly causes
|
||||||
|
* VLAN insertion. */
|
||||||
if (init_attr->qp_type == IB_QPT_RAW_PACKET)
|
if (init_attr->qp_type == IB_QPT_RAW_PACKET)
|
||||||
err = mlx4_qp_reserve_range(dev->dev, 1, 1 << 8, &qpn);
|
err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn,
|
||||||
|
(init_attr->cap.max_send_wr ?
|
||||||
|
MLX4_RESERVE_ETH_BF_QP : 0) |
|
||||||
|
(init_attr->cap.max_recv_wr ?
|
||||||
|
MLX4_RESERVE_A0_QP : 0));
|
||||||
else
|
else
|
||||||
if (qp->flags & MLX4_IB_QP_NETIF)
|
if (qp->flags & MLX4_IB_QP_NETIF)
|
||||||
err = mlx4_ib_steer_qp_alloc(dev, 1, &qpn);
|
err = mlx4_ib_steer_qp_alloc(dev, 1, &qpn);
|
||||||
else
|
else
|
||||||
err = mlx4_qp_reserve_range(dev->dev, 1, 1,
|
err = mlx4_qp_reserve_range(dev->dev, 1, 1,
|
||||||
&qpn);
|
&qpn, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_proxy;
|
goto err_proxy;
|
||||||
}
|
}
|
||||||
|
@ -76,22 +76,53 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr)
|
|||||||
mlx4_bitmap_free_range(bitmap, obj, 1, use_rr);
|
mlx4_bitmap_free_range(bitmap, obj, 1, use_rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
|
static unsigned long find_aligned_range(unsigned long *bitmap,
|
||||||
|
u32 start, u32 nbits,
|
||||||
|
int len, int align, u32 skip_mask)
|
||||||
|
{
|
||||||
|
unsigned long end, i;
|
||||||
|
|
||||||
|
again:
|
||||||
|
start = ALIGN(start, align);
|
||||||
|
|
||||||
|
while ((start < nbits) && (test_bit(start, bitmap) ||
|
||||||
|
(start & skip_mask)))
|
||||||
|
start += align;
|
||||||
|
|
||||||
|
if (start >= nbits)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
end = start+len;
|
||||||
|
if (end > nbits)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = start + 1; i < end; i++) {
|
||||||
|
if (test_bit(i, bitmap) || ((u32)i & skip_mask)) {
|
||||||
|
start = i + 1;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt,
|
||||||
|
int align, u32 skip_mask)
|
||||||
{
|
{
|
||||||
u32 obj;
|
u32 obj;
|
||||||
|
|
||||||
if (likely(cnt == 1 && align == 1))
|
if (likely(cnt == 1 && align == 1 && !skip_mask))
|
||||||
return mlx4_bitmap_alloc(bitmap);
|
return mlx4_bitmap_alloc(bitmap);
|
||||||
|
|
||||||
spin_lock(&bitmap->lock);
|
spin_lock(&bitmap->lock);
|
||||||
|
|
||||||
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
|
obj = find_aligned_range(bitmap->table, bitmap->last,
|
||||||
bitmap->last, cnt, align - 1);
|
bitmap->max, cnt, align, skip_mask);
|
||||||
if (obj >= bitmap->max) {
|
if (obj >= bitmap->max) {
|
||||||
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
|
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
|
||||||
& bitmap->mask;
|
& bitmap->mask;
|
||||||
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
|
obj = find_aligned_range(bitmap->table, 0, bitmap->max,
|
||||||
0, cnt, align - 1);
|
cnt, align, skip_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj < bitmap->max) {
|
if (obj < bitmap->max) {
|
||||||
@ -118,6 +149,11 @@ u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap)
|
|||||||
return bitmap->avail;
|
return bitmap->avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 mlx4_bitmap_masked_value(struct mlx4_bitmap *bitmap, u32 obj)
|
||||||
|
{
|
||||||
|
return obj & (bitmap->max + bitmap->reserved_top - 1);
|
||||||
|
}
|
||||||
|
|
||||||
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt,
|
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt,
|
||||||
int use_rr)
|
int use_rr)
|
||||||
{
|
{
|
||||||
@ -147,6 +183,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
|
|||||||
bitmap->mask = mask;
|
bitmap->mask = mask;
|
||||||
bitmap->reserved_top = reserved_top;
|
bitmap->reserved_top = reserved_top;
|
||||||
bitmap->avail = num - reserved_top - reserved_bot;
|
bitmap->avail = num - reserved_top - reserved_bot;
|
||||||
|
bitmap->effective_len = bitmap->avail;
|
||||||
spin_lock_init(&bitmap->lock);
|
spin_lock_init(&bitmap->lock);
|
||||||
bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) *
|
bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) *
|
||||||
sizeof (long), GFP_KERNEL);
|
sizeof (long), GFP_KERNEL);
|
||||||
@ -163,6 +200,382 @@ void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
|
|||||||
kfree(bitmap->table);
|
kfree(bitmap->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mlx4_zone_allocator {
|
||||||
|
struct list_head entries;
|
||||||
|
struct list_head prios;
|
||||||
|
u32 last_uid;
|
||||||
|
u32 mask;
|
||||||
|
/* protect the zone_allocator from concurrent accesses */
|
||||||
|
spinlock_t lock;
|
||||||
|
enum mlx4_zone_alloc_flags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx4_zone_entry {
|
||||||
|
struct list_head list;
|
||||||
|
struct list_head prio_list;
|
||||||
|
u32 uid;
|
||||||
|
struct mlx4_zone_allocator *allocator;
|
||||||
|
struct mlx4_bitmap *bitmap;
|
||||||
|
int use_rr;
|
||||||
|
int priority;
|
||||||
|
int offset;
|
||||||
|
enum mlx4_zone_flags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx4_zone_allocator *mlx4_zone_allocator_create(enum mlx4_zone_alloc_flags flags)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_allocator *zones = kmalloc(sizeof(*zones), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (NULL == zones)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&zones->entries);
|
||||||
|
INIT_LIST_HEAD(&zones->prios);
|
||||||
|
spin_lock_init(&zones->lock);
|
||||||
|
zones->last_uid = 0;
|
||||||
|
zones->mask = 0;
|
||||||
|
zones->flags = flags;
|
||||||
|
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mlx4_zone_add_one(struct mlx4_zone_allocator *zone_alloc,
|
||||||
|
struct mlx4_bitmap *bitmap,
|
||||||
|
u32 flags,
|
||||||
|
int priority,
|
||||||
|
int offset,
|
||||||
|
u32 *puid)
|
||||||
|
{
|
||||||
|
u32 mask = mlx4_bitmap_masked_value(bitmap, (u32)-1);
|
||||||
|
struct mlx4_zone_entry *it;
|
||||||
|
struct mlx4_zone_entry *zone = kmalloc(sizeof(*zone), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (NULL == zone)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
zone->flags = flags;
|
||||||
|
zone->bitmap = bitmap;
|
||||||
|
zone->use_rr = (flags & MLX4_ZONE_USE_RR) ? MLX4_USE_RR : 0;
|
||||||
|
zone->priority = priority;
|
||||||
|
zone->offset = offset;
|
||||||
|
|
||||||
|
spin_lock(&zone_alloc->lock);
|
||||||
|
|
||||||
|
zone->uid = zone_alloc->last_uid++;
|
||||||
|
zone->allocator = zone_alloc;
|
||||||
|
|
||||||
|
if (zone_alloc->mask < mask)
|
||||||
|
zone_alloc->mask = mask;
|
||||||
|
|
||||||
|
list_for_each_entry(it, &zone_alloc->prios, prio_list)
|
||||||
|
if (it->priority >= priority)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (&it->prio_list == &zone_alloc->prios || it->priority > priority)
|
||||||
|
list_add_tail(&zone->prio_list, &it->prio_list);
|
||||||
|
list_add_tail(&zone->list, &it->list);
|
||||||
|
|
||||||
|
spin_unlock(&zone_alloc->lock);
|
||||||
|
|
||||||
|
*puid = zone->uid;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called under a lock */
|
||||||
|
static int __mlx4_zone_remove_one_entry(struct mlx4_zone_entry *entry)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_allocator *zone_alloc = entry->allocator;
|
||||||
|
|
||||||
|
if (!list_empty(&entry->prio_list)) {
|
||||||
|
/* Check if we need to add an alternative node to the prio list */
|
||||||
|
if (!list_is_last(&entry->list, &zone_alloc->entries)) {
|
||||||
|
struct mlx4_zone_entry *next = list_first_entry(&entry->list,
|
||||||
|
typeof(*next),
|
||||||
|
list);
|
||||||
|
|
||||||
|
if (next->priority == entry->priority)
|
||||||
|
list_add_tail(&next->prio_list, &entry->prio_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&entry->prio_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&entry->list);
|
||||||
|
|
||||||
|
if (zone_alloc->flags & MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP) {
|
||||||
|
u32 mask = 0;
|
||||||
|
struct mlx4_zone_entry *it;
|
||||||
|
|
||||||
|
list_for_each_entry(it, &zone_alloc->prios, prio_list) {
|
||||||
|
u32 cur_mask = mlx4_bitmap_masked_value(it->bitmap, (u32)-1);
|
||||||
|
|
||||||
|
if (mask < cur_mask)
|
||||||
|
mask = cur_mask;
|
||||||
|
}
|
||||||
|
zone_alloc->mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx4_zone_allocator_destroy(struct mlx4_zone_allocator *zone_alloc)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone, *tmp;
|
||||||
|
|
||||||
|
spin_lock(&zone_alloc->lock);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(zone, tmp, &zone_alloc->entries, list) {
|
||||||
|
list_del(&zone->list);
|
||||||
|
list_del(&zone->prio_list);
|
||||||
|
kfree(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&zone_alloc->lock);
|
||||||
|
kfree(zone_alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called under a lock */
|
||||||
|
static u32 __mlx4_alloc_from_zone(struct mlx4_zone_entry *zone, int count,
|
||||||
|
int align, u32 skip_mask, u32 *puid)
|
||||||
|
{
|
||||||
|
u32 uid;
|
||||||
|
u32 res;
|
||||||
|
struct mlx4_zone_allocator *zone_alloc = zone->allocator;
|
||||||
|
struct mlx4_zone_entry *curr_node;
|
||||||
|
|
||||||
|
res = mlx4_bitmap_alloc_range(zone->bitmap, count,
|
||||||
|
align, skip_mask);
|
||||||
|
|
||||||
|
if (res != (u32)-1) {
|
||||||
|
res += zone->offset;
|
||||||
|
uid = zone->uid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(curr_node, &zone_alloc->prios, prio_list) {
|
||||||
|
if (unlikely(curr_node->priority == zone->priority))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone->flags & MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO) {
|
||||||
|
struct mlx4_zone_entry *it = curr_node;
|
||||||
|
|
||||||
|
list_for_each_entry_continue_reverse(it, &zone_alloc->entries, list) {
|
||||||
|
res = mlx4_bitmap_alloc_range(it->bitmap, count,
|
||||||
|
align, skip_mask);
|
||||||
|
if (res != (u32)-1) {
|
||||||
|
res += it->offset;
|
||||||
|
uid = it->uid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone->flags & MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO) {
|
||||||
|
struct mlx4_zone_entry *it = curr_node;
|
||||||
|
|
||||||
|
list_for_each_entry_from(it, &zone_alloc->entries, list) {
|
||||||
|
if (unlikely(it == zone))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (unlikely(it->priority != curr_node->priority))
|
||||||
|
break;
|
||||||
|
|
||||||
|
res = mlx4_bitmap_alloc_range(it->bitmap, count,
|
||||||
|
align, skip_mask);
|
||||||
|
if (res != (u32)-1) {
|
||||||
|
res += it->offset;
|
||||||
|
uid = it->uid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone->flags & MLX4_ZONE_FALLBACK_TO_HIGHER_PRIO) {
|
||||||
|
if (list_is_last(&curr_node->prio_list, &zone_alloc->prios))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
curr_node = list_first_entry(&curr_node->prio_list,
|
||||||
|
typeof(*curr_node),
|
||||||
|
prio_list);
|
||||||
|
|
||||||
|
list_for_each_entry_from(curr_node, &zone_alloc->entries, list) {
|
||||||
|
res = mlx4_bitmap_alloc_range(curr_node->bitmap, count,
|
||||||
|
align, skip_mask);
|
||||||
|
if (res != (u32)-1) {
|
||||||
|
res += curr_node->offset;
|
||||||
|
uid = curr_node->uid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (NULL != puid && res != (u32)-1)
|
||||||
|
*puid = uid;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called under a lock */
|
||||||
|
static void __mlx4_free_from_zone(struct mlx4_zone_entry *zone, u32 obj,
|
||||||
|
u32 count)
|
||||||
|
{
|
||||||
|
mlx4_bitmap_free_range(zone->bitmap, obj - zone->offset, count, zone->use_rr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called under a lock */
|
||||||
|
static struct mlx4_zone_entry *__mlx4_find_zone_by_uid(
|
||||||
|
struct mlx4_zone_allocator *zones, u32 uid)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
|
||||||
|
list_for_each_entry(zone, &zones->entries, list) {
|
||||||
|
if (zone->uid == uid)
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mlx4_bitmap *mlx4_zone_get_bitmap(struct mlx4_zone_allocator *zones, u32 uid)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
struct mlx4_bitmap *bitmap;
|
||||||
|
|
||||||
|
spin_lock(&zones->lock);
|
||||||
|
|
||||||
|
zone = __mlx4_find_zone_by_uid(zones, uid);
|
||||||
|
|
||||||
|
bitmap = zone == NULL ? NULL : zone->bitmap;
|
||||||
|
|
||||||
|
spin_unlock(&zones->lock);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mlx4_zone_remove_one(struct mlx4_zone_allocator *zones, u32 uid)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
spin_lock(&zones->lock);
|
||||||
|
|
||||||
|
zone = __mlx4_find_zone_by_uid(zones, uid);
|
||||||
|
|
||||||
|
if (NULL == zone) {
|
||||||
|
res = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = __mlx4_zone_remove_one_entry(zone);
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&zones->lock);
|
||||||
|
kfree(zone);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should be called under a lock */
|
||||||
|
static struct mlx4_zone_entry *__mlx4_find_zone_by_uid_unique(
|
||||||
|
struct mlx4_zone_allocator *zones, u32 obj)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone, *zone_candidate = NULL;
|
||||||
|
u32 dist = (u32)-1;
|
||||||
|
|
||||||
|
/* Search for the smallest zone that this obj could be
|
||||||
|
* allocated from. This is done in order to handle
|
||||||
|
* situations when small bitmaps are allocated from bigger
|
||||||
|
* bitmaps (and the allocated space is marked as reserved in
|
||||||
|
* the bigger bitmap.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(zone, &zones->entries, list) {
|
||||||
|
if (obj >= zone->offset) {
|
||||||
|
u32 mobj = (obj - zone->offset) & zones->mask;
|
||||||
|
|
||||||
|
if (mobj < zone->bitmap->max) {
|
||||||
|
u32 curr_dist = zone->bitmap->effective_len;
|
||||||
|
|
||||||
|
if (curr_dist < dist) {
|
||||||
|
dist = curr_dist;
|
||||||
|
zone_candidate = zone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone_candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 mlx4_zone_alloc_entries(struct mlx4_zone_allocator *zones, u32 uid, int count,
|
||||||
|
int align, u32 skip_mask, u32 *puid)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
spin_lock(&zones->lock);
|
||||||
|
|
||||||
|
zone = __mlx4_find_zone_by_uid(zones, uid);
|
||||||
|
|
||||||
|
if (NULL == zone)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
res = __mlx4_alloc_from_zone(zone, count, align, skip_mask, puid);
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&zones->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 mlx4_zone_free_entries(struct mlx4_zone_allocator *zones, u32 uid, u32 obj, u32 count)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
spin_lock(&zones->lock);
|
||||||
|
|
||||||
|
zone = __mlx4_find_zone_by_uid(zones, uid);
|
||||||
|
|
||||||
|
if (NULL == zone) {
|
||||||
|
res = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
__mlx4_free_from_zone(zone, obj, count);
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&zones->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 mlx4_zone_free_entries_unique(struct mlx4_zone_allocator *zones, u32 obj, u32 count)
|
||||||
|
{
|
||||||
|
struct mlx4_zone_entry *zone;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!(zones->flags & MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
spin_lock(&zones->lock);
|
||||||
|
|
||||||
|
zone = __mlx4_find_zone_by_uid_unique(zones, obj);
|
||||||
|
|
||||||
|
if (NULL == zone) {
|
||||||
|
res = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
__mlx4_free_from_zone(zone, obj, count);
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&zones->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Handling for queue buffers -- we allocate a bunch of memory and
|
* Handling for queue buffers -- we allocate a bunch of memory and
|
||||||
* register it in a memory region at HCA virtual address 0. If the
|
* register it in a memory region at HCA virtual address 0. If the
|
||||||
|
@ -52,6 +52,51 @@
|
|||||||
#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8)
|
#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8)
|
||||||
#define MLX4_EQ_STATE_FIRED (10 << 8)
|
#define MLX4_EQ_STATE_FIRED (10 << 8)
|
||||||
|
|
||||||
|
#define TASKLET_MAX_TIME 2
|
||||||
|
#define TASKLET_MAX_TIME_JIFFIES msecs_to_jiffies(TASKLET_MAX_TIME)
|
||||||
|
|
||||||
|
void mlx4_cq_tasklet_cb(unsigned long data)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned long end = jiffies + TASKLET_MAX_TIME_JIFFIES;
|
||||||
|
struct mlx4_eq_tasklet *ctx = (struct mlx4_eq_tasklet *)data;
|
||||||
|
struct mlx4_cq *mcq, *temp;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ctx->lock, flags);
|
||||||
|
list_splice_tail_init(&ctx->list, &ctx->process_list);
|
||||||
|
spin_unlock_irqrestore(&ctx->lock, flags);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mcq, temp, &ctx->process_list, tasklet_ctx.list) {
|
||||||
|
list_del_init(&mcq->tasklet_ctx.list);
|
||||||
|
mcq->tasklet_ctx.comp(mcq);
|
||||||
|
if (atomic_dec_and_test(&mcq->refcount))
|
||||||
|
complete(&mcq->free);
|
||||||
|
if (time_after(jiffies, end))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&ctx->process_list))
|
||||||
|
tasklet_schedule(&ctx->task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx4_add_cq_to_tasklet(struct mlx4_cq *cq)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct mlx4_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tasklet_ctx->lock, flags);
|
||||||
|
/* When migrating CQs between EQs will be implemented, please note
|
||||||
|
* that you need to sync this point. It is possible that
|
||||||
|
* while migrating a CQ, completions on the old EQs could
|
||||||
|
* still arrive.
|
||||||
|
*/
|
||||||
|
if (list_empty_careful(&cq->tasklet_ctx.list)) {
|
||||||
|
atomic_inc(&cq->refcount);
|
||||||
|
list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn)
|
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn)
|
||||||
{
|
{
|
||||||
struct mlx4_cq *cq;
|
struct mlx4_cq *cq;
|
||||||
@ -292,6 +337,11 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
|
|||||||
cq->uar = uar;
|
cq->uar = uar;
|
||||||
atomic_set(&cq->refcount, 1);
|
atomic_set(&cq->refcount, 1);
|
||||||
init_completion(&cq->free);
|
init_completion(&cq->free);
|
||||||
|
cq->comp = mlx4_add_cq_to_tasklet;
|
||||||
|
cq->tasklet_ctx.priv =
|
||||||
|
&priv->eq_table.eq[cq->vector].tasklet_ctx;
|
||||||
|
INIT_LIST_HEAD(&cq->tasklet_ctx.list);
|
||||||
|
|
||||||
|
|
||||||
cq->irq = priv->eq_table.eq[cq->vector].irq;
|
cq->irq = priv->eq_table.eq[cq->vector].irq;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -595,7 +595,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
|
err = mlx4_qp_reserve_range(dev, 1, 1, qpn, MLX4_RESERVE_A0_QP);
|
||||||
en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
|
en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
|
||||||
if (err) {
|
if (err) {
|
||||||
en_err(priv, "Failed to reserve qp for mac registration\n");
|
en_err(priv, "Failed to reserve qp for mac registration\n");
|
||||||
@ -1974,15 +1974,8 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
|
|||||||
{
|
{
|
||||||
struct mlx4_en_port_profile *prof = priv->prof;
|
struct mlx4_en_port_profile *prof = priv->prof;
|
||||||
int i;
|
int i;
|
||||||
int err;
|
|
||||||
int node;
|
int node;
|
||||||
|
|
||||||
err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &priv->base_tx_qpn);
|
|
||||||
if (err) {
|
|
||||||
en_err(priv, "failed reserving range for TX rings\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create tx Rings */
|
/* Create tx Rings */
|
||||||
for (i = 0; i < priv->tx_ring_num; i++) {
|
for (i = 0; i < priv->tx_ring_num; i++) {
|
||||||
node = cpu_to_node(i % num_online_cpus());
|
node = cpu_to_node(i % num_online_cpus());
|
||||||
@ -1991,7 +1984,6 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i],
|
if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i],
|
||||||
priv->base_tx_qpn + i,
|
|
||||||
prof->tx_ring_size, TXBB_SIZE,
|
prof->tx_ring_size, TXBB_SIZE,
|
||||||
node, i))
|
node, i))
|
||||||
goto err;
|
goto err;
|
||||||
@ -2602,7 +2594,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
|
|||||||
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
|
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
|
||||||
|
|
||||||
if (mdev->dev->caps.steering_mode ==
|
if (mdev->dev->caps.steering_mode ==
|
||||||
MLX4_STEERING_MODE_DEVICE_MANAGED)
|
MLX4_STEERING_MODE_DEVICE_MANAGED &&
|
||||||
|
mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC)
|
||||||
dev->hw_features |= NETIF_F_NTUPLE;
|
dev->hw_features |= NETIF_F_NTUPLE;
|
||||||
|
|
||||||
if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
|
if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
|
||||||
|
@ -888,7 +888,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
|
|||||||
gro_skb->ip_summed = ip_summed;
|
gro_skb->ip_summed = ip_summed;
|
||||||
|
|
||||||
if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
|
if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
|
||||||
gro_skb->encapsulation = 1;
|
gro_skb->csum_level = 1;
|
||||||
|
|
||||||
if ((cqe->vlan_my_qpn &
|
if ((cqe->vlan_my_qpn &
|
||||||
cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
|
cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
|
||||||
(dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
|
(dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
|
||||||
@ -1130,7 +1131,8 @@ int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv)
|
|||||||
int err;
|
int err;
|
||||||
u32 qpn;
|
u32 qpn;
|
||||||
|
|
||||||
err = mlx4_qp_reserve_range(priv->mdev->dev, 1, 1, &qpn);
|
err = mlx4_qp_reserve_range(priv->mdev->dev, 1, 1, &qpn,
|
||||||
|
MLX4_RESERVE_A0_QP);
|
||||||
if (err) {
|
if (err) {
|
||||||
en_err(priv, "Failed reserving drop qpn\n");
|
en_err(priv, "Failed reserving drop qpn\n");
|
||||||
return err;
|
return err;
|
||||||
@ -1173,7 +1175,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
|
|||||||
en_dbg(DRV, priv, "Configuring rss steering\n");
|
en_dbg(DRV, priv, "Configuring rss steering\n");
|
||||||
err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num,
|
err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num,
|
||||||
priv->rx_ring_num,
|
priv->rx_ring_num,
|
||||||
&rss_map->base_qpn);
|
&rss_map->base_qpn, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num);
|
en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num);
|
||||||
return err;
|
return err;
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
#include "mlx4_en.h"
|
#include "mlx4_en.h"
|
||||||
|
|
||||||
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
||||||
struct mlx4_en_tx_ring **pring, int qpn, u32 size,
|
struct mlx4_en_tx_ring **pring, u32 size,
|
||||||
u16 stride, int node, int queue_index)
|
u16 stride, int node, int queue_index)
|
||||||
{
|
{
|
||||||
struct mlx4_en_dev *mdev = priv->mdev;
|
struct mlx4_en_dev *mdev = priv->mdev;
|
||||||
@ -112,11 +112,17 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
|||||||
ring, ring->buf, ring->size, ring->buf_size,
|
ring, ring->buf, ring->size, ring->buf_size,
|
||||||
(unsigned long long) ring->wqres.buf.direct.map);
|
(unsigned long long) ring->wqres.buf.direct.map);
|
||||||
|
|
||||||
ring->qpn = qpn;
|
err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn,
|
||||||
|
MLX4_RESERVE_ETH_BF_QP);
|
||||||
|
if (err) {
|
||||||
|
en_err(priv, "failed reserving qp for TX ring\n");
|
||||||
|
goto err_map;
|
||||||
|
}
|
||||||
|
|
||||||
err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp, GFP_KERNEL);
|
err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp, GFP_KERNEL);
|
||||||
if (err) {
|
if (err) {
|
||||||
en_err(priv, "Failed allocating qp %d\n", ring->qpn);
|
en_err(priv, "Failed allocating qp %d\n", ring->qpn);
|
||||||
goto err_map;
|
goto err_reserve;
|
||||||
}
|
}
|
||||||
ring->qp.event = mlx4_en_sqp_event;
|
ring->qp.event = mlx4_en_sqp_event;
|
||||||
|
|
||||||
@ -143,6 +149,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
|||||||
*pring = ring;
|
*pring = ring;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_reserve:
|
||||||
|
mlx4_qp_release_range(mdev->dev, ring->qpn, 1);
|
||||||
err_map:
|
err_map:
|
||||||
mlx4_en_unmap_buffer(&ring->wqres.buf);
|
mlx4_en_unmap_buffer(&ring->wqres.buf);
|
||||||
err_hwq_res:
|
err_hwq_res:
|
||||||
|
@ -450,7 +450,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
|
|||||||
{
|
{
|
||||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||||
struct mlx4_eqe *eqe;
|
struct mlx4_eqe *eqe;
|
||||||
int cqn;
|
int cqn = -1;
|
||||||
int eqes_found = 0;
|
int eqes_found = 0;
|
||||||
int set_ci = 0;
|
int set_ci = 0;
|
||||||
int port;
|
int port;
|
||||||
@ -758,6 +758,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
|
|||||||
|
|
||||||
eq_set_ci(eq, 1);
|
eq_set_ci(eq, 1);
|
||||||
|
|
||||||
|
/* cqn is 24bit wide but is initialized such that its higher bits
|
||||||
|
* are ones too. Thus, if we got any event, cqn's high bits should be off
|
||||||
|
* and we need to schedule the tasklet.
|
||||||
|
*/
|
||||||
|
if (!(cqn & ~0xffffff))
|
||||||
|
tasklet_schedule(&eq->tasklet_ctx.task);
|
||||||
|
|
||||||
return eqes_found;
|
return eqes_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,6 +978,12 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
|
|||||||
|
|
||||||
eq->cons_index = 0;
|
eq->cons_index = 0;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&eq->tasklet_ctx.list);
|
||||||
|
INIT_LIST_HEAD(&eq->tasklet_ctx.process_list);
|
||||||
|
spin_lock_init(&eq->tasklet_ctx.lock);
|
||||||
|
tasklet_init(&eq->tasklet_ctx.task, mlx4_cq_tasklet_cb,
|
||||||
|
(unsigned long)&eq->tasklet_ctx);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err_out_free_mtt:
|
err_out_free_mtt:
|
||||||
@ -1027,6 +1040,7 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronize_irq(eq->irq);
|
synchronize_irq(eq->irq);
|
||||||
|
tasklet_disable(&eq->tasklet_ctx.task);
|
||||||
|
|
||||||
mlx4_mtt_cleanup(dev, &eq->mtt);
|
mlx4_mtt_cleanup(dev, &eq->mtt);
|
||||||
for (i = 0; i < npages; ++i)
|
for (i = 0; i < npages; ++i)
|
||||||
|
@ -144,7 +144,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
|
|||||||
[15] = "Ethernet Backplane autoneg support",
|
[15] = "Ethernet Backplane autoneg support",
|
||||||
[16] = "CONFIG DEV support",
|
[16] = "CONFIG DEV support",
|
||||||
[17] = "Asymmetric EQs support",
|
[17] = "Asymmetric EQs support",
|
||||||
[18] = "More than 80 VFs support"
|
[18] = "More than 80 VFs support",
|
||||||
|
[19] = "Performance optimized for limited rule configuration flow steering support"
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -266,10 +267,16 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET 0x64
|
#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET 0x64
|
||||||
#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET 0x68
|
#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET 0x68
|
||||||
|
|
||||||
|
#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET 0x6c
|
||||||
|
|
||||||
#define QUERY_FUNC_CAP_FMR_FLAG 0x80
|
#define QUERY_FUNC_CAP_FMR_FLAG 0x80
|
||||||
#define QUERY_FUNC_CAP_FLAG_RDMA 0x40
|
#define QUERY_FUNC_CAP_FLAG_RDMA 0x40
|
||||||
#define QUERY_FUNC_CAP_FLAG_ETH 0x80
|
#define QUERY_FUNC_CAP_FLAG_ETH 0x80
|
||||||
#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10
|
#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10
|
||||||
|
#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX 0x04
|
||||||
|
|
||||||
|
#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG (1UL << 31)
|
||||||
|
#define QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG (1UL << 30)
|
||||||
|
|
||||||
/* when opcode modifier = 1 */
|
/* when opcode modifier = 1 */
|
||||||
#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3
|
#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3
|
||||||
@ -339,7 +346,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
mlx4_get_active_ports(dev, slave);
|
mlx4_get_active_ports(dev, slave);
|
||||||
/* enable rdma and ethernet interfaces, and new quota locations */
|
/* enable rdma and ethernet interfaces, and new quota locations */
|
||||||
field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
|
field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
|
||||||
QUERY_FUNC_CAP_FLAG_QUOTAS);
|
QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX);
|
||||||
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
|
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
|
||||||
|
|
||||||
field = min(
|
field = min(
|
||||||
@ -401,6 +408,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
|
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
|
||||||
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
|
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
|
||||||
|
|
||||||
|
size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG |
|
||||||
|
QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG;
|
||||||
|
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
|
||||||
} else
|
} else
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
@ -493,6 +503,19 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
|
|||||||
MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
|
MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
|
||||||
func_cap->reserved_eq = size & 0xFFFFFF;
|
func_cap->reserved_eq = size & 0xFFFFFF;
|
||||||
|
|
||||||
|
func_cap->extra_flags = 0;
|
||||||
|
|
||||||
|
/* Mailbox data from 0x6c and onward should only be treated if
|
||||||
|
* QUERY_FUNC_CAP_FLAG_VALID_MAILBOX is set in func_cap->flags
|
||||||
|
*/
|
||||||
|
if (func_cap->flags & QUERY_FUNC_CAP_FLAG_VALID_MAILBOX) {
|
||||||
|
MLX4_GET(size, outbox, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
|
||||||
|
if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG)
|
||||||
|
func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_BF_RES_QP;
|
||||||
|
if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG)
|
||||||
|
func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_A0_RES_QP;
|
||||||
|
}
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,6 +681,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
#define QUERY_DEV_CAP_FW_REASSIGN_MAC 0x9d
|
#define QUERY_DEV_CAP_FW_REASSIGN_MAC 0x9d
|
||||||
#define QUERY_DEV_CAP_VXLAN 0x9e
|
#define QUERY_DEV_CAP_VXLAN 0x9e
|
||||||
#define QUERY_DEV_CAP_MAD_DEMUX_OFFSET 0xb0
|
#define QUERY_DEV_CAP_MAD_DEMUX_OFFSET 0xb0
|
||||||
|
#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET 0xa8
|
||||||
|
#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET 0xac
|
||||||
|
|
||||||
dev_cap->flags2 = 0;
|
dev_cap->flags2 = 0;
|
||||||
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
||||||
@ -854,6 +879,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
if (field32 & (1 << 0))
|
if (field32 & (1 << 0))
|
||||||
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_MAD_DEMUX;
|
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_MAD_DEMUX;
|
||||||
|
|
||||||
|
MLX4_GET(dev_cap->dmfs_high_rate_qpn_base, outbox,
|
||||||
|
QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET);
|
||||||
|
dev_cap->dmfs_high_rate_qpn_base &= MGM_QPN_MASK;
|
||||||
|
MLX4_GET(dev_cap->dmfs_high_rate_qpn_range, outbox,
|
||||||
|
QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET);
|
||||||
|
dev_cap->dmfs_high_rate_qpn_range &= MGM_QPN_MASK;
|
||||||
|
|
||||||
MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
|
MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
|
||||||
if (field32 & (1 << 16))
|
if (field32 & (1 << 16))
|
||||||
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
|
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
|
||||||
@ -864,61 +896,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
if (field32 & (1 << 21))
|
if (field32 & (1 << 21))
|
||||||
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS;
|
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS;
|
||||||
|
|
||||||
if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
|
for (i = 1; i <= dev_cap->num_ports; i++) {
|
||||||
for (i = 1; i <= dev_cap->num_ports; ++i) {
|
err = mlx4_QUERY_PORT(dev, i, dev_cap->port_cap + i);
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
|
if (err)
|
||||||
dev_cap->max_vl[i] = field >> 4;
|
goto out;
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
|
|
||||||
dev_cap->ib_mtu[i] = field >> 4;
|
|
||||||
dev_cap->max_port_width[i] = field & 0xf;
|
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
|
|
||||||
dev_cap->max_gids[i] = 1 << (field & 0xf);
|
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
|
|
||||||
dev_cap->max_pkeys[i] = 1 << (field & 0xf);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00
|
|
||||||
#define QUERY_PORT_MTU_OFFSET 0x01
|
|
||||||
#define QUERY_PORT_ETH_MTU_OFFSET 0x02
|
|
||||||
#define QUERY_PORT_WIDTH_OFFSET 0x06
|
|
||||||
#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07
|
|
||||||
#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a
|
|
||||||
#define QUERY_PORT_MAX_VL_OFFSET 0x0b
|
|
||||||
#define QUERY_PORT_MAC_OFFSET 0x10
|
|
||||||
#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18
|
|
||||||
#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c
|
|
||||||
#define QUERY_PORT_TRANS_CODE_OFFSET 0x20
|
|
||||||
|
|
||||||
for (i = 1; i <= dev_cap->num_ports; ++i) {
|
|
||||||
err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
|
|
||||||
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
|
|
||||||
dev_cap->supported_port_types[i] = field & 3;
|
|
||||||
dev_cap->suggested_type[i] = (field >> 3) & 1;
|
|
||||||
dev_cap->default_sense[i] = (field >> 4) & 1;
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
|
|
||||||
dev_cap->ib_mtu[i] = field & 0xf;
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
|
|
||||||
dev_cap->max_port_width[i] = field & 0xf;
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
|
|
||||||
dev_cap->max_gids[i] = 1 << (field >> 4);
|
|
||||||
dev_cap->max_pkeys[i] = 1 << (field & 0xf);
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
|
|
||||||
dev_cap->max_vl[i] = field & 0xf;
|
|
||||||
MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
|
|
||||||
dev_cap->log_max_macs[i] = field & 0xf;
|
|
||||||
dev_cap->log_max_vlans[i] = field >> 4;
|
|
||||||
MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
|
|
||||||
MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
|
|
||||||
MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
|
|
||||||
dev_cap->trans_type[i] = field32 >> 24;
|
|
||||||
dev_cap->vendor_oui[i] = field32 & 0xffffff;
|
|
||||||
MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
|
|
||||||
MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
|
mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
|
||||||
@ -955,8 +936,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
|
mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
|
||||||
dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
|
dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
|
||||||
mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
|
mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
|
||||||
dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
|
dev_cap->local_ca_ack_delay, 128 << dev_cap->port_cap[1].ib_mtu,
|
||||||
dev_cap->max_port_width[1]);
|
dev_cap->port_cap[1].max_port_width);
|
||||||
mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
|
mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
|
||||||
dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
|
dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
|
||||||
mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
|
mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
|
||||||
@ -964,6 +945,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
|
mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
|
||||||
mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
|
mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
|
||||||
mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
|
mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
|
||||||
|
mlx4_dbg(dev, "DMFS high rate steer QPn base: %d\n",
|
||||||
|
dev_cap->dmfs_high_rate_qpn_base);
|
||||||
|
mlx4_dbg(dev, "DMFS high rate steer QPn range: %d\n",
|
||||||
|
dev_cap->dmfs_high_rate_qpn_range);
|
||||||
|
|
||||||
dump_dev_cap_flags(dev, dev_cap->flags);
|
dump_dev_cap_flags(dev, dev_cap->flags);
|
||||||
dump_dev_cap_flags2(dev, dev_cap->flags2);
|
dump_dev_cap_flags2(dev, dev_cap->flags2);
|
||||||
@ -973,6 +958,89 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap)
|
||||||
|
{
|
||||||
|
struct mlx4_cmd_mailbox *mailbox;
|
||||||
|
u32 *outbox;
|
||||||
|
u8 field;
|
||||||
|
u32 field32;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
||||||
|
if (IS_ERR(mailbox))
|
||||||
|
return PTR_ERR(mailbox);
|
||||||
|
outbox = mailbox->buf;
|
||||||
|
|
||||||
|
if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
|
||||||
|
err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
|
||||||
|
MLX4_CMD_TIME_CLASS_A,
|
||||||
|
MLX4_CMD_NATIVE);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
|
||||||
|
port_cap->max_vl = field >> 4;
|
||||||
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
|
||||||
|
port_cap->ib_mtu = field >> 4;
|
||||||
|
port_cap->max_port_width = field & 0xf;
|
||||||
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
|
||||||
|
port_cap->max_gids = 1 << (field & 0xf);
|
||||||
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
|
||||||
|
port_cap->max_pkeys = 1 << (field & 0xf);
|
||||||
|
} else {
|
||||||
|
#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00
|
||||||
|
#define QUERY_PORT_MTU_OFFSET 0x01
|
||||||
|
#define QUERY_PORT_ETH_MTU_OFFSET 0x02
|
||||||
|
#define QUERY_PORT_WIDTH_OFFSET 0x06
|
||||||
|
#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07
|
||||||
|
#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a
|
||||||
|
#define QUERY_PORT_MAX_VL_OFFSET 0x0b
|
||||||
|
#define QUERY_PORT_MAC_OFFSET 0x10
|
||||||
|
#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18
|
||||||
|
#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c
|
||||||
|
#define QUERY_PORT_TRANS_CODE_OFFSET 0x20
|
||||||
|
|
||||||
|
err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, MLX4_CMD_QUERY_PORT,
|
||||||
|
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
|
||||||
|
port_cap->supported_port_types = field & 3;
|
||||||
|
port_cap->suggested_type = (field >> 3) & 1;
|
||||||
|
port_cap->default_sense = (field >> 4) & 1;
|
||||||
|
port_cap->dmfs_optimized_state = (field >> 5) & 1;
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
|
||||||
|
port_cap->ib_mtu = field & 0xf;
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
|
||||||
|
port_cap->max_port_width = field & 0xf;
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
|
||||||
|
port_cap->max_gids = 1 << (field >> 4);
|
||||||
|
port_cap->max_pkeys = 1 << (field & 0xf);
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
|
||||||
|
port_cap->max_vl = field & 0xf;
|
||||||
|
MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
|
||||||
|
port_cap->log_max_macs = field & 0xf;
|
||||||
|
port_cap->log_max_vlans = field >> 4;
|
||||||
|
MLX4_GET(port_cap->eth_mtu, outbox, QUERY_PORT_ETH_MTU_OFFSET);
|
||||||
|
MLX4_GET(port_cap->def_mac, outbox, QUERY_PORT_MAC_OFFSET);
|
||||||
|
MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
|
||||||
|
port_cap->trans_type = field32 >> 24;
|
||||||
|
port_cap->vendor_oui = field32 & 0xffffff;
|
||||||
|
MLX4_GET(port_cap->wavelength, outbox, QUERY_PORT_WAVELENGTH_OFFSET);
|
||||||
|
MLX4_GET(port_cap->trans_code, outbox, QUERY_PORT_TRANS_CODE_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
mlx4_free_cmd_mailbox(dev, mailbox);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEV_CAP_EXT_2_FLAG_VLAN_CONTROL (1 << 26)
|
||||||
|
#define DEV_CAP_EXT_2_FLAG_80_VFS (1 << 21)
|
||||||
|
#define DEV_CAP_EXT_2_FLAG_FSM (1 << 20)
|
||||||
|
|
||||||
int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
||||||
struct mlx4_vhcr *vhcr,
|
struct mlx4_vhcr *vhcr,
|
||||||
struct mlx4_cmd_mailbox *inbox,
|
struct mlx4_cmd_mailbox *inbox,
|
||||||
@ -982,7 +1050,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
u64 flags;
|
u64 flags;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 field;
|
u8 field;
|
||||||
u32 bmme_flags;
|
u32 bmme_flags, field32;
|
||||||
int real_port;
|
int real_port;
|
||||||
int slave_port;
|
int slave_port;
|
||||||
int first_port;
|
int first_port;
|
||||||
@ -1053,6 +1121,12 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
field &= ~0x80;
|
field &= ~0x80;
|
||||||
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
|
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
|
||||||
|
|
||||||
|
/* turn off host side virt features (VST, FSM, etc) for guests */
|
||||||
|
MLX4_GET(field32, outbox->buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
|
||||||
|
field32 &= ~(DEV_CAP_EXT_2_FLAG_VLAN_CONTROL | DEV_CAP_EXT_2_FLAG_80_VFS |
|
||||||
|
DEV_CAP_EXT_2_FLAG_FSM);
|
||||||
|
MLX4_PUT(outbox->buf, field32, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1471,6 +1545,12 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
|
|||||||
struct mlx4_cmd_mailbox *mailbox;
|
struct mlx4_cmd_mailbox *mailbox;
|
||||||
__be32 *inbox;
|
__be32 *inbox;
|
||||||
int err;
|
int err;
|
||||||
|
static const u8 a0_dmfs_hw_steering[] = {
|
||||||
|
[MLX4_STEERING_DMFS_A0_DEFAULT] = 0,
|
||||||
|
[MLX4_STEERING_DMFS_A0_DYNAMIC] = 1,
|
||||||
|
[MLX4_STEERING_DMFS_A0_STATIC] = 2,
|
||||||
|
[MLX4_STEERING_DMFS_A0_DISABLE] = 3
|
||||||
|
};
|
||||||
|
|
||||||
#define INIT_HCA_IN_SIZE 0x200
|
#define INIT_HCA_IN_SIZE 0x200
|
||||||
#define INIT_HCA_VERSION_OFFSET 0x000
|
#define INIT_HCA_VERSION_OFFSET 0x000
|
||||||
@ -1504,6 +1584,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
|
|||||||
#define INIT_HCA_FS_PARAM_OFFSET 0x1d0
|
#define INIT_HCA_FS_PARAM_OFFSET 0x1d0
|
||||||
#define INIT_HCA_FS_BASE_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x00)
|
#define INIT_HCA_FS_BASE_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x00)
|
||||||
#define INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x12)
|
#define INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x12)
|
||||||
|
#define INIT_HCA_FS_A0_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x18)
|
||||||
#define INIT_HCA_FS_LOG_TABLE_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
|
#define INIT_HCA_FS_LOG_TABLE_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
|
||||||
#define INIT_HCA_FS_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21)
|
#define INIT_HCA_FS_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21)
|
||||||
#define INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22)
|
#define INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22)
|
||||||
@ -1614,8 +1695,11 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
|
|||||||
/* Enable Ethernet flow steering
|
/* Enable Ethernet flow steering
|
||||||
* with udp unicast and tcp unicast
|
* with udp unicast and tcp unicast
|
||||||
*/
|
*/
|
||||||
MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
|
if (dev->caps.dmfs_high_steer_mode !=
|
||||||
INIT_HCA_FS_ETH_BITS_OFFSET);
|
MLX4_STEERING_DMFS_A0_STATIC)
|
||||||
|
MLX4_PUT(inbox,
|
||||||
|
(u8)(MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
|
||||||
|
INIT_HCA_FS_ETH_BITS_OFFSET);
|
||||||
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
|
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
|
||||||
INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
|
INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
|
||||||
/* Enable IPoIB flow steering
|
/* Enable IPoIB flow steering
|
||||||
@ -1625,6 +1709,13 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
|
|||||||
INIT_HCA_FS_IB_BITS_OFFSET);
|
INIT_HCA_FS_IB_BITS_OFFSET);
|
||||||
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
|
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
|
||||||
INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
|
INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
|
||||||
|
|
||||||
|
if (dev->caps.dmfs_high_steer_mode !=
|
||||||
|
MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
|
||||||
|
MLX4_PUT(inbox,
|
||||||
|
((u8)(a0_dmfs_hw_steering[dev->caps.dmfs_high_steer_mode]
|
||||||
|
<< 6)),
|
||||||
|
INIT_HCA_FS_A0_OFFSET);
|
||||||
} else {
|
} else {
|
||||||
MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET);
|
MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET);
|
||||||
MLX4_PUT(inbox, param->log_mc_entry_sz,
|
MLX4_PUT(inbox, param->log_mc_entry_sz,
|
||||||
@ -1675,6 +1766,12 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
|
|||||||
u32 dword_field;
|
u32 dword_field;
|
||||||
int err;
|
int err;
|
||||||
u8 byte_field;
|
u8 byte_field;
|
||||||
|
static const u8 a0_dmfs_query_hw_steering[] = {
|
||||||
|
[0] = MLX4_STEERING_DMFS_A0_DEFAULT,
|
||||||
|
[1] = MLX4_STEERING_DMFS_A0_DYNAMIC,
|
||||||
|
[2] = MLX4_STEERING_DMFS_A0_STATIC,
|
||||||
|
[3] = MLX4_STEERING_DMFS_A0_DISABLE
|
||||||
|
};
|
||||||
|
|
||||||
#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04
|
#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04
|
||||||
#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c
|
#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c
|
||||||
@ -1727,6 +1824,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
|
|||||||
INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
|
INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
|
||||||
MLX4_GET(param->log_mc_table_sz, outbox,
|
MLX4_GET(param->log_mc_table_sz, outbox,
|
||||||
INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
|
INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
|
||||||
|
MLX4_GET(byte_field, outbox,
|
||||||
|
INIT_HCA_FS_A0_OFFSET);
|
||||||
|
param->dmfs_high_steer_mode =
|
||||||
|
a0_dmfs_query_hw_steering[(byte_field >> 6) & 3];
|
||||||
} else {
|
} else {
|
||||||
MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
|
MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
|
||||||
MLX4_GET(param->log_mc_entry_sz, outbox,
|
MLX4_GET(param->log_mc_entry_sz, outbox,
|
||||||
|
@ -43,6 +43,26 @@ struct mlx4_mod_stat_cfg {
|
|||||||
u8 log_pg_sz_m;
|
u8 log_pg_sz_m;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mlx4_port_cap {
|
||||||
|
u8 supported_port_types;
|
||||||
|
u8 suggested_type;
|
||||||
|
u8 default_sense;
|
||||||
|
u8 log_max_macs;
|
||||||
|
u8 log_max_vlans;
|
||||||
|
int ib_mtu;
|
||||||
|
int max_port_width;
|
||||||
|
int max_vl;
|
||||||
|
int max_gids;
|
||||||
|
int max_pkeys;
|
||||||
|
u64 def_mac;
|
||||||
|
u16 eth_mtu;
|
||||||
|
int trans_type;
|
||||||
|
int vendor_oui;
|
||||||
|
u16 wavelength;
|
||||||
|
u64 trans_code;
|
||||||
|
u8 dmfs_optimized_state;
|
||||||
|
};
|
||||||
|
|
||||||
struct mlx4_dev_cap {
|
struct mlx4_dev_cap {
|
||||||
int max_srq_sz;
|
int max_srq_sz;
|
||||||
int max_qp_sz;
|
int max_qp_sz;
|
||||||
@ -67,17 +87,6 @@ struct mlx4_dev_cap {
|
|||||||
int local_ca_ack_delay;
|
int local_ca_ack_delay;
|
||||||
int num_ports;
|
int num_ports;
|
||||||
u32 max_msg_sz;
|
u32 max_msg_sz;
|
||||||
int ib_mtu[MLX4_MAX_PORTS + 1];
|
|
||||||
int max_port_width[MLX4_MAX_PORTS + 1];
|
|
||||||
int max_vl[MLX4_MAX_PORTS + 1];
|
|
||||||
int max_gids[MLX4_MAX_PORTS + 1];
|
|
||||||
int max_pkeys[MLX4_MAX_PORTS + 1];
|
|
||||||
u64 def_mac[MLX4_MAX_PORTS + 1];
|
|
||||||
u16 eth_mtu[MLX4_MAX_PORTS + 1];
|
|
||||||
int trans_type[MLX4_MAX_PORTS + 1];
|
|
||||||
int vendor_oui[MLX4_MAX_PORTS + 1];
|
|
||||||
u16 wavelength[MLX4_MAX_PORTS + 1];
|
|
||||||
u64 trans_code[MLX4_MAX_PORTS + 1];
|
|
||||||
u16 stat_rate_support;
|
u16 stat_rate_support;
|
||||||
int fs_log_max_ucast_qp_range_size;
|
int fs_log_max_ucast_qp_range_size;
|
||||||
int fs_max_num_qp_per_entry;
|
int fs_max_num_qp_per_entry;
|
||||||
@ -115,12 +124,10 @@ struct mlx4_dev_cap {
|
|||||||
u64 max_icm_sz;
|
u64 max_icm_sz;
|
||||||
int max_gso_sz;
|
int max_gso_sz;
|
||||||
int max_rss_tbl_sz;
|
int max_rss_tbl_sz;
|
||||||
u8 supported_port_types[MLX4_MAX_PORTS + 1];
|
|
||||||
u8 suggested_type[MLX4_MAX_PORTS + 1];
|
|
||||||
u8 default_sense[MLX4_MAX_PORTS + 1];
|
|
||||||
u8 log_max_macs[MLX4_MAX_PORTS + 1];
|
|
||||||
u8 log_max_vlans[MLX4_MAX_PORTS + 1];
|
|
||||||
u32 max_counters;
|
u32 max_counters;
|
||||||
|
u32 dmfs_high_rate_qpn_base;
|
||||||
|
u32 dmfs_high_rate_qpn_range;
|
||||||
|
struct mlx4_port_cap port_cap[MLX4_MAX_PORTS + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_func_cap {
|
struct mlx4_func_cap {
|
||||||
@ -144,6 +151,7 @@ struct mlx4_func_cap {
|
|||||||
u8 port_flags;
|
u8 port_flags;
|
||||||
u8 flags1;
|
u8 flags1;
|
||||||
u64 phys_port_id;
|
u64 phys_port_id;
|
||||||
|
u32 extra_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_func {
|
struct mlx4_func {
|
||||||
@ -189,6 +197,7 @@ struct mlx4_init_hca_param {
|
|||||||
u8 mw_enabled; /* Enable memory windows */
|
u8 mw_enabled; /* Enable memory windows */
|
||||||
u8 uar_page_sz; /* log pg sz in 4k chunks */
|
u8 uar_page_sz; /* log pg sz in 4k chunks */
|
||||||
u8 steering_mode; /* for QUERY_HCA */
|
u8 steering_mode; /* for QUERY_HCA */
|
||||||
|
u8 dmfs_high_steer_mode; /* for QUERY_HCA */
|
||||||
u64 dev_cap_enabled;
|
u64 dev_cap_enabled;
|
||||||
u16 cqe_size; /* For use only when CQE stride feature enabled */
|
u16 cqe_size; /* For use only when CQE stride feature enabled */
|
||||||
u16 eqe_size; /* For use only when EQE stride feature enabled */
|
u16 eqe_size; /* For use only when EQE stride feature enabled */
|
||||||
@ -216,6 +225,7 @@ struct mlx4_set_ib_param {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
|
int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
|
||||||
|
int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap);
|
||||||
int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
|
int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
|
||||||
struct mlx4_func_cap *func_cap);
|
struct mlx4_func_cap *func_cap);
|
||||||
int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
||||||
|
@ -105,7 +105,8 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe,
|
|||||||
"Enable 64 byte CQEs/EQEs when the FW supports this (default: True)");
|
"Enable 64 byte CQEs/EQEs when the FW supports this (default: True)");
|
||||||
|
|
||||||
#define PF_CONTEXT_BEHAVIOUR_MASK (MLX4_FUNC_CAP_64B_EQE_CQE | \
|
#define PF_CONTEXT_BEHAVIOUR_MASK (MLX4_FUNC_CAP_64B_EQE_CQE | \
|
||||||
MLX4_FUNC_CAP_EQE_CQE_STRIDE)
|
MLX4_FUNC_CAP_EQE_CQE_STRIDE | \
|
||||||
|
MLX4_FUNC_CAP_DMFS_A0_STATIC)
|
||||||
|
|
||||||
static char mlx4_version[] =
|
static char mlx4_version[] =
|
||||||
DRV_NAME ": Mellanox ConnectX core driver v"
|
DRV_NAME ": Mellanox ConnectX core driver v"
|
||||||
@ -254,6 +255,46 @@ static void mlx4_enable_cqe_eqe_stride(struct mlx4_dev *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _mlx4_dev_port(struct mlx4_dev *dev, int port,
|
||||||
|
struct mlx4_port_cap *port_cap)
|
||||||
|
{
|
||||||
|
dev->caps.vl_cap[port] = port_cap->max_vl;
|
||||||
|
dev->caps.ib_mtu_cap[port] = port_cap->ib_mtu;
|
||||||
|
dev->phys_caps.gid_phys_table_len[port] = port_cap->max_gids;
|
||||||
|
dev->phys_caps.pkey_phys_table_len[port] = port_cap->max_pkeys;
|
||||||
|
/* set gid and pkey table operating lengths by default
|
||||||
|
* to non-sriov values
|
||||||
|
*/
|
||||||
|
dev->caps.gid_table_len[port] = port_cap->max_gids;
|
||||||
|
dev->caps.pkey_table_len[port] = port_cap->max_pkeys;
|
||||||
|
dev->caps.port_width_cap[port] = port_cap->max_port_width;
|
||||||
|
dev->caps.eth_mtu_cap[port] = port_cap->eth_mtu;
|
||||||
|
dev->caps.def_mac[port] = port_cap->def_mac;
|
||||||
|
dev->caps.supported_type[port] = port_cap->supported_port_types;
|
||||||
|
dev->caps.suggested_type[port] = port_cap->suggested_type;
|
||||||
|
dev->caps.default_sense[port] = port_cap->default_sense;
|
||||||
|
dev->caps.trans_type[port] = port_cap->trans_type;
|
||||||
|
dev->caps.vendor_oui[port] = port_cap->vendor_oui;
|
||||||
|
dev->caps.wavelength[port] = port_cap->wavelength;
|
||||||
|
dev->caps.trans_code[port] = port_cap->trans_code;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlx4_dev_port(struct mlx4_dev *dev, int port,
|
||||||
|
struct mlx4_port_cap *port_cap)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
err = mlx4_QUERY_PORT(dev, port, port_cap);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
mlx4_err(dev, "QUERY_PORT command failed.\n");
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MLX4_A0_STEERING_TABLE_SIZE 256
|
||||||
static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -289,24 +330,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
dev->caps.num_sys_eqs :
|
dev->caps.num_sys_eqs :
|
||||||
MLX4_MAX_EQ_NUM;
|
MLX4_MAX_EQ_NUM;
|
||||||
for (i = 1; i <= dev->caps.num_ports; ++i) {
|
for (i = 1; i <= dev->caps.num_ports; ++i) {
|
||||||
dev->caps.vl_cap[i] = dev_cap->max_vl[i];
|
err = _mlx4_dev_port(dev, i, dev_cap->port_cap + i);
|
||||||
dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i];
|
if (err) {
|
||||||
dev->phys_caps.gid_phys_table_len[i] = dev_cap->max_gids[i];
|
mlx4_err(dev, "QUERY_PORT command failed, aborting\n");
|
||||||
dev->phys_caps.pkey_phys_table_len[i] = dev_cap->max_pkeys[i];
|
return err;
|
||||||
/* set gid and pkey table operating lengths by default
|
}
|
||||||
* to non-sriov values */
|
|
||||||
dev->caps.gid_table_len[i] = dev_cap->max_gids[i];
|
|
||||||
dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i];
|
|
||||||
dev->caps.port_width_cap[i] = dev_cap->max_port_width[i];
|
|
||||||
dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i];
|
|
||||||
dev->caps.def_mac[i] = dev_cap->def_mac[i];
|
|
||||||
dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
|
|
||||||
dev->caps.suggested_type[i] = dev_cap->suggested_type[i];
|
|
||||||
dev->caps.default_sense[i] = dev_cap->default_sense[i];
|
|
||||||
dev->caps.trans_type[i] = dev_cap->trans_type[i];
|
|
||||||
dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i];
|
|
||||||
dev->caps.wavelength[i] = dev_cap->wavelength[i];
|
|
||||||
dev->caps.trans_code[i] = dev_cap->trans_code[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->caps.uar_page_size = PAGE_SIZE;
|
dev->caps.uar_page_size = PAGE_SIZE;
|
||||||
@ -415,13 +443,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
dev->caps.possible_type[i] = dev->caps.port_type[i];
|
dev->caps.possible_type[i] = dev->caps.port_type[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
|
if (dev->caps.log_num_macs > dev_cap->port_cap[i].log_max_macs) {
|
||||||
dev->caps.log_num_macs = dev_cap->log_max_macs[i];
|
dev->caps.log_num_macs = dev_cap->port_cap[i].log_max_macs;
|
||||||
mlx4_warn(dev, "Requested number of MACs is too much for port %d, reducing to %d\n",
|
mlx4_warn(dev, "Requested number of MACs is too much for port %d, reducing to %d\n",
|
||||||
i, 1 << dev->caps.log_num_macs);
|
i, 1 << dev->caps.log_num_macs);
|
||||||
}
|
}
|
||||||
if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) {
|
if (dev->caps.log_num_vlans > dev_cap->port_cap[i].log_max_vlans) {
|
||||||
dev->caps.log_num_vlans = dev_cap->log_max_vlans[i];
|
dev->caps.log_num_vlans = dev_cap->port_cap[i].log_max_vlans;
|
||||||
mlx4_warn(dev, "Requested number of VLANs is too much for port %d, reducing to %d\n",
|
mlx4_warn(dev, "Requested number of VLANs is too much for port %d, reducing to %d\n",
|
||||||
i, 1 << dev->caps.log_num_vlans);
|
i, 1 << dev->caps.log_num_vlans);
|
||||||
}
|
}
|
||||||
@ -437,6 +465,28 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
dev->caps.num_ports;
|
dev->caps.num_ports;
|
||||||
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH;
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH;
|
||||||
|
|
||||||
|
if (dev_cap->dmfs_high_rate_qpn_base > 0 &&
|
||||||
|
dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FS_EN)
|
||||||
|
dev->caps.dmfs_high_rate_qpn_base = dev_cap->dmfs_high_rate_qpn_base;
|
||||||
|
else
|
||||||
|
dev->caps.dmfs_high_rate_qpn_base =
|
||||||
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
|
||||||
|
|
||||||
|
if (dev_cap->dmfs_high_rate_qpn_range > 0 &&
|
||||||
|
dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FS_EN) {
|
||||||
|
dev->caps.dmfs_high_rate_qpn_range = dev_cap->dmfs_high_rate_qpn_range;
|
||||||
|
dev->caps.dmfs_high_steer_mode = MLX4_STEERING_DMFS_A0_DEFAULT;
|
||||||
|
dev->caps.flags2 |= MLX4_DEV_CAP_FLAG2_FS_A0;
|
||||||
|
} else {
|
||||||
|
dev->caps.dmfs_high_steer_mode = MLX4_STEERING_DMFS_A0_NOT_SUPPORTED;
|
||||||
|
dev->caps.dmfs_high_rate_qpn_base =
|
||||||
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
|
||||||
|
dev->caps.dmfs_high_rate_qpn_range = MLX4_A0_STEERING_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_RSS_RAW_ETH] =
|
||||||
|
dev->caps.dmfs_high_rate_qpn_range;
|
||||||
|
|
||||||
dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] +
|
dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] +
|
||||||
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] +
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] +
|
||||||
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] +
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] +
|
||||||
@ -466,8 +516,14 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|||||||
mlx4_is_master(dev))
|
mlx4_is_master(dev))
|
||||||
dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE;
|
dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE;
|
||||||
|
|
||||||
if (!mlx4_is_slave(dev))
|
if (!mlx4_is_slave(dev)) {
|
||||||
mlx4_enable_cqe_eqe_stride(dev);
|
mlx4_enable_cqe_eqe_stride(dev);
|
||||||
|
dev->caps.alloc_res_qp_mask =
|
||||||
|
(dev->caps.bf_reg_size ? MLX4_RESERVE_ETH_BF_QP : 0) |
|
||||||
|
MLX4_RESERVE_A0_QP;
|
||||||
|
} else {
|
||||||
|
dev->caps.alloc_res_qp_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -718,7 +774,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|||||||
|
|
||||||
if ((func_cap.pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) !=
|
if ((func_cap.pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) !=
|
||||||
PF_CONTEXT_BEHAVIOUR_MASK) {
|
PF_CONTEXT_BEHAVIOUR_MASK) {
|
||||||
mlx4_err(dev, "Unknown pf context behaviour\n");
|
mlx4_err(dev, "Unknown pf context behaviour %x known flags %x\n",
|
||||||
|
func_cap.pf_context_behaviour, PF_CONTEXT_BEHAVIOUR_MASK);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,6 +874,13 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|||||||
|
|
||||||
slave_adjust_steering_mode(dev, &dev_cap, &hca_param);
|
slave_adjust_steering_mode(dev, &dev_cap, &hca_param);
|
||||||
|
|
||||||
|
if (func_cap.extra_flags & MLX4_QUERY_FUNC_FLAGS_BF_RES_QP &&
|
||||||
|
dev->caps.bf_reg_size)
|
||||||
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_ETH_BF_QP;
|
||||||
|
|
||||||
|
if (func_cap.extra_flags & MLX4_QUERY_FUNC_FLAGS_A0_RES_QP)
|
||||||
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_A0_QP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_mem:
|
err_mem:
|
||||||
@ -1598,10 +1662,46 @@ static int choose_log_fs_mgm_entry_size(int qp_per_entry)
|
|||||||
return (i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE) ? i : -1;
|
return (i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE) ? i : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *dmfs_high_rate_steering_mode_str(int dmfs_high_steer_mode)
|
||||||
|
{
|
||||||
|
switch (dmfs_high_steer_mode) {
|
||||||
|
case MLX4_STEERING_DMFS_A0_DEFAULT:
|
||||||
|
return "default performance";
|
||||||
|
|
||||||
|
case MLX4_STEERING_DMFS_A0_DYNAMIC:
|
||||||
|
return "dynamic hybrid mode";
|
||||||
|
|
||||||
|
case MLX4_STEERING_DMFS_A0_STATIC:
|
||||||
|
return "performance optimized for limited rule configuration (static)";
|
||||||
|
|
||||||
|
case MLX4_STEERING_DMFS_A0_DISABLE:
|
||||||
|
return "disabled performance optimized steering";
|
||||||
|
|
||||||
|
case MLX4_STEERING_DMFS_A0_NOT_SUPPORTED:
|
||||||
|
return "performance optimized steering not supported";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "Unrecognized mode";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MLX4_DMFS_A0_STEERING (1UL << 2)
|
||||||
|
|
||||||
static void choose_steering_mode(struct mlx4_dev *dev,
|
static void choose_steering_mode(struct mlx4_dev *dev,
|
||||||
struct mlx4_dev_cap *dev_cap)
|
struct mlx4_dev_cap *dev_cap)
|
||||||
{
|
{
|
||||||
if (mlx4_log_num_mgm_entry_size == -1 &&
|
if (mlx4_log_num_mgm_entry_size <= 0) {
|
||||||
|
if ((-mlx4_log_num_mgm_entry_size) & MLX4_DMFS_A0_STEERING) {
|
||||||
|
if (dev->caps.dmfs_high_steer_mode ==
|
||||||
|
MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
|
||||||
|
mlx4_err(dev, "DMFS high rate mode not supported\n");
|
||||||
|
else
|
||||||
|
dev->caps.dmfs_high_steer_mode =
|
||||||
|
MLX4_STEERING_DMFS_A0_STATIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mlx4_log_num_mgm_entry_size <= 0 &&
|
||||||
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
|
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
|
||||||
(!mlx4_is_mfunc(dev) ||
|
(!mlx4_is_mfunc(dev) ||
|
||||||
(dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) &&
|
(dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) &&
|
||||||
@ -1614,6 +1714,9 @@ static void choose_steering_mode(struct mlx4_dev *dev,
|
|||||||
dev->caps.fs_log_max_ucast_qp_range_size =
|
dev->caps.fs_log_max_ucast_qp_range_size =
|
||||||
dev_cap->fs_log_max_ucast_qp_range_size;
|
dev_cap->fs_log_max_ucast_qp_range_size;
|
||||||
} else {
|
} else {
|
||||||
|
if (dev->caps.dmfs_high_steer_mode !=
|
||||||
|
MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
|
||||||
|
dev->caps.dmfs_high_steer_mode = MLX4_STEERING_DMFS_A0_DISABLE;
|
||||||
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER &&
|
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER &&
|
||||||
dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
|
dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
|
||||||
dev->caps.steering_mode = MLX4_STEERING_MODE_B0;
|
dev->caps.steering_mode = MLX4_STEERING_MODE_B0;
|
||||||
@ -1640,7 +1743,8 @@ static void choose_tunnel_offload_mode(struct mlx4_dev *dev,
|
|||||||
struct mlx4_dev_cap *dev_cap)
|
struct mlx4_dev_cap *dev_cap)
|
||||||
{
|
{
|
||||||
if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED &&
|
if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED &&
|
||||||
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
|
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS &&
|
||||||
|
dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC)
|
||||||
dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_VXLAN;
|
dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_VXLAN;
|
||||||
else
|
else
|
||||||
dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_NONE;
|
dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_NONE;
|
||||||
@ -1649,6 +1753,35 @@ static void choose_tunnel_offload_mode(struct mlx4_dev *dev,
|
|||||||
== MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) ? "vxlan" : "none");
|
== MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) ? "vxlan" : "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mlx4_validate_optimized_steering(struct mlx4_dev *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct mlx4_port_cap port_cap;
|
||||||
|
|
||||||
|
if (dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 1; i <= dev->caps.num_ports; i++) {
|
||||||
|
if (mlx4_dev_port(dev, i, &port_cap)) {
|
||||||
|
mlx4_err(dev,
|
||||||
|
"QUERY_DEV_CAP command failed, can't veify DMFS high rate steering.\n");
|
||||||
|
} else if ((dev->caps.dmfs_high_steer_mode !=
|
||||||
|
MLX4_STEERING_DMFS_A0_DEFAULT) &&
|
||||||
|
(port_cap.dmfs_optimized_state ==
|
||||||
|
!!(dev->caps.dmfs_high_steer_mode ==
|
||||||
|
MLX4_STEERING_DMFS_A0_DISABLE))) {
|
||||||
|
mlx4_err(dev,
|
||||||
|
"DMFS high rate steer mode differ, driver requested %s but %s in FW.\n",
|
||||||
|
dmfs_high_rate_steering_mode_str(
|
||||||
|
dev->caps.dmfs_high_steer_mode),
|
||||||
|
(port_cap.dmfs_optimized_state ?
|
||||||
|
"enabled" : "disabled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mlx4_init_fw(struct mlx4_dev *dev)
|
static int mlx4_init_fw(struct mlx4_dev *dev)
|
||||||
{
|
{
|
||||||
struct mlx4_mod_stat_cfg mlx4_cfg;
|
struct mlx4_mod_stat_cfg mlx4_cfg;
|
||||||
@ -1701,6 +1834,10 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
|
|||||||
choose_steering_mode(dev, &dev_cap);
|
choose_steering_mode(dev, &dev_cap);
|
||||||
choose_tunnel_offload_mode(dev, &dev_cap);
|
choose_tunnel_offload_mode(dev, &dev_cap);
|
||||||
|
|
||||||
|
if (dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC &&
|
||||||
|
mlx4_is_master(dev))
|
||||||
|
dev->caps.function_caps |= MLX4_FUNC_CAP_DMFS_A0_STATIC;
|
||||||
|
|
||||||
err = mlx4_get_phys_port_id(dev);
|
err = mlx4_get_phys_port_id(dev);
|
||||||
if (err)
|
if (err)
|
||||||
mlx4_err(dev, "Fail to get physical port id\n");
|
mlx4_err(dev, "Fail to get physical port id\n");
|
||||||
@ -1787,6 +1924,24 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
|
|||||||
mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported\n");
|
mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->caps.dmfs_high_steer_mode !=
|
||||||
|
MLX4_STEERING_DMFS_A0_NOT_SUPPORTED) {
|
||||||
|
if (mlx4_validate_optimized_steering(dev))
|
||||||
|
mlx4_warn(dev, "Optimized steering validation failed\n");
|
||||||
|
|
||||||
|
if (dev->caps.dmfs_high_steer_mode ==
|
||||||
|
MLX4_STEERING_DMFS_A0_DISABLE) {
|
||||||
|
dev->caps.dmfs_high_rate_qpn_base =
|
||||||
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
|
||||||
|
dev->caps.dmfs_high_rate_qpn_range =
|
||||||
|
MLX4_A0_STEERING_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlx4_dbg(dev, "DMFS high rate steer mode is: %s\n",
|
||||||
|
dmfs_high_rate_steering_mode_str(
|
||||||
|
dev->caps.dmfs_high_steer_mode));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err = mlx4_init_slave(dev);
|
err = mlx4_init_slave(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -3159,10 +3314,11 @@ static int __init mlx4_verify_params(void)
|
|||||||
port_type_array[0] = true;
|
port_type_array[0] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mlx4_log_num_mgm_entry_size != -1 &&
|
if (mlx4_log_num_mgm_entry_size < -7 ||
|
||||||
(mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE ||
|
(mlx4_log_num_mgm_entry_size > 0 &&
|
||||||
mlx4_log_num_mgm_entry_size > MLX4_MAX_MGM_LOG_ENTRY_SIZE)) {
|
(mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE ||
|
||||||
pr_warn("mlx4_core: mlx4_log_num_mgm_entry_size (%d) not in legal range (-1 or %d..%d)\n",
|
mlx4_log_num_mgm_entry_size > MLX4_MAX_MGM_LOG_ENTRY_SIZE))) {
|
||||||
|
pr_warn("mlx4_core: mlx4_log_num_mgm_entry_size (%d) not in legal range (-7..0 or %d..%d)\n",
|
||||||
mlx4_log_num_mgm_entry_size,
|
mlx4_log_num_mgm_entry_size,
|
||||||
MLX4_MIN_MGM_LOG_ENTRY_SIZE,
|
MLX4_MIN_MGM_LOG_ENTRY_SIZE,
|
||||||
MLX4_MAX_MGM_LOG_ENTRY_SIZE);
|
MLX4_MAX_MGM_LOG_ENTRY_SIZE);
|
||||||
|
@ -999,12 +999,27 @@ int mlx4_flow_attach(struct mlx4_dev *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
|
ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
|
||||||
if (ret == -ENOMEM)
|
if (ret == -ENOMEM) {
|
||||||
mlx4_err_rule(dev,
|
mlx4_err_rule(dev,
|
||||||
"mcg table is full. Fail to register network rule\n",
|
"mcg table is full. Fail to register network rule\n",
|
||||||
rule);
|
rule);
|
||||||
else if (ret)
|
} else if (ret) {
|
||||||
mlx4_err_rule(dev, "Fail to register network rule\n", rule);
|
if (ret == -ENXIO) {
|
||||||
|
if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
|
||||||
|
mlx4_err_rule(dev,
|
||||||
|
"DMFS is not enabled, "
|
||||||
|
"failed to register network rule.\n",
|
||||||
|
rule);
|
||||||
|
else
|
||||||
|
mlx4_err_rule(dev,
|
||||||
|
"Rule exceeds the dmfs_high_rate_mode limitations, "
|
||||||
|
"failed to register network rule.\n",
|
||||||
|
rule);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mlx4_free_cmd_mailbox(dev, mailbox);
|
mlx4_free_cmd_mailbox(dev, mailbox);
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#include <linux/mlx4/device.h>
|
#include <linux/mlx4/device.h>
|
||||||
#include <linux/mlx4/driver.h>
|
#include <linux/mlx4/driver.h>
|
||||||
@ -243,6 +245,7 @@ struct mlx4_bitmap {
|
|||||||
u32 reserved_top;
|
u32 reserved_top;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
u32 avail;
|
u32 avail;
|
||||||
|
u32 effective_len;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
unsigned long *table;
|
unsigned long *table;
|
||||||
};
|
};
|
||||||
@ -373,6 +376,14 @@ struct mlx4_srq_context {
|
|||||||
__be64 db_rec_addr;
|
__be64 db_rec_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mlx4_eq_tasklet {
|
||||||
|
struct list_head list;
|
||||||
|
struct list_head process_list;
|
||||||
|
struct tasklet_struct task;
|
||||||
|
/* lock on completion tasklet list */
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
struct mlx4_eq {
|
struct mlx4_eq {
|
||||||
struct mlx4_dev *dev;
|
struct mlx4_dev *dev;
|
||||||
void __iomem *doorbell;
|
void __iomem *doorbell;
|
||||||
@ -383,6 +394,7 @@ struct mlx4_eq {
|
|||||||
int nent;
|
int nent;
|
||||||
struct mlx4_buf_list *page_list;
|
struct mlx4_buf_list *page_list;
|
||||||
struct mlx4_mtt mtt;
|
struct mlx4_mtt mtt;
|
||||||
|
struct mlx4_eq_tasklet tasklet_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_slave_eqe {
|
struct mlx4_slave_eqe {
|
||||||
@ -670,8 +682,17 @@ struct mlx4_srq_table {
|
|||||||
struct mlx4_icm_table cmpt_table;
|
struct mlx4_icm_table cmpt_table;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mlx4_qp_table_zones {
|
||||||
|
MLX4_QP_TABLE_ZONE_GENERAL,
|
||||||
|
MLX4_QP_TABLE_ZONE_RSS,
|
||||||
|
MLX4_QP_TABLE_ZONE_RAW_ETH,
|
||||||
|
MLX4_QP_TABLE_ZONE_NUM
|
||||||
|
};
|
||||||
|
|
||||||
struct mlx4_qp_table {
|
struct mlx4_qp_table {
|
||||||
struct mlx4_bitmap bitmap;
|
struct mlx4_bitmap *bitmap_gen;
|
||||||
|
struct mlx4_zone_allocator *zones;
|
||||||
|
u32 zones_uids[MLX4_QP_TABLE_ZONE_NUM];
|
||||||
u32 rdmarc_base;
|
u32 rdmarc_base;
|
||||||
int rdmarc_shift;
|
int rdmarc_shift;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
@ -873,7 +894,8 @@ extern struct workqueue_struct *mlx4_wq;
|
|||||||
|
|
||||||
u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
|
u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
|
||||||
void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr);
|
void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr);
|
||||||
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
|
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt,
|
||||||
|
int align, u32 skip_mask);
|
||||||
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt,
|
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt,
|
||||||
int use_rr);
|
int use_rr);
|
||||||
u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap);
|
u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap);
|
||||||
@ -959,7 +981,7 @@ int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
|
|||||||
struct mlx4_cmd_mailbox *outbox,
|
struct mlx4_cmd_mailbox *outbox,
|
||||||
struct mlx4_cmd_info *cmd);
|
struct mlx4_cmd_info *cmd);
|
||||||
int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
||||||
int *base);
|
int *base, u8 flags);
|
||||||
void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
|
void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
|
||||||
int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
|
int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
|
||||||
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
|
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
|
||||||
@ -1146,6 +1168,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev);
|
|||||||
int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
|
int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
|
||||||
unsigned long timeout);
|
unsigned long timeout);
|
||||||
|
|
||||||
|
void mlx4_cq_tasklet_cb(unsigned long data);
|
||||||
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
|
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
|
||||||
void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type);
|
void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type);
|
||||||
|
|
||||||
@ -1332,4 +1355,72 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port);
|
|||||||
int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
|
int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
|
||||||
int mlx4_config_mad_demux(struct mlx4_dev *dev);
|
int mlx4_config_mad_demux(struct mlx4_dev *dev);
|
||||||
|
|
||||||
|
enum mlx4_zone_flags {
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO = 1UL << 0,
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO = 1UL << 1,
|
||||||
|
MLX4_ZONE_FALLBACK_TO_HIGHER_PRIO = 1UL << 2,
|
||||||
|
MLX4_ZONE_USE_RR = 1UL << 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mlx4_zone_alloc_flags {
|
||||||
|
/* No two objects could overlap between zones. UID
|
||||||
|
* could be left unused. If this flag is given and
|
||||||
|
* two overlapped zones are used, an object will be free'd
|
||||||
|
* from the smallest possible matching zone.
|
||||||
|
*/
|
||||||
|
MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP = 1UL << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx4_zone_allocator;
|
||||||
|
|
||||||
|
/* Create a new zone allocator */
|
||||||
|
struct mlx4_zone_allocator *mlx4_zone_allocator_create(enum mlx4_zone_alloc_flags flags);
|
||||||
|
|
||||||
|
/* Attach a mlx4_bitmap <bitmap> of priority <priority> to the zone allocator
|
||||||
|
* <zone_alloc>. Allocating an object from this zone adds an offset <offset>.
|
||||||
|
* Similarly, when searching for an object to free, this offset it taken into
|
||||||
|
* account. The use_rr mlx4_ib parameter for allocating objects from this <bitmap>
|
||||||
|
* is given through the MLX4_ZONE_USE_RR flag in <flags>.
|
||||||
|
* When an allocation fails, <zone_alloc> tries to allocate from other zones
|
||||||
|
* according to the policy set by <flags>. <puid> is the unique identifier
|
||||||
|
* received to this zone.
|
||||||
|
*/
|
||||||
|
int mlx4_zone_add_one(struct mlx4_zone_allocator *zone_alloc,
|
||||||
|
struct mlx4_bitmap *bitmap,
|
||||||
|
u32 flags,
|
||||||
|
int priority,
|
||||||
|
int offset,
|
||||||
|
u32 *puid);
|
||||||
|
|
||||||
|
/* Remove bitmap indicated by <uid> from <zone_alloc> */
|
||||||
|
int mlx4_zone_remove_one(struct mlx4_zone_allocator *zone_alloc, u32 uid);
|
||||||
|
|
||||||
|
/* Delete the zone allocator <zone_alloc. This function doesn't destroy
|
||||||
|
* the attached bitmaps.
|
||||||
|
*/
|
||||||
|
void mlx4_zone_allocator_destroy(struct mlx4_zone_allocator *zone_alloc);
|
||||||
|
|
||||||
|
/* Allocate <count> objects with align <align> and skip_mask <skip_mask>
|
||||||
|
* from the mlx4_bitmap whose uid is <uid>. The bitmap which we actually
|
||||||
|
* allocated from is returned in <puid>. If the allocation fails, a negative
|
||||||
|
* number is returned. Otherwise, the offset of the first object is returned.
|
||||||
|
*/
|
||||||
|
u32 mlx4_zone_alloc_entries(struct mlx4_zone_allocator *zones, u32 uid, int count,
|
||||||
|
int align, u32 skip_mask, u32 *puid);
|
||||||
|
|
||||||
|
/* Free <count> objects, start from <obj> of the uid <uid> from zone_allocator
|
||||||
|
* <zones>.
|
||||||
|
*/
|
||||||
|
u32 mlx4_zone_free_entries(struct mlx4_zone_allocator *zones,
|
||||||
|
u32 uid, u32 obj, u32 count);
|
||||||
|
|
||||||
|
/* If <zones> was allocated with MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP, instead of
|
||||||
|
* specifying the uid when freeing an object, zone allocator could figure it by
|
||||||
|
* itself. Other parameters are similar to mlx4_zone_free.
|
||||||
|
*/
|
||||||
|
u32 mlx4_zone_free_entries_unique(struct mlx4_zone_allocator *zones, u32 obj, u32 count);
|
||||||
|
|
||||||
|
/* Returns a pointer to mlx4_bitmap that was attached to <zones> with <uid> */
|
||||||
|
struct mlx4_bitmap *mlx4_zone_get_bitmap(struct mlx4_zone_allocator *zones, u32 uid);
|
||||||
|
|
||||||
#endif /* MLX4_H */
|
#endif /* MLX4_H */
|
||||||
|
@ -778,7 +778,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
|
|||||||
|
|
||||||
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
|
||||||
struct mlx4_en_tx_ring **pring,
|
struct mlx4_en_tx_ring **pring,
|
||||||
int qpn, u32 size, u16 stride,
|
u32 size, u16 stride,
|
||||||
int node, int queue_index);
|
int node, int queue_index);
|
||||||
void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
|
void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
|
||||||
struct mlx4_en_tx_ring **pring);
|
struct mlx4_en_tx_ring **pring);
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
#include "mlx4.h"
|
#include "mlx4.h"
|
||||||
#include "icm.h"
|
#include "icm.h"
|
||||||
|
|
||||||
|
/* QP to support BF should have bits 6,7 cleared */
|
||||||
|
#define MLX4_BF_QP_SKIP_MASK 0xc0
|
||||||
|
#define MLX4_MAX_BF_QP_RANGE 0x40
|
||||||
|
|
||||||
void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
|
void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
|
||||||
{
|
{
|
||||||
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
||||||
@ -207,26 +211,45 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
|
|||||||
EXPORT_SYMBOL_GPL(mlx4_qp_modify);
|
EXPORT_SYMBOL_GPL(mlx4_qp_modify);
|
||||||
|
|
||||||
int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
||||||
int *base)
|
int *base, u8 flags)
|
||||||
{
|
{
|
||||||
|
u32 uid;
|
||||||
|
int bf_qp = !!(flags & (u8)MLX4_RESERVE_ETH_BF_QP);
|
||||||
|
|
||||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||||
struct mlx4_qp_table *qp_table = &priv->qp_table;
|
struct mlx4_qp_table *qp_table = &priv->qp_table;
|
||||||
|
|
||||||
*base = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
|
if (cnt > MLX4_MAX_BF_QP_RANGE && bf_qp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
uid = MLX4_QP_TABLE_ZONE_GENERAL;
|
||||||
|
if (flags & (u8)MLX4_RESERVE_A0_QP) {
|
||||||
|
if (bf_qp)
|
||||||
|
uid = MLX4_QP_TABLE_ZONE_RAW_ETH;
|
||||||
|
else
|
||||||
|
uid = MLX4_QP_TABLE_ZONE_RSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
*base = mlx4_zone_alloc_entries(qp_table->zones, uid, cnt, align,
|
||||||
|
bf_qp ? MLX4_BF_QP_SKIP_MASK : 0, NULL);
|
||||||
if (*base == -1)
|
if (*base == -1)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
|
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
||||||
|
int *base, u8 flags)
|
||||||
{
|
{
|
||||||
u64 in_param = 0;
|
u64 in_param = 0;
|
||||||
u64 out_param;
|
u64 out_param;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
/* Turn off all unsupported QP allocation flags */
|
||||||
|
flags &= dev->caps.alloc_res_qp_mask;
|
||||||
|
|
||||||
if (mlx4_is_mfunc(dev)) {
|
if (mlx4_is_mfunc(dev)) {
|
||||||
set_param_l(&in_param, cnt);
|
set_param_l(&in_param, (((u32)flags) << 24) | (u32)cnt);
|
||||||
set_param_h(&in_param, align);
|
set_param_h(&in_param, align);
|
||||||
err = mlx4_cmd_imm(dev, in_param, &out_param,
|
err = mlx4_cmd_imm(dev, in_param, &out_param,
|
||||||
RES_QP, RES_OP_RESERVE,
|
RES_QP, RES_OP_RESERVE,
|
||||||
@ -238,7 +261,7 @@ int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
|
|||||||
*base = get_param_l(&out_param);
|
*base = get_param_l(&out_param);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return __mlx4_qp_reserve_range(dev, cnt, align, base);
|
return __mlx4_qp_reserve_range(dev, cnt, align, base, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
|
EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
|
||||||
|
|
||||||
@ -249,7 +272,7 @@ void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
|
|||||||
|
|
||||||
if (mlx4_is_qp_reserved(dev, (u32) base_qpn))
|
if (mlx4_is_qp_reserved(dev, (u32) base_qpn))
|
||||||
return;
|
return;
|
||||||
mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, MLX4_USE_RR);
|
mlx4_zone_free_entries_unique(qp_table->zones, base_qpn, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
|
void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
|
||||||
@ -459,28 +482,261 @@ static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn)
|
|||||||
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
|
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MLX4_QP_TABLE_RSS_ETH_PRIORITY 2
|
||||||
|
#define MLX4_QP_TABLE_RAW_ETH_PRIORITY 1
|
||||||
|
#define MLX4_QP_TABLE_RAW_ETH_SIZE 256
|
||||||
|
|
||||||
|
static int mlx4_create_zones(struct mlx4_dev *dev,
|
||||||
|
u32 reserved_bottom_general,
|
||||||
|
u32 reserved_top_general,
|
||||||
|
u32 reserved_bottom_rss,
|
||||||
|
u32 start_offset_rss,
|
||||||
|
u32 max_table_offset)
|
||||||
|
{
|
||||||
|
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
||||||
|
struct mlx4_bitmap (*bitmap)[MLX4_QP_TABLE_ZONE_NUM] = NULL;
|
||||||
|
int bitmap_initialized = 0;
|
||||||
|
u32 last_offset;
|
||||||
|
int k;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
qp_table->zones = mlx4_zone_allocator_create(MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP);
|
||||||
|
|
||||||
|
if (NULL == qp_table->zones)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (NULL == bitmap) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto free_zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mlx4_bitmap_init(*bitmap + MLX4_QP_TABLE_ZONE_GENERAL, dev->caps.num_qps,
|
||||||
|
(1 << 23) - 1, reserved_bottom_general,
|
||||||
|
reserved_top_general);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto free_bitmap;
|
||||||
|
|
||||||
|
++bitmap_initialized;
|
||||||
|
|
||||||
|
err = mlx4_zone_add_one(qp_table->zones, *bitmap + MLX4_QP_TABLE_ZONE_GENERAL,
|
||||||
|
MLX4_ZONE_FALLBACK_TO_HIGHER_PRIO |
|
||||||
|
MLX4_ZONE_USE_RR, 0,
|
||||||
|
0, qp_table->zones_uids + MLX4_QP_TABLE_ZONE_GENERAL);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto free_bitmap;
|
||||||
|
|
||||||
|
err = mlx4_bitmap_init(*bitmap + MLX4_QP_TABLE_ZONE_RSS,
|
||||||
|
reserved_bottom_rss,
|
||||||
|
reserved_bottom_rss - 1,
|
||||||
|
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
|
||||||
|
reserved_bottom_rss - start_offset_rss);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto free_bitmap;
|
||||||
|
|
||||||
|
++bitmap_initialized;
|
||||||
|
|
||||||
|
err = mlx4_zone_add_one(qp_table->zones, *bitmap + MLX4_QP_TABLE_ZONE_RSS,
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO |
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO |
|
||||||
|
MLX4_ZONE_USE_RR, MLX4_QP_TABLE_RSS_ETH_PRIORITY,
|
||||||
|
0, qp_table->zones_uids + MLX4_QP_TABLE_ZONE_RSS);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto free_bitmap;
|
||||||
|
|
||||||
|
last_offset = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
|
||||||
|
/* We have a single zone for the A0 steering QPs area of the FW. This area
|
||||||
|
* needs to be split into subareas. One set of subareas is for RSS QPs
|
||||||
|
* (in which qp number bits 6 and/or 7 are set); the other set of subareas
|
||||||
|
* is for RAW_ETH QPs, which require that both bits 6 and 7 are zero.
|
||||||
|
* Currently, the values returned by the FW (A0 steering area starting qp number
|
||||||
|
* and A0 steering area size) are such that there are only two subareas -- one
|
||||||
|
* for RSS and one for RAW_ETH.
|
||||||
|
*/
|
||||||
|
for (k = MLX4_QP_TABLE_ZONE_RSS + 1; k < sizeof(*bitmap)/sizeof((*bitmap)[0]);
|
||||||
|
k++) {
|
||||||
|
int size;
|
||||||
|
u32 offset = start_offset_rss;
|
||||||
|
u32 bf_mask;
|
||||||
|
u32 requested_size;
|
||||||
|
|
||||||
|
/* Assuming MLX4_BF_QP_SKIP_MASK is consecutive ones, this calculates
|
||||||
|
* a mask of all LSB bits set until (and not including) the first
|
||||||
|
* set bit of MLX4_BF_QP_SKIP_MASK. For example, if MLX4_BF_QP_SKIP_MASK
|
||||||
|
* is 0xc0, bf_mask will be 0x3f.
|
||||||
|
*/
|
||||||
|
bf_mask = (MLX4_BF_QP_SKIP_MASK & ~(MLX4_BF_QP_SKIP_MASK - 1)) - 1;
|
||||||
|
requested_size = min((u32)MLX4_QP_TABLE_RAW_ETH_SIZE, bf_mask + 1);
|
||||||
|
|
||||||
|
if (((last_offset & MLX4_BF_QP_SKIP_MASK) &&
|
||||||
|
((int)(max_table_offset - last_offset)) >=
|
||||||
|
roundup_pow_of_two(MLX4_BF_QP_SKIP_MASK)) ||
|
||||||
|
(!(last_offset & MLX4_BF_QP_SKIP_MASK) &&
|
||||||
|
!((last_offset + requested_size - 1) &
|
||||||
|
MLX4_BF_QP_SKIP_MASK)))
|
||||||
|
size = requested_size;
|
||||||
|
else {
|
||||||
|
u32 candidate_offset =
|
||||||
|
(last_offset | MLX4_BF_QP_SKIP_MASK | bf_mask) + 1;
|
||||||
|
|
||||||
|
if (last_offset & MLX4_BF_QP_SKIP_MASK)
|
||||||
|
last_offset = candidate_offset;
|
||||||
|
|
||||||
|
/* From this point, the BF bits are 0 */
|
||||||
|
|
||||||
|
if (last_offset > max_table_offset) {
|
||||||
|
/* need to skip */
|
||||||
|
size = -1;
|
||||||
|
} else {
|
||||||
|
size = min3(max_table_offset - last_offset,
|
||||||
|
bf_mask - (last_offset & bf_mask),
|
||||||
|
requested_size);
|
||||||
|
if (size < requested_size) {
|
||||||
|
int candidate_size;
|
||||||
|
|
||||||
|
candidate_size = min3(
|
||||||
|
max_table_offset - candidate_offset,
|
||||||
|
bf_mask - (last_offset & bf_mask),
|
||||||
|
requested_size);
|
||||||
|
|
||||||
|
/* We will not take this path if last_offset was
|
||||||
|
* already set above to candidate_offset
|
||||||
|
*/
|
||||||
|
if (candidate_size > size) {
|
||||||
|
last_offset = candidate_offset;
|
||||||
|
size = candidate_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
/* mlx4_bitmap_alloc_range will find a contiguous range of "size"
|
||||||
|
* QPs in which both bits 6 and 7 are zero, because we pass it the
|
||||||
|
* MLX4_BF_SKIP_MASK).
|
||||||
|
*/
|
||||||
|
offset = mlx4_bitmap_alloc_range(
|
||||||
|
*bitmap + MLX4_QP_TABLE_ZONE_RSS,
|
||||||
|
size, 1,
|
||||||
|
MLX4_BF_QP_SKIP_MASK);
|
||||||
|
|
||||||
|
if (offset == (u32)-1) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_offset = offset + size;
|
||||||
|
|
||||||
|
err = mlx4_bitmap_init(*bitmap + k, roundup_pow_of_two(size),
|
||||||
|
roundup_pow_of_two(size) - 1, 0,
|
||||||
|
roundup_pow_of_two(size) - size);
|
||||||
|
} else {
|
||||||
|
/* Add an empty bitmap, we'll allocate from different zones (since
|
||||||
|
* at least one is reserved)
|
||||||
|
*/
|
||||||
|
err = mlx4_bitmap_init(*bitmap + k, 1,
|
||||||
|
MLX4_QP_TABLE_RAW_ETH_SIZE - 1, 0,
|
||||||
|
0);
|
||||||
|
mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
|
||||||
|
++bitmap_initialized;
|
||||||
|
|
||||||
|
err = mlx4_zone_add_one(qp_table->zones, *bitmap + k,
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO |
|
||||||
|
MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO |
|
||||||
|
MLX4_ZONE_USE_RR, MLX4_QP_TABLE_RAW_ETH_PRIORITY,
|
||||||
|
offset, qp_table->zones_uids + k);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto free_bitmap;
|
||||||
|
|
||||||
|
qp_table->bitmap_gen = *bitmap;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
|
||||||
|
free_bitmap:
|
||||||
|
for (k = 0; k < bitmap_initialized; k++)
|
||||||
|
mlx4_bitmap_cleanup(*bitmap + k);
|
||||||
|
kfree(bitmap);
|
||||||
|
free_zone:
|
||||||
|
mlx4_zone_allocator_destroy(qp_table->zones);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx4_cleanup_qp_zones(struct mlx4_dev *dev)
|
||||||
|
{
|
||||||
|
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
||||||
|
|
||||||
|
if (qp_table->zones) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
i < sizeof(qp_table->zones_uids)/sizeof(qp_table->zones_uids[0]);
|
||||||
|
i++) {
|
||||||
|
struct mlx4_bitmap *bitmap =
|
||||||
|
mlx4_zone_get_bitmap(qp_table->zones,
|
||||||
|
qp_table->zones_uids[i]);
|
||||||
|
|
||||||
|
mlx4_zone_remove_one(qp_table->zones, qp_table->zones_uids[i]);
|
||||||
|
if (NULL == bitmap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mlx4_bitmap_cleanup(bitmap);
|
||||||
|
}
|
||||||
|
mlx4_zone_allocator_destroy(qp_table->zones);
|
||||||
|
kfree(qp_table->bitmap_gen);
|
||||||
|
qp_table->bitmap_gen = NULL;
|
||||||
|
qp_table->zones = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int mlx4_init_qp_table(struct mlx4_dev *dev)
|
int mlx4_init_qp_table(struct mlx4_dev *dev)
|
||||||
{
|
{
|
||||||
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
|
||||||
int err;
|
int err;
|
||||||
int reserved_from_top = 0;
|
int reserved_from_top = 0;
|
||||||
|
int reserved_from_bot;
|
||||||
int k;
|
int k;
|
||||||
|
int fixed_reserved_from_bot_rv = 0;
|
||||||
|
int bottom_reserved_for_rss_bitmap;
|
||||||
|
u32 max_table_offset = dev->caps.dmfs_high_rate_qpn_base +
|
||||||
|
dev->caps.dmfs_high_rate_qpn_range;
|
||||||
|
|
||||||
spin_lock_init(&qp_table->lock);
|
spin_lock_init(&qp_table->lock);
|
||||||
INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
|
INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
|
||||||
if (mlx4_is_slave(dev))
|
if (mlx4_is_slave(dev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/* We reserve 2 extra QPs per port for the special QPs. The
|
||||||
* We reserve 2 extra QPs per port for the special QPs. The
|
|
||||||
* block of special QPs must be aligned to a multiple of 8, so
|
* block of special QPs must be aligned to a multiple of 8, so
|
||||||
* round up.
|
* round up.
|
||||||
*
|
*
|
||||||
* We also reserve the MSB of the 24-bit QP number to indicate
|
* We also reserve the MSB of the 24-bit QP number to indicate
|
||||||
* that a QP is an XRC QP.
|
* that a QP is an XRC QP.
|
||||||
*/
|
*/
|
||||||
dev->phys_caps.base_sqpn =
|
for (k = 0; k <= MLX4_QP_REGION_BOTTOM; k++)
|
||||||
ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
|
fixed_reserved_from_bot_rv += dev->caps.reserved_qps_cnt[k];
|
||||||
|
|
||||||
|
if (fixed_reserved_from_bot_rv < max_table_offset)
|
||||||
|
fixed_reserved_from_bot_rv = max_table_offset;
|
||||||
|
|
||||||
|
/* We reserve at least 1 extra for bitmaps that we don't have enough space for*/
|
||||||
|
bottom_reserved_for_rss_bitmap =
|
||||||
|
roundup_pow_of_two(fixed_reserved_from_bot_rv + 1);
|
||||||
|
dev->phys_caps.base_sqpn = ALIGN(bottom_reserved_for_rss_bitmap, 8);
|
||||||
|
|
||||||
{
|
{
|
||||||
int sort[MLX4_NUM_QP_REGION];
|
int sort[MLX4_NUM_QP_REGION];
|
||||||
@ -490,8 +746,8 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
|
|||||||
for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
|
for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
|
||||||
sort[i] = i;
|
sort[i] = i;
|
||||||
|
|
||||||
for (i = MLX4_NUM_QP_REGION; i > 0; --i) {
|
for (i = MLX4_NUM_QP_REGION; i > MLX4_QP_REGION_BOTTOM; --i) {
|
||||||
for (j = 2; j < i; ++j) {
|
for (j = MLX4_QP_REGION_BOTTOM + 2; j < i; ++j) {
|
||||||
if (dev->caps.reserved_qps_cnt[sort[j]] >
|
if (dev->caps.reserved_qps_cnt[sort[j]] >
|
||||||
dev->caps.reserved_qps_cnt[sort[j - 1]]) {
|
dev->caps.reserved_qps_cnt[sort[j - 1]]) {
|
||||||
tmp = sort[j];
|
tmp = sort[j];
|
||||||
@ -501,13 +757,12 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 1; i < MLX4_NUM_QP_REGION; ++i) {
|
for (i = MLX4_QP_REGION_BOTTOM + 1; i < MLX4_NUM_QP_REGION; ++i) {
|
||||||
last_base -= dev->caps.reserved_qps_cnt[sort[i]];
|
last_base -= dev->caps.reserved_qps_cnt[sort[i]];
|
||||||
dev->caps.reserved_qps_base[sort[i]] = last_base;
|
dev->caps.reserved_qps_base[sort[i]] = last_base;
|
||||||
reserved_from_top +=
|
reserved_from_top +=
|
||||||
dev->caps.reserved_qps_cnt[sort[i]];
|
dev->caps.reserved_qps_cnt[sort[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve 8 real SQPs in both native and SRIOV modes.
|
/* Reserve 8 real SQPs in both native and SRIOV modes.
|
||||||
@ -520,10 +775,17 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
|
|||||||
* b. All the proxy SQPs (8 per function)
|
* b. All the proxy SQPs (8 per function)
|
||||||
* c. All the tunnel QPs (8 per function)
|
* c. All the tunnel QPs (8 per function)
|
||||||
*/
|
*/
|
||||||
|
reserved_from_bot = mlx4_num_reserved_sqps(dev);
|
||||||
|
if (reserved_from_bot + reserved_from_top > dev->caps.num_qps) {
|
||||||
|
mlx4_err(dev, "Number of reserved QPs is higher than number of QPs\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mlx4_create_zones(dev, reserved_from_bot, reserved_from_bot,
|
||||||
|
bottom_reserved_for_rss_bitmap,
|
||||||
|
fixed_reserved_from_bot_rv,
|
||||||
|
max_table_offset);
|
||||||
|
|
||||||
err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
|
|
||||||
(1 << 23) - 1, mlx4_num_reserved_sqps(dev),
|
|
||||||
reserved_from_top);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -559,7 +821,8 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
|
|||||||
err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn);
|
err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_mem;
|
goto err_mem;
|
||||||
return 0;
|
|
||||||
|
return err;
|
||||||
|
|
||||||
err_mem:
|
err_mem:
|
||||||
kfree(dev->caps.qp0_tunnel);
|
kfree(dev->caps.qp0_tunnel);
|
||||||
@ -568,6 +831,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
|
|||||||
kfree(dev->caps.qp1_proxy);
|
kfree(dev->caps.qp1_proxy);
|
||||||
dev->caps.qp0_tunnel = dev->caps.qp0_proxy =
|
dev->caps.qp0_tunnel = dev->caps.qp0_proxy =
|
||||||
dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL;
|
dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL;
|
||||||
|
mlx4_cleanup_qp_zones(dev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,7 +841,8 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
mlx4_CONF_SPECIAL_QP(dev, 0);
|
mlx4_CONF_SPECIAL_QP(dev, 0);
|
||||||
mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap);
|
|
||||||
|
mlx4_cleanup_qp_zones(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
|
int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
|
||||||
|
@ -1543,16 +1543,21 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
|
|||||||
int align;
|
int align;
|
||||||
int base;
|
int base;
|
||||||
int qpn;
|
int qpn;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case RES_OP_RESERVE:
|
case RES_OP_RESERVE:
|
||||||
count = get_param_l(&in_param) & 0xffffff;
|
count = get_param_l(&in_param) & 0xffffff;
|
||||||
|
/* Turn off all unsupported QP allocation flags that the
|
||||||
|
* slave tries to set.
|
||||||
|
*/
|
||||||
|
flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask;
|
||||||
align = get_param_h(&in_param);
|
align = get_param_h(&in_param);
|
||||||
err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
|
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);
|
err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);
|
||||||
if (err) {
|
if (err) {
|
||||||
mlx4_release_resource(dev, slave, RES_QP, count, 0);
|
mlx4_release_resource(dev, slave, RES_QP, count, 0);
|
||||||
return err;
|
return err;
|
||||||
|
@ -117,6 +117,14 @@ enum {
|
|||||||
MLX4_STEERING_MODE_DEVICE_MANAGED
|
MLX4_STEERING_MODE_DEVICE_MANAGED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MLX4_STEERING_DMFS_A0_DEFAULT,
|
||||||
|
MLX4_STEERING_DMFS_A0_DYNAMIC,
|
||||||
|
MLX4_STEERING_DMFS_A0_STATIC,
|
||||||
|
MLX4_STEERING_DMFS_A0_DISABLE,
|
||||||
|
MLX4_STEERING_DMFS_A0_NOT_SUPPORTED
|
||||||
|
};
|
||||||
|
|
||||||
static inline const char *mlx4_steering_mode_str(int steering_mode)
|
static inline const char *mlx4_steering_mode_str(int steering_mode)
|
||||||
{
|
{
|
||||||
switch (steering_mode) {
|
switch (steering_mode) {
|
||||||
@ -191,7 +199,26 @@ enum {
|
|||||||
MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP = 1LL << 15,
|
MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP = 1LL << 15,
|
||||||
MLX4_DEV_CAP_FLAG2_CONFIG_DEV = 1LL << 16,
|
MLX4_DEV_CAP_FLAG2_CONFIG_DEV = 1LL << 16,
|
||||||
MLX4_DEV_CAP_FLAG2_SYS_EQS = 1LL << 17,
|
MLX4_DEV_CAP_FLAG2_SYS_EQS = 1LL << 17,
|
||||||
MLX4_DEV_CAP_FLAG2_80_VFS = 1LL << 18
|
MLX4_DEV_CAP_FLAG2_80_VFS = 1LL << 18,
|
||||||
|
MLX4_DEV_CAP_FLAG2_FS_A0 = 1LL << 19
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MLX4_QUERY_FUNC_FLAGS_BF_RES_QP = 1LL << 0,
|
||||||
|
MLX4_QUERY_FUNC_FLAGS_A0_RES_QP = 1LL << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* bit enums for an 8-bit flags field indicating special use
|
||||||
|
* QPs which require special handling in qp_reserve_range.
|
||||||
|
* Currently, this only includes QPs used by the ETH interface,
|
||||||
|
* where we expect to use blueflame. These QPs must not have
|
||||||
|
* bits 6 and 7 set in their qp number.
|
||||||
|
*
|
||||||
|
* This enum may use only bits 0..7.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
MLX4_RESERVE_A0_QP = 1 << 6,
|
||||||
|
MLX4_RESERVE_ETH_BF_QP = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -207,7 +234,8 @@ enum {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
MLX4_FUNC_CAP_64B_EQE_CQE = 1L << 0,
|
MLX4_FUNC_CAP_64B_EQE_CQE = 1L << 0,
|
||||||
MLX4_FUNC_CAP_EQE_CQE_STRIDE = 1L << 1
|
MLX4_FUNC_CAP_EQE_CQE_STRIDE = 1L << 1,
|
||||||
|
MLX4_FUNC_CAP_DMFS_A0_STATIC = 1L << 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -333,6 +361,8 @@ enum {
|
|||||||
|
|
||||||
enum mlx4_qp_region {
|
enum mlx4_qp_region {
|
||||||
MLX4_QP_REGION_FW = 0,
|
MLX4_QP_REGION_FW = 0,
|
||||||
|
MLX4_QP_REGION_RSS_RAW_ETH,
|
||||||
|
MLX4_QP_REGION_BOTTOM = MLX4_QP_REGION_RSS_RAW_ETH,
|
||||||
MLX4_QP_REGION_ETH_ADDR,
|
MLX4_QP_REGION_ETH_ADDR,
|
||||||
MLX4_QP_REGION_FC_ADDR,
|
MLX4_QP_REGION_FC_ADDR,
|
||||||
MLX4_QP_REGION_FC_EXCH,
|
MLX4_QP_REGION_FC_EXCH,
|
||||||
@ -462,6 +492,7 @@ struct mlx4_caps {
|
|||||||
int reserved_mcgs;
|
int reserved_mcgs;
|
||||||
int num_qp_per_mgm;
|
int num_qp_per_mgm;
|
||||||
int steering_mode;
|
int steering_mode;
|
||||||
|
int dmfs_high_steer_mode;
|
||||||
int fs_log_max_ucast_qp_range_size;
|
int fs_log_max_ucast_qp_range_size;
|
||||||
int num_pds;
|
int num_pds;
|
||||||
int reserved_pds;
|
int reserved_pds;
|
||||||
@ -501,6 +532,9 @@ struct mlx4_caps {
|
|||||||
u64 phys_port_id[MLX4_MAX_PORTS + 1];
|
u64 phys_port_id[MLX4_MAX_PORTS + 1];
|
||||||
int tunnel_offload_mode;
|
int tunnel_offload_mode;
|
||||||
u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1];
|
u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1];
|
||||||
|
u8 alloc_res_qp_mask;
|
||||||
|
u32 dmfs_high_rate_qpn_base;
|
||||||
|
u32 dmfs_high_rate_qpn_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_buf_list {
|
struct mlx4_buf_list {
|
||||||
@ -621,6 +655,11 @@ struct mlx4_cq {
|
|||||||
|
|
||||||
atomic_t refcount;
|
atomic_t refcount;
|
||||||
struct completion free;
|
struct completion free;
|
||||||
|
struct {
|
||||||
|
struct list_head list;
|
||||||
|
void (*comp)(struct mlx4_cq *);
|
||||||
|
void *priv;
|
||||||
|
} tasklet_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_qp {
|
struct mlx4_qp {
|
||||||
@ -869,7 +908,9 @@ static inline int mlx4_num_reserved_sqps(struct mlx4_dev *dev)
|
|||||||
static inline int mlx4_is_qp_reserved(struct mlx4_dev *dev, u32 qpn)
|
static inline int mlx4_is_qp_reserved(struct mlx4_dev *dev, u32 qpn)
|
||||||
{
|
{
|
||||||
return (qpn < dev->phys_caps.base_sqpn + 8 +
|
return (qpn < dev->phys_caps.base_sqpn + 8 +
|
||||||
16 * MLX4_MFUNC_MAX * !!mlx4_is_master(dev));
|
16 * MLX4_MFUNC_MAX * !!mlx4_is_master(dev) &&
|
||||||
|
qpn >= dev->phys_caps.base_sqpn) ||
|
||||||
|
(qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int mlx4_is_guest_proxy(struct mlx4_dev *dev, int slave, u32 qpn)
|
static inline int mlx4_is_guest_proxy(struct mlx4_dev *dev, int slave, u32 qpn)
|
||||||
@ -945,8 +986,8 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
|
|||||||
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
|
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
|
||||||
unsigned vector, int collapsed, int timestamp_en);
|
unsigned vector, int collapsed, int timestamp_en);
|
||||||
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
|
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
|
||||||
|
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
|
||||||
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
|
int *base, u8 flags);
|
||||||
void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
|
void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
|
||||||
|
|
||||||
int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp,
|
int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp,
|
||||||
|
Loading…
Reference in New Issue
Block a user