Skip to content

Commit 1c73934

Browse files
authored
Merge pull request #1741 from jpirko/wip_sf_renames
kernel-boot: Add naming support for sub-function (SF) RDMA devices
2 parents 8284c5a + e9de4bb commit 1c73934

3 files changed

Lines changed: 124 additions & 9 deletions

File tree

Documentation/udev.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ Type of names:
190190
* s<slot>[f<function>] - hotplug slot index number
191191
* x<GUID> - Node GUID
192192
* [P<domain>]p<bus>s<slot>[f<function>] - PCI geographical location
193+
* S<sfnum> - sub-function number, appended to the parent PCI device name
193194

194195
Notes:
195196

@@ -198,3 +199,5 @@ Notes:
198199
* When using PCI geography, The PCI domain is only prepended when it is not 0.
199200
* SR-IOV virtual devices are named based on the name of the parent interface,
200201
with a suffix of "v<N>", where <N> is the virtual device number.
202+
* Sub-functions (SFs) are named based on the name of their parent PCI device,
203+
with a suffix of "S<N>", where <N> is the kernel-exposed sfnum.

kernel-boot/rdma-persistent-naming.rules

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
# pci = 0000:00:0c.4
2222
# Device type = IB
2323
# mlx5_0 -> ibp0s12f4
24+
# * NAME_PCI with sub-function (SF)
25+
# parent pci = 0000:c1:00.0, sfnum = 88
26+
# Device type = RoCE
27+
# mlx5_5 -> rocep193s0f0S88
28+
# * NAME_PCI with SF on SR-IOV VF (VF-SF)
29+
# parent pci = 0000:c1:00.4 (VF of 0000:c1:00.0), sfnum = 99
30+
# Device type = RoCE
31+
# mlx5_6 -> rocep193s0f0v0S99
2432
# * NAME_GUID
2533
# GUID = 5254:00c0:fe12:3455
2634
# Device type = RoCE

kernel-boot/rdma_rename.c

Lines changed: 113 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stdio.h>
66
#include <stdlib.h>
77
#include <libgen.h>
8+
#include <limits.h>
89
#include <stdbool.h>
910
#include <errno.h>
1011
#include <unistd.h>
@@ -41,6 +42,14 @@
4142
* pci = 0000:00:0c.4
4243
* Device type = IB
4344
* mlx5_0 -> ibp0s12f4
45+
* NAME_PCI with sub-function (SF)
46+
* parent pci = 0000:c1:00.0, sfnum = 88
47+
* Device type = RoCE
48+
* mlx5_5 -> rocep193s0f0S88
49+
* NAME_PCI with SF on SR-IOV VF (VF-SF)
50+
* parent pci = 0000:c1:00.4 (VF of 0000:c1:00.0), sfnum = 99
51+
* Device type = RoCE
52+
* mlx5_6 -> rocep193s0f0v0S99
4453
* NAME_GUID
4554
* GUID = 5254:00c0:fe12:3455
4655
* Device type = RoCE
@@ -245,9 +254,82 @@ struct pci_info {
245254
unsigned int func;
246255
unsigned int sun;
247256
unsigned int vf;
257+
unsigned int sfnum;
248258
bool valid_vf;
259+
bool valid_sf;
249260
};
250261

262+
/*
263+
* If the ibdev's parent (the "device" symlink) is an auxiliary device that
264+
* carries a stable 'sfnum' attribute, this is a sub-function (SF) host RDMA
265+
* device. Read sfnum, then re-point p->pcidev at /sys/bus/pci/devices/<BDF>
266+
* of the aux device's PCI parent so that the rest of by_pci() (i.e.
267+
* get_virtfn_info(), fill_pci_info() and the name composition) proceeds
268+
* unchanged. The PCI parent can be a PF or an SR-IOV VF; both layouts
269+
* are handled by the same code path.
270+
*/
271+
static int detect_sf(struct data *d, struct pci_info *p)
272+
{
273+
char real_path[PATH_MAX];
274+
char *sfnum_path = NULL;
275+
char *device_path = NULL;
276+
char *last_slash, *bdf;
277+
unsigned int sfnum;
278+
FILE *fp;
279+
int ret;
280+
281+
ret = asprintf(&sfnum_path,
282+
"/sys/class/infiniband/%s/device/sfnum", d->curr);
283+
if (ret < 0)
284+
return -ENOMEM;
285+
286+
fp = fopen(sfnum_path, "r");
287+
free(sfnum_path);
288+
if (!fp) {
289+
/* Auxiliary parent without 'sfnum'; not an SF we recognize. */
290+
pr_dbg("%s: Auxiliary parent has no 'sfnum' attribute\n",
291+
d->curr);
292+
return -EINVAL;
293+
}
294+
295+
if (fscanf(fp, "%u", &sfnum) != 1) {
296+
fclose(fp);
297+
return -EINVAL;
298+
}
299+
fclose(fp);
300+
301+
ret = asprintf(&device_path, "/sys/class/infiniband/%s/device",
302+
d->curr);
303+
if (ret < 0)
304+
return -ENOMEM;
305+
306+
/* The 'device' symlink target is relative (e.g. "../../../<driver>.sf.<id>")
307+
* and does not itself encode the PCI BDF. Resolve it to its absolute,
308+
* canonical form so the path's parent directory exposes the BDF. */
309+
if (!realpath(device_path, real_path)) {
310+
free(device_path);
311+
return -EINVAL;
312+
}
313+
free(device_path);
314+
315+
/* Strip the trailing aux-device component to expose the PCI parent. */
316+
last_slash = strrchr(real_path, '/');
317+
if (!last_slash || last_slash == real_path)
318+
return -EINVAL;
319+
*last_slash = 0;
320+
321+
bdf = basename(real_path);
322+
ret = asprintf(&p->pcidev, "/sys/bus/pci/devices/%s", bdf);
323+
if (ret < 0) {
324+
p->pcidev = NULL;
325+
return -ENOMEM;
326+
}
327+
328+
p->valid_sf = true;
329+
p->sfnum = sfnum;
330+
return 0;
331+
}
332+
251333
static int fill_pci_info(struct data *d, struct pci_info *p)
252334
{
253335
char buf[256] = {};
@@ -379,21 +461,26 @@ static int by_pci(struct data *d)
379461
buf[ret] = 0;
380462

381463
subs = basename(buf);
382-
if (strcmp(subs, "pci")) {
464+
if (!strcmp(subs, "auxiliary")) {
465+
/* SFs sit one auxiliary hop below the underlying PCI function. */
466+
ret = detect_sf(d, &p);
467+
if (ret)
468+
goto out;
469+
} else if (!strcmp(subs, "pci")) {
470+
ret = asprintf(&p.pcidev,
471+
"/sys/class/infiniband/%s/device", d->curr);
472+
if (ret < 0) {
473+
ret = -ENOMEM;
474+
p.pcidev = NULL;
475+
goto out;
476+
}
477+
} else {
383478
/* Ball out virtual devices */
384479
pr_dbg("%s: Non-PCI device (%s) was detected\n", d->curr, subs);
385480
ret = -EINVAL;
386481
goto out;
387482
}
388483

389-
/* Real devices */
390-
ret = asprintf(&p.pcidev, "/sys/class/infiniband/%s/device", d->curr);
391-
if (ret < 0) {
392-
ret = -ENOMEM;
393-
p.pcidev = NULL;
394-
goto out;
395-
}
396-
397484
ret = get_virtfn_info(d, &p);
398485
if (ret)
399486
goto out;
@@ -453,6 +540,23 @@ static int by_pci(struct data *d)
453540
strcat(d->name, buf);
454541
}
455542
}
543+
544+
/*
545+
* SF identity is independent of any preceding f<func>/v<vf>
546+
* components, so append S<sfnum> last whenever it was set. For an SF
547+
* whose parent is a multi-function PF this yields
548+
* <prefix>p<bus>s<slot>f<func>S<sfnum>; for an SF on an SR-IOV VF
549+
* (VF-SF) the same rule yields
550+
* <prefix>p<bus>s<slot>f<func>v<vf>S<sfnum>.
551+
*/
552+
if (p.valid_sf) {
553+
ret = sprintf(buf, "S%u", p.sfnum);
554+
if (ret == -1) {
555+
ret = -ENOMEM;
556+
goto out;
557+
}
558+
strcat(d->name, buf);
559+
}
456560
ret = 0;
457561
out:
458562
free(p.pcidev);

0 commit comments

Comments
 (0)