Commit ff7166c4 authored by Jack Morgenstein's avatar Jack Morgenstein Committed by Roland Dreier

IB/core: Handle table with full and partial membership for the same P_Key

Extend the cached and non-cached P_Key table lookups to handle limited
and full membership of the same P_Key to co-exist in the P_Key table.

This is necessary for SR-IOV, to allow for some guests would to have
the full membership P_Key in their virtual P_Key table, while other
guests on the same physical HCA would have the limited one.
To support this, we need both the limited and full membership P_Keys
to be present in the master's (hypervisor physical port) P_Key table.

The algorithm for handling P_Key tables which contain both the limited
and the full membership versions of the same P_Key works as follows:

When scanning the P_Key table for a 15-bit P_Key:

A. If there is a full member version of that P_Key anywhere in the
    table, return its index (even if a limited-member version of the
    P_Key exists earlier in the table).

B. If the full member version is not in the table, but the
   limited-member version is in the table, return the index of the
   limited P_Key.
Signed-off-by: default avatarLiran Liss <liranl@mellanox.com>
Signed-off-by: default avatarJack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent d2b57063
...@@ -167,6 +167,7 @@ int ib_find_cached_pkey(struct ib_device *device, ...@@ -167,6 +167,7 @@ int ib_find_cached_pkey(struct ib_device *device,
unsigned long flags; unsigned long flags;
int i; int i;
int ret = -ENOENT; int ret = -ENOENT;
int partial_ix = -1;
if (port_num < start_port(device) || port_num > end_port(device)) if (port_num < start_port(device) || port_num > end_port(device))
return -EINVAL; return -EINVAL;
...@@ -179,11 +180,19 @@ int ib_find_cached_pkey(struct ib_device *device, ...@@ -179,11 +180,19 @@ int ib_find_cached_pkey(struct ib_device *device,
for (i = 0; i < cache->table_len; ++i) for (i = 0; i < cache->table_len; ++i)
if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
*index = i; if (cache->table[i] & 0x8000) {
ret = 0; *index = i;
break; ret = 0;
break;
} else
partial_ix = i;
} }
if (ret && partial_ix >= 0) {
*index = partial_ix;
ret = 0;
}
read_unlock_irqrestore(&device->cache.lock, flags); read_unlock_irqrestore(&device->cache.lock, flags);
return ret; return ret;
......
...@@ -707,18 +707,28 @@ int ib_find_pkey(struct ib_device *device, ...@@ -707,18 +707,28 @@ int ib_find_pkey(struct ib_device *device,
{ {
int ret, i; int ret, i;
u16 tmp_pkey; u16 tmp_pkey;
int partial_ix = -1;
for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) { for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) {
ret = ib_query_pkey(device, port_num, i, &tmp_pkey); ret = ib_query_pkey(device, port_num, i, &tmp_pkey);
if (ret) if (ret)
return ret; return ret;
if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) { if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) {
*index = i; /* if there is full-member pkey take it.*/
return 0; if (tmp_pkey & 0x8000) {
*index = i;
return 0;
}
if (partial_ix < 0)
partial_ix = i;
} }
} }
/*no full-member, if exists take the limited*/
if (partial_ix >= 0) {
*index = partial_ix;
return 0;
}
return -ENOENT; return -ENOENT;
} }
EXPORT_SYMBOL(ib_find_pkey); EXPORT_SYMBOL(ib_find_pkey);
......
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