Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Liran Liss <liranl@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>

authored by

Jack Morgenstein and committed by
Roland Dreier
ff7166c4 d2b57063

+25 -6
+12 -3
drivers/infiniband/core/cache.c
··· 167 167 unsigned long flags; 168 168 int i; 169 169 int ret = -ENOENT; 170 + int partial_ix = -1; 170 171 171 172 if (port_num < start_port(device) || port_num > end_port(device)) 172 173 return -EINVAL; ··· 180 179 181 180 for (i = 0; i < cache->table_len; ++i) 182 181 if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { 183 - *index = i; 184 - ret = 0; 185 - break; 182 + if (cache->table[i] & 0x8000) { 183 + *index = i; 184 + ret = 0; 185 + break; 186 + } else 187 + partial_ix = i; 186 188 } 189 + 190 + if (ret && partial_ix >= 0) { 191 + *index = partial_ix; 192 + ret = 0; 193 + } 187 194 188 195 read_unlock_irqrestore(&device->cache.lock, flags); 189 196
+13 -3
drivers/infiniband/core/device.c
··· 707 707 { 708 708 int ret, i; 709 709 u16 tmp_pkey; 710 + int partial_ix = -1; 710 711 711 712 for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) { 712 713 ret = ib_query_pkey(device, port_num, i, &tmp_pkey); 713 714 if (ret) 714 715 return ret; 715 - 716 716 if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) { 717 - *index = i; 718 - return 0; 717 + /* if there is full-member pkey take it.*/ 718 + if (tmp_pkey & 0x8000) { 719 + *index = i; 720 + return 0; 721 + } 722 + if (partial_ix < 0) 723 + partial_ix = i; 719 724 } 720 725 } 721 726 727 + /*no full-member, if exists take the limited*/ 728 + if (partial_ix >= 0) { 729 + *index = partial_ix; 730 + return 0; 731 + } 722 732 return -ENOENT; 723 733 } 724 734 EXPORT_SYMBOL(ib_find_pkey);