Commit efef7939 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 630f4b70 7d077cd3
......@@ -233,7 +233,10 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
if (err)
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;
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;
err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
MLX4_IB_UC_STEER_QPN_ALIGN,
&ibdev->steer_qpn_base);
&ibdev->steer_qpn_base, 0);
if (err)
goto err_counter;
......
......@@ -802,16 +802,21 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
}
}
} else {
/* Raw packet QPNs must be aligned to 8 bits. If not, the WQE
* BlueFlame setup flow wrongly causes VLAN insertion. */
/* Raw packet QPNs may not have bits 6,7 set in their qp_num;
* otherwise, the WQE BlueFlame setup flow wrongly causes
* VLAN insertion. */
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
if (qp->flags & MLX4_IB_QP_NETIF)
err = mlx4_ib_steer_qp_alloc(dev, 1, &qpn);
else
err = mlx4_qp_reserve_range(dev->dev, 1, 1,
&qpn);
&qpn, 0);
if (err)
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);
}
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;
if (likely(cnt == 1 && align == 1))
if (likely(cnt == 1 && align == 1 && !skip_mask))
return mlx4_bitmap_alloc(bitmap);
spin_lock(&bitmap->lock);
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
bitmap->last, cnt, align - 1);
obj = find_aligned_range(bitmap->table, bitmap->last,
bitmap->max, cnt, align, skip_mask);
if (obj >= bitmap->max) {
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
& bitmap->mask;
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
0, cnt, align - 1);
obj = find_aligned_range(bitmap->table, 0, bitmap->max,
cnt, align, skip_mask);
}
if (obj < bitmap->max) {
......@@ -118,6 +149,11 @@ u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap)
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,
int use_rr)
{
......@@ -147,6 +183,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
bitmap->mask = mask;
bitmap->reserved_top = reserved_top;
bitmap->avail = num - reserved_top - reserved_bot;
bitmap->effective_len = bitmap->avail;
spin_lock_init(&bitmap->lock);
bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) *
sizeof (long), GFP_KERNEL);
......@@ -163,6 +200,382 @@ void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
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
* 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_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)
{
struct mlx4_cq *cq;
......@@ -292,6 +337,11 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
cq->uar = uar;
atomic_set(&cq->refcount, 1);
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;
return 0;
......
......@@ -595,7 +595,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
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);
if (err) {
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;
int i;
int err;
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 */
for (i = 0; i < priv->tx_ring_num; i++) {
node = cpu_to_node(i % num_online_cpus());
......@@ -1991,7 +1984,6 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
goto err;
if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i],
priv->base_tx_qpn + i,
prof->tx_ring_size, TXBB_SIZE,
node, i))
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;
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;
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;
if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
gro_skb->encapsulation = 1;
gro_skb->csum_level = 1;
if ((cqe->vlan_my_qpn &
cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
(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;
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) {
en_err(priv, "Failed reserving drop qpn\n");
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");
err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num,
priv->rx_ring_num,
&rss_map->base_qpn);
&rss_map->base_qpn, 0);
if (err) {
en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num);
return err;
......
......@@ -46,7 +46,7 @@
#include "mlx4_en.h"
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)
{
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,
(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);
if (err) {
en_err(priv, "Failed allocating qp %d\n", ring->qpn);
goto err_map;
goto err_reserve;
}
ring->qp.event = mlx4_en_sqp_event;
......@@ -143,6 +149,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
*pring = ring;
return 0;
err_reserve:
mlx4_qp_release_range(mdev->dev, ring->qpn, 1);
err_map:
mlx4_en_unmap_buffer(&ring->wqres.buf);
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_eqe *eqe;
int cqn;
int cqn = -1;
int eqes_found = 0;
int set_ci = 0;
int port;
......@@ -758,6 +758,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
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;
}
......@@ -971,6 +978,12 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
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;
err_out_free_mtt:
......@@ -1027,6 +1040,7 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
}
}
synchronize_irq(eq->irq);
tasklet_disable(&eq->tasklet_ctx.task);
mlx4_mtt_cleanup(dev, &eq->mtt);
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",
[16] = "CONFIG DEV 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;
......@@ -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_MCG_QUOTA_OFFSET 0x68
#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET 0x6c
#define QUERY_FUNC_CAP_FMR_FLAG 0x80
#define QUERY_FUNC_CAP_FLAG_RDMA 0x40
#define QUERY_FUNC_CAP_FLAG_ETH 0x80
#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 */
#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);
/* enable rdma and ethernet interfaces, and new quota locations */
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);
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_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
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);
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;
}
......@@ -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_VXLAN 0x9e
#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;
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))
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);
if (field32 & (1 << 16))
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))
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) {
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
dev_cap->max_vl[i] = field >> 4;
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);
}
for (i = 1; i <= dev_cap->num_ports; i++) {
err = mlx4_QUERY_PORT(dev, i, dev_cap->port_cap + i);
if (err)
goto out;
}
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",
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",
dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
dev_cap->max_port_width[1]);
dev_cap->local_ca_ack_delay, 128 << dev_cap->port_cap[1].ib_mtu,
dev_cap->port_cap[1].max_port_width);
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);
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 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, "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_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;
}
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,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
......@@ -982,7 +1050,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
u64 flags;
int err = 0;
u8 field;
u32 bmme_flags;
u32 bmme_flags, field32;
int real_port;
int slave_port;
int first_port;
......@@ -1053,6 +1121,12 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
field &= ~0x80;
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;
}
......@@ -1471,6 +1545,12 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
struct mlx4_cmd_mailbox *mailbox;
__be32 *inbox;
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_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_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_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_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21)
#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
* with udp unicast and tcp unicast
*/
MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
INIT_HCA_FS_ETH_BITS_OFFSET);
if (dev->caps.dmfs_high_steer_mode !=
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,
INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
/* 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);
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
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 {
MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET);
MLX4_PUT(inbox, param->log_mc_entry_sz,
......@@ -1675,6 +1766,12 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
u32 dword_field;
int err;
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_CORE_CLOCK_OFFSET 0x0c
......@@ -1727,6 +1824,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
MLX4_GET(param->log_mc_table_sz, outbox,
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 {
MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
MLX4_GET(param->log_mc_entry_sz, outbox,
......
......@@ -43,6 +43,26 @@ struct mlx4_mod_stat_cfg {
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 {
int max_srq_sz;
int max_qp_sz;
......@@ -67,17 +87,6 @@ struct mlx4_dev_cap {
int local_ca_ack_delay;
int num_ports;
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;
int fs_log_max_ucast_qp_range_size;
int fs_max_num_qp_per_entry;
......@@ -115,12 +124,10 @@ struct mlx4_dev_cap {
u64 max_icm_sz;
int max_gso_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 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 {
......@@ -144,6 +151,7 @@ struct mlx4_func_cap {
u8 port_flags;
u8 flags1;
u64 phys_port_id;
u32 extra_flags;
};
struct mlx4_func {
......@@ -189,6 +197,7 @@ struct mlx4_init_hca_param {
u8 mw_enabled; /* Enable memory windows */
u8 uar_page_sz; /* log pg sz in 4k chunks */
u8 steering_mode; /* for QUERY_HCA */
u8 dmfs_high_steer_mode; /* for QUERY_HCA */
u64 dev_cap_enabled;
u16 cqe_size; /* For use only when CQE 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_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,
struct mlx4_func_cap *func_cap);
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)");
#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[] =
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)
{
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 :
MLX4_MAX_EQ_NUM;
for (i = 1; i <= dev->caps.num_ports; ++i) {
dev->caps.vl_cap[i] = dev_cap->max_vl[i];
dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i];
dev->phys_caps.gid_phys_table_len[i] = dev_cap->max_gids[i];
dev->phys_caps.pkey_phys_table_len[i] = dev_cap->max_pkeys[i];
/* 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];
err = _mlx4_dev_port(dev, i, dev_cap->port_cap + i);
if (err) {
mlx4_err(dev, "QUERY_PORT command failed, aborting\n");
return err;
}
}
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];
}
if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
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->port_cap[i].log_max_macs;
mlx4_warn(dev, "Requested number of MACs is too much for port %d, reducing to %d\n",
i, 1 << dev->caps.log_num_macs);
}
if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) {
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->port_cap[i].log_max_vlans;
mlx4_warn(dev, "Requested number of VLANs is too much for port %d, reducing to %d\n",
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.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_cnt[MLX4_QP_REGION_ETH_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))
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);
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;
}
......@@ -718,7 +774,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
if ((func_cap.pf_context_behaviour | 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;
}
......@@ -817,6 +874,13 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
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;
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;
}
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,
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 &&
(!mlx4_is_mfunc(dev) ||
(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_cap->fs_log_max_ucast_qp_range_size;
} 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 &&
dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
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)
{
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;
else
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");
}
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)
{
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_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);
if (err)
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");
}
}
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 {
err = mlx4_init_slave(dev);
if (err) {
......@@ -3159,10 +3314,11 @@ static int __init mlx4_verify_params(void)
port_type_array[0] = true;
}
if (mlx4_log_num_mgm_entry_size != -1 &&
(mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE ||
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 (-1 or %d..%d)\n",
if (mlx4_log_num_mgm_entry_size < -7 ||
(mlx4_log_num_mgm_entry_size > 0 &&
(mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE ||
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_MIN_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);
if (ret == -ENOMEM)
if (ret == -ENOMEM) {
mlx4_err_rule(dev,
"mcg table is full. Fail to register network rule\n",
rule);
else if (ret)
mlx4_err_rule(dev, "Fail to register network rule\n", rule);
} else if (ret) {
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);
......
......@@ -43,6 +43,8 @@
#include <linux/timer.h>
#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h>
......@@ -243,6 +245,7 @@ struct mlx4_bitmap {
u32 reserved_top;
u32 mask;
u32 avail;
u32 effective_len;
spinlock_t lock;
unsigned long *table;
};
......@@ -373,6 +376,14 @@ struct mlx4_srq_context {
__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_dev *dev;
void __iomem *doorbell;
......@@ -383,6 +394,7 @@ struct mlx4_eq {
int nent;
struct mlx4_buf_list *page_list;
struct mlx4_mtt mtt;
struct mlx4_eq_tasklet tasklet_ctx;
};
struct mlx4_slave_eqe {
......@@ -670,8 +682,17 @@ struct mlx4_srq_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_bitmap bitmap;
struct mlx4_bitmap *bitmap_gen;
struct mlx4_zone_allocator *zones;
u32 zones_uids[MLX4_QP_TABLE_ZONE_NUM];
u32 rdmarc_base;
int rdmarc_shift;
spinlock_t lock;
......@@ -873,7 +894,8 @@ extern struct workqueue_struct *mlx4_wq;
u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
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,
int use_rr);
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_info *cmd);
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);
int __mlx4_register_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,
unsigned long timeout);
void mlx4_cq_tasklet_cb(unsigned long data);
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
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_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 */
......@@ -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,
struct mlx4_en_tx_ring **pring,
int qpn, u32 size, u16 stride,
u32 size, u16 stride,
int node, int queue_index);
void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring **pring);
......
......@@ -42,6 +42,10 @@
#include "mlx4.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)
{
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);
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_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)
return -ENOMEM;
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 out_param;
int err;
/* Turn off all unsupported QP allocation flags */
flags &= dev->caps.alloc_res_qp_mask;
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);
err = mlx4_cmd_imm(dev, in_param, &out_param,
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);
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);
......@@ -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))
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)
......@@ -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);
}
#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)
{
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
int err;
int reserved_from_top = 0;
int reserved_from_bot;
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);
INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
if (mlx4_is_slave(dev))
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
* round up.
*
* We also reserve the MSB of the 24-bit QP number to indicate
* that a QP is an XRC QP.
*/
dev->phys_caps.base_sqpn =
ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
for (k = 0; k <= MLX4_QP_REGION_BOTTOM; k++)
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];
......@@ -490,8 +746,8 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
sort[i] = i;
for (i = MLX4_NUM_QP_REGION; i > 0; --i) {
for (j = 2; j < i; ++j) {
for (i = MLX4_NUM_QP_REGION; i > MLX4_QP_REGION_BOTTOM; --i) {
for (j = MLX4_QP_REGION_BOTTOM + 2; j < i; ++j) {
if (dev->caps.reserved_qps_cnt[sort[j]] >
dev->caps.reserved_qps_cnt[sort[j - 1]]) {
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]];
dev->caps.reserved_qps_base[sort[i]] = last_base;
reserved_from_top +=
dev->caps.reserved_qps_cnt[sort[i]];
}
}
/* 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)
* 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)
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);
if (err)
goto err_mem;
return 0;
return err;
err_mem:
kfree(dev->caps.qp0_tunnel);
......@@ -568,6 +831,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
kfree(dev->caps.qp1_proxy);
dev->caps.qp0_tunnel = dev->caps.qp0_proxy =
dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL;
mlx4_cleanup_qp_zones(dev);
return err;
}
......@@ -577,7 +841,8 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
return;
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,
......
......@@ -1543,16 +1543,21 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
int align;
int base;
int qpn;
u8 flags;
switch (op) {
case RES_OP_RESERVE:
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);
err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
if (err)
return err;
err = __mlx4_qp_reserve_range(dev, count, align, &base);
err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);
if (err) {
mlx4_release_resource(dev, slave, RES_QP, count, 0);
return err;
......
......@@ -117,6 +117,14 @@ enum {
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)
{
switch (steering_mode) {
......@@ -191,7 +199,26 @@ enum {
MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP = 1LL << 15,
MLX4_DEV_CAP_FLAG2_CONFIG_DEV = 1LL << 16,
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 {
......@@ -207,7 +234,8 @@ enum {
enum {
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 {
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_FC_ADDR,
MLX4_QP_REGION_FC_EXCH,
......@@ -462,6 +492,7 @@ struct mlx4_caps {
int reserved_mcgs;
int num_qp_per_mgm;
int steering_mode;
int dmfs_high_steer_mode;
int fs_log_max_ucast_qp_range_size;
int num_pds;
int reserved_pds;
......@@ -501,6 +532,9 @@ struct mlx4_caps {
u64 phys_port_id[MLX4_MAX_PORTS + 1];
int tunnel_offload_mode;
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 {
......@@ -621,6 +655,11 @@ struct mlx4_cq {
atomic_t refcount;
struct completion free;
struct {
struct list_head list;
void (*comp)(struct mlx4_cq *);
void *priv;
} tasklet_ctx;
};
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)
{
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)
......@@ -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,
unsigned vector, int collapsed, int timestamp_en);
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 *base);
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
int *base, u8 flags);
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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment