From nobody Mon Aug 10 22:52:23 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hJqlP2s2dz6m7Jh for ; Mon, 10 Aug 2026 22:52:33 +0000 (UTC) (envelope-from oliver.pntr@gmail.com) Received: from mail-yw1-x1136.google.com (mail-yw1-x1136.google.com [IPv6:2607:f8b0:4864:20::1136]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "WR4" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hJqlM3DJPz3vWG for ; Mon, 10 Aug 2026 22:52:31 +0000 (UTC) (envelope-from oliver.pntr@gmail.com) Authentication-Results: mx1.freebsd.org; dkim=pass header.d=gmail.com header.s=20251104 header.b=nnyWkjCE; arc=pass ("google.com:s=arc-20260327:i=1"); spf=pass (mx1.freebsd.org: domain of oliver.pntr@gmail.com designates 2607:f8b0:4864:20::1136 as permitted sender) smtp.mailfrom=oliver.pntr@gmail.com; dmarc=pass (policy=none) header.from=gmail.com Received: by mail-yw1-x1136.google.com with SMTP id 00721157ae682-82113c53aeaso3482407b3.1 for ; Mon, 10 Aug 2026 15:52:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1786402345; cv=none; d=google.com; s=arc-20260327; b=ZzmrlH+twixS/eCQsX6JsuzBztvcfg1CzxB8iSXGsQcGG2/zn9pt0c4yCpWplBu2yY FRdzj4lMlfg2/ZPU3j2WwPCMeJl57pAuJatzyjBYOCvRAgIncxS/p9Ybfn95ydWq1aMn R3rDR+OUW1BhL6GWpu9aPNM1ZVGiIuEgwNqPiGkNmdpTkgr5m9ZYx90feiTpougbshV2 +VvPIV1Uya32q8arGboLw5OaXFPzn3L+gtHbTEfDq+31sKqwUY9RPC6CC4HTBMQL359C VYYG5XEGBz2dV+ggJ2JgCFyH689Fo0x3xsufShYC3PWEX1PUNS2jp2qilEEgHe/cGZB/ vAvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:subject:message-id:date:from:references:in-reply-to :mime-version:dkim-signature; bh=WYxijCOjXj92pKJdKLpSbdXAiRfW0UhE6vTMmRnXYa0=; fh=I/fiO5Tku/f0hBs4wsHzqtGZ4MKigXehGOB5UrkOTIE=; b=qZC1aEqDBjKXeVccbWm+oejTU+pGauAr3y54/zq/JvzX8SnZYhp9wKd8kEDTippWGo 7TLAtCLDBQLvcMAQFQqj+HeLCw651d6VniZYw9JieJXt+hWGJFtAgjAxRbnfvGIyxy6Z /yHi1oHnHh/YyNhZTF6+qHSfVRMfIdklUX8IhAOylawvlE3xq8t0ykl3dopJouZNM/Xl Hz++tiS82A50+gOXF6ns1+7Pss1QaN4idQKisJNU/1PzFafNGlljiK8YHOvQUYeD/hH3 fTNZRCCAdlcVCWxCbUr4Uc1r+AzcycViIy92i/hmo5t8Tcr4DGv4TPWdLvvZy6J7/jNX xVuA==; darn=freebsd.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786402345; x=1787007145; darn=freebsd.org; h=content-type:cc:to:subject:message-id:date:from:references :in-reply-to:mime-version:from:to:cc:subject:date:message-id :reply-to:content-type; bh=WYxijCOjXj92pKJdKLpSbdXAiRfW0UhE6vTMmRnXYa0=; b=nnyWkjCERUFbV85wPIa8gD3wWTWApLC3byFXI7cthDQuaCKddESqTRJnrX1y6Ss2jb JE0cwGgS6YkalvLloiAV8RIf/ojS9nvJ4v9VbDevlM6dLQdxb7u4aW60ZVyC9IKsADgw 9i14KdtWymLURbQ7a/83RVPG54FxIpGvrZ9GUcnBdW4RRHYwbxhoJa196lrQ+MK/aYiY CIUwC68PlROGg/DMnIfuZYvZmSPMRoFx65HqZmTfP3hnwgPNQWccFAyo3QYxnLBV5SXQ Fl1WnJa4A/I2HqRRcqnJz6CC7aWW9T5M0LfUclu2M3DwoHOMhVQGeVJkAKuKVO66U283 OejQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786402345; x=1787007145; h=content-type:cc:to:subject:message-id:date:from:references :in-reply-to:mime-version:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to:content-type; bh=WYxijCOjXj92pKJdKLpSbdXAiRfW0UhE6vTMmRnXYa0=; b=XRlM0Cc2UCtXzwEVYQfq/k1oUm9wBNsMNXxhsfvcSGcjeKSn1ZOM1i4YvVGfWNTBai TuZZNsRKFky+Y9nUsgbcFm1xpS0n8Ctbc+RMyvhrDPowwZtUgwQ4d7SSUIuZoRS9uDaU XqJkh14i0f2N0DaGHErYX4nT9sLW9+KbCbdE9C4KxmY/Lp547jdkGE71QwlkwHUuuZHR zD3fmtE7Vr2aL9OfqrSinZWK1fLOsfsfTWWOk11iA0+gZ6WIecG8kjSiDfSf7myqRFYI eVmo/fQpTXcpv+aUuazOHEmD09VYBPwsU84aLHsUfpL5trozcRLwkvFAOmvkBaiPzpqE tjxg== X-Forwarded-Encrypted: i=1; AHgh+RoDBg/mM/ndIWim2NPO5GnFSqvi1+g71nQsDjAptqaCMArt5Fi1PhMZkMXF5T73oUjxauTrtao0XaDwMReo1trltX+e@freebsd.org X-Gm-Message-State: AOJu0YzKbiyXTrgT0O/TXxsJ0U0aTlQXGMhhirvs46He8ZyoHSW1gol4 myT0+fHjQs/qoV3gm513tUkDPA7t7As15VIPORiN6xLXPNbiXrt0yi9P6fB3nRvcR+fSIDTZfIH flNCEt0otugzJ7rwDUtpjFwvky8OZ9yE= X-Gm-Gg: AR+sD13U+FNBKxNQuKbwLNCndPeA179PBTjQBlBxoLUrMCgTBODY8rXoGdshI+WWj5y TqtaLxE8p4jOLkyjGFAdXDRfb9qLy5CU4vRJy+9m7v+7BI37Ynlquq0/hAB5q45pEM0CY7p91tk CuKUHZjLO50EZryDxGDWyx5ZqpmxJCXj/30Fr4H2smexYueND8ltECdAyC73MOoKID9TUl+94np EzC3nf2HHoTDvIIfFY93SLPOIUHPyoRSgAZkNJF7eXpsAPhjmNk5+7SAKg9C/xwSMXqJO1lYTm4 5czPx0uUBWEuLr6f0y00rJfdain4RsRm3KbT6VWUIAhfbX57vrKDOX6qOP5gR1tn3kYfEii6eH5 80JI= X-Received: by 2002:a05:690c:601:b0:81e:7075:e2e3 with SMTP id 00721157ae682-82022630960mr280977067b3.35.1786402345169; Mon, 10 Aug 2026 15:52:25 -0700 (PDT) List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Received: by 2002:a05:6174:ea02:20b0:52f:56f9:14ef with HTTP; Mon, 10 Aug 2026 15:52:23 -0700 (PDT) In-Reply-To: <6a782292.1895b.72e40e68@gitrepo.freebsd.org> References: <6a782292.1895b.72e40e68@gitrepo.freebsd.org> From: Oliver Pinter Date: Tue, 11 Aug 2026 00:52:23 +0200 X-Gm-Features: AUfX_myh-o02fzFjLeN5oSEbXv5QHOP7MwlzeFWxi4xffvY3EPl6EdwSiCDs3XA Message-ID: Subject: Re: git: 6f8b3be1fbd6 - main - pci: Add SR-IOV status reporting To: Kevin Bowling Cc: "src-committers@freebsd.org" , "dev-commits-src-all@freebsd.org" , "dev-commits-src-main@freebsd.org" Content-Type: multipart/alternative; boundary="00000000000035b8a40658b9359e" X-Spamd-Result: default: False [-4.45 / 15.00]; ARC_ALLOW(-1.00)[google.com:s=arc-20260327:i=1]; NEURAL_HAM_LONG(-1.00)[-1.000]; NEURAL_HAM_MEDIUM(-1.00)[-1.000]; DMARC_POLICY_ALLOW(-0.50)[gmail.com,none]; NEURAL_HAM_SHORT(-0.45)[-0.446]; R_SPF_ALLOW(-0.20)[+ip6:2607:f8b0:4864::/56:c]; R_DKIM_ALLOW(-0.20)[gmail.com:s=20251104]; MIME_GOOD(-0.10)[multipart/alternative,text/plain]; TAGGED_FROM(0.00)[]; RCVD_TLS_LAST(0.00)[]; FROM_HAS_DN(0.00)[]; MIME_TRACE(0.00)[0:+,1:+,2:~]; FREEMAIL_ENVFROM(0.00)[gmail.com]; TO_DN_EQ_ADDR_SOME(0.00)[]; FREEMAIL_FROM(0.00)[gmail.com]; TO_DN_SOME(0.00)[]; DKIM_TRACE(0.00)[gmail.com:+]; MISSING_XM_UA(0.00)[]; DWL_DNSWL_NONE(0.00)[gmail.com:dkim]; TO_MATCH_ENVRCPT_SOME(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[]; RCPT_COUNT_THREE(0.00)[4]; PREVIOUSLY_DELIVERED(0.00)[dev-commits-src-all@freebsd.org]; MLMMJ_DEST(0.00)[dev-commits-src-all@freebsd.org]; MID_RHS_MATCH_FROMTLD(0.00)[]; ASN(0.00)[asn:15169, ipnet:2607:f8b0::/32, country:US]; RCVD_IN_DNSWL_NONE(0.00)[2607:f8b0:4864:20::1136:from] X-Rspamd-Queue-Id: 4hJqlM3DJPz3vWG X-Spamd-Bar: ---- --00000000000035b8a40658b9359e Content-Type: text/plain; charset="UTF-8" On Sunday, August 9, 2026, Kevin Bowling wrote: > The branch main has been updated by kbowling: > > URL: https://cgit.FreeBSD.org/src/commit/?id= > 6f8b3be1fbd661bfa11c55081851c36ee1d5d2c1 > > commit 6f8b3be1fbd661bfa11c55081851c36ee1d5d2c1 > Author: Kevin Bowling > AuthorDate: 2026-08-09 02:03:49 +0000 > Commit: Kevin Bowling > CommitDate: 2026-08-09 06:46:41 +0000 > > pci: Add SR-IOV status reporting > > Add a generic packed-nvlist status query to each /dev/iov/ > control device. Report the live VF Enable state, configured and total > VF counts, and one record for each configured VF. > > Each VF record contains its PF-local index, computed PCI location, > newbus attachment state, attached driver, and ppt binding. Construct > records for hardware VFs whose newbus child is absent so attachment > failures remain visible. > > Version the extensible schema in sys/iov.h. Use fixed-width request > fields so the ioctl command and layout are identical for 32-bit > callers. > Serialize the topology snapshot with Giant, then pack and copy it after > releasing Giant. Hi! Just curiosity, why introducing Giant lock usage in FreeBSD in 2026? Wasn't there some very heavy efforts to kill it with fire from the kernel before? > --- > sys/dev/pci/pci_iov.c | 174 ++++++++++++++++++++++++++++++ > +++++++++++++++++++- > sys/sys/iov.h | 46 +++++++++++++ > 2 files changed, 219 insertions(+), 1 deletion(-) > > diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c > index 643f0e59b9b8..00a9c8e8be72 100644 > --- a/sys/dev/pci/pci_iov.c > +++ b/sys/dev/pci/pci_iov.c > @@ -27,6 +27,7 @@ > #include > #include "opt_bus.h" > > +#include > #include > #include > #include > @@ -875,6 +876,129 @@ pci_iov_is_child_vf(struct pcicfg_iov *pf, device_t > child) > return (pf == vfinfo->cfg.iov); > } > > +static int > +pci_iov_build_status(struct pci_devinfo *dinfo, nvlist_t **statusp) > +{ > + const char *driver; > + device_t bus, child, dev, pcib, *devlist, *vfdevs; > + nvlist_t *pf, *status, **vfs; > + struct pcicfg_iov *iov; > + struct pci_devinfo *vfinfo; > + bool attached, passthrough; > + int busno, devcount, error, func, i, slot; > + uint16_t rid_off, rid_stride, vf_rid; > + > + mtx_assert(&Giant, MA_OWNED); > + > + iov = dinfo->cfg.iov; > + dev = dinfo->cfg.dev; > + bus = device_get_parent(dev); > + pcib = device_get_parent(bus); > + devlist = NULL; > + vfdevs = NULL; > + vfs = NULL; > + status = NULL; > + pf = NULL; > + error = 0; > + > + if (iov->iov_num_vfs != 0) { > + vfdevs = mallocarray(iov->iov_num_vfs, sizeof(*vfdevs), > + M_SRIOV, M_WAITOK | M_ZERO); > + error = device_get_children(bus, &devlist, &devcount); > + if (error != 0) > + goto out; > + for (i = 0; i < devcount; i++) { > + child = devlist[i]; > + if (!pci_iov_is_child_vf(iov, child)) > + continue; > + vfinfo = device_get_ivars(child); > + if (vfinfo->cfg.vf.index < iov->iov_num_vfs) > + vfdevs[vfinfo->cfg.vf.index] = child; > + } > + } > + > + status = nvlist_create(0); > + pf = nvlist_create(0); > + if (status == NULL || pf == NULL) { > + error = ENOMEM; > + goto out; > + } > + nvlist_add_number(status, IOV_STATUS_VERSION_NAME, > IOV_STATUS_VERSION); > + nvlist_add_string(pf, IOV_STATUS_DEVICE_NAME, > device_get_nameunit(dev)); > + nvlist_add_stringf(pf, IOV_STATUS_PCI_LOCATION_NAME, > "pci%u:%u:%u:%u", > + (u_int)pci_get_domain(dev), (u_int)pci_get_bus(dev), > + (u_int)pci_get_slot(dev), (u_int)pci_get_function(dev)); > + nvlist_add_bool(pf, IOV_STATUS_ENABLED_NAME, > + (IOV_READ(dinfo, PCIR_SRIOV_CTL, 2) & PCIM_SRIOV_VF_EN) != 0); > + nvlist_add_number(pf, IOV_STATUS_NUM_VFS_NAME, iov->iov_num_vfs); > + nvlist_add_number(pf, IOV_STATUS_TOTAL_VFS_NAME, > + IOV_READ(dinfo, PCIR_SRIOV_TOTAL_VFS, 2)); > + error = nvlist_error(pf); > + if (error != 0) > + goto out; > + nvlist_move_nvlist(status, IOV_STATUS_PF_NAME, pf); > + pf = NULL; > + > + if (iov->iov_num_vfs != 0) > + vfs = mallocarray(iov->iov_num_vfs, sizeof(*vfs), M_SRIOV, > + M_WAITOK | M_ZERO); > + rid_off = IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, 2); > + rid_stride = IOV_READ(dinfo, PCIR_SRIOV_VF_STRIDE, 2); > + vf_rid = pci_get_rid(dev) + rid_off; > + for (i = 0; i < iov->iov_num_vfs; i++, vf_rid += rid_stride) { > + vfs[i] = nvlist_create(0); > + if (vfs[i] == NULL) { > + error = ENOMEM; > + goto out; > + } > + nvlist_add_number(vfs[i], IOV_STATUS_VF_INDEX_NAME, i); > + child = vfdevs[i]; > + if (child != NULL) { > + busno = pci_get_bus(child); > + slot = pci_get_slot(child); > + func = pci_get_function(child); > + } else > + PCIB_DECODE_RID(pcib, vf_rid, &busno, &slot, > &func); > + nvlist_add_stringf(vfs[i], IOV_STATUS_PCI_LOCATION_NAME, > + "pci%u:%u:%u:%u", (u_int)pci_get_domain(dev), > + (u_int)busno, (u_int)slot, (u_int)func); > + attached = child != NULL && device_is_attached(child); > + passthrough = child != NULL && device_get_name(child) != > NULL && > + strcmp(device_get_name(child), "ppt") == 0; > + nvlist_add_bool(vfs[i], IOV_STATUS_ATTACHED_NAME, > attached); > + nvlist_add_bool(vfs[i], IOV_STATUS_PASSTHROUGH_NAME, > + passthrough); > + if (attached) { > + driver = device_get_nameunit(child); > + if (driver != NULL) > + nvlist_add_string(vfs[i], > + IOV_STATUS_BOUND_DRIVER_NAME, driver); > + } > + error = nvlist_error(vfs[i]); > + if (error != 0) > + goto out; > + } > + if (iov->iov_num_vfs != 0) > + nvlist_add_nvlist_array(status, IOV_STATUS_VFS_NAME, > + (const nvlist_t * const *)vfs, iov->iov_num_vfs); > + error = nvlist_error(status); > + if (error != 0) > + goto out; > + *statusp = status; > + status = NULL; > +out: > + if (vfs != NULL) { > + for (i = 0; i < iov->iov_num_vfs; i++) > + nvlist_destroy(vfs[i]); > + free(vfs, M_SRIOV); > + } > + nvlist_destroy(pf); > + nvlist_destroy(status); > + free(vfdevs, M_SRIOV); > + free(devlist, M_TEMP); > + return (error); > +} > + > static int > pci_iov_delete_iov_children(struct pci_devinfo *dinfo) > { > @@ -985,7 +1109,8 @@ pci_iov_get_schema_ioctl(struct cdev *cdev, struct > pci_iov_schema *output) > { > struct pci_devinfo *dinfo; > void *packed; > - size_t output_len, size; > + size_t size; > + uint64_t output_len; > int error; > > packed = NULL; > @@ -1025,6 +1150,50 @@ fail: > return (error); > } > > +static int > +pci_iov_get_status_ioctl(struct cdev *cdev, struct pci_iov_status > *output) > +{ > + struct pci_devinfo *dinfo; > + nvlist_t *status; > + void *packed; > + size_t output_len, size; > + int error; > + > + status = NULL; > + packed = NULL; > + if (output->reserved != 0) > + return (EINVAL); > + mtx_lock(&Giant); > + dinfo = cdev->si_drv1; > + error = pci_iov_build_status(dinfo, &status); > + mtx_unlock(&Giant); > + if (error != 0) > + goto out; > + > + packed = nvlist_pack(status, &size); > + if (packed == NULL) { > + error = ENOMEM; > + goto out; > + } > + > + output_len = output->len; > + output->len = size; > + if (size <= output_len) { > + error = copyout(packed, PTRIN(output->status), size); > + if (error != 0) > + goto out; > + output->error = 0; > + } else { > + /* Keep the ioctl successful so the required size is > copied out. */ > + output->error = EMSGSIZE; > + } > + error = 0; > +out: > + free(packed, M_NVLIST); > + nvlist_destroy(status); > + return (error); > +} > + > static int > pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, > struct thread *td) > @@ -1038,6 +1207,9 @@ pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t > data, int fflag, > case IOV_GET_SCHEMA: > return (pci_iov_get_schema_ioctl(dev, > (struct pci_iov_schema *)data)); > + case IOV_GET_STATUS: > + return (pci_iov_get_status_ioctl(dev, > + (struct pci_iov_status *)data)); > default: > return (EINVAL); > } > diff --git a/sys/sys/iov.h b/sys/sys/iov.h > index 2ae7e5ac6767..67a890bba66f 100644 > --- a/sys/sys/iov.h > +++ b/sys/sys/iov.h > @@ -164,6 +164,51 @@ struct pci_iov_schema > int error; > }; > > +/* > + * IOV_GET_STATUS schema contract. > + * > + * The top-level nvlist contains a version number, a PF nvlist, and, when > VFs > + * are configured, an array of per-VF nvlists. The "vfs" key is omitted > when > + * "num-vfs" is zero; its absence therefore means no VFs are configured. > The > + * PF record identifies the device, reports the live SR-IOV VF Enable > state, > + * and gives the number of VFs configured by the PCI IOV framework and the > + * hardware limit. When present, the array contains one VF record for > each > + * configured VF, even when its newbus child could not be attached. > + * > + * PCI locations use FreeBSD's native decimal pciD:B:S:F notation (for > + * example, pci0:2:16:2). "attached" means that newbus successfully > attached > + * a driver. "bound-driver" is present only for an attached VF and > contains > + * the driver's nameunit. "passthrough" means that the VF has the ppt > host > + * devclass; it does not imply that a running virtual machine currently > owns > + * the VF. > + * > + * Consumers must ignore unknown keys. Additive optional keys retain the > + * status version; incompatible type or structural changes require a new > + * version. > + */ > +#define IOV_STATUS_VERSION 1 > +#define IOV_STATUS_VERSION_NAME "version" > +#define IOV_STATUS_PF_NAME "pf" > +#define IOV_STATUS_VFS_NAME "vfs" > +#define IOV_STATUS_DEVICE_NAME "device" > +#define IOV_STATUS_PCI_LOCATION_NAME "pci-location" > +#define IOV_STATUS_ENABLED_NAME "enabled" > +#define IOV_STATUS_NUM_VFS_NAME "num-vfs" > +#define IOV_STATUS_TOTAL_VFS_NAME "total-vfs" > +#define IOV_STATUS_VF_INDEX_NAME "index" > +#define IOV_STATUS_ATTACHED_NAME "attached" > +#define IOV_STATUS_BOUND_DRIVER_NAME "bound-driver" > +#define IOV_STATUS_PASSTHROUGH_NAME "passthrough" > + > +/* Fixed-width fields keep the ioctl ABI identical for 32-bit callers. */ > +struct pci_iov_status > +{ > + uint64_t status; /* User pointer to the packed nvlist. */ > + uint64_t len; > + int32_t error; > + uint32_t reserved; /* Must be zero. */ > +}; > + > /* > * SR-IOV configuration is passed to the kernel as a packed nvlist. See > nv(3) > * for the details of the nvlist API. The expected format of the nvlist > is: > @@ -254,5 +299,6 @@ struct pci_iov_arg > #define IOV_CONFIG _IOW('p', 10, struct pci_iov_arg) > #define IOV_DELETE _IO('p', 11) > #define IOV_GET_SCHEMA _IOWR('p', 12, struct pci_iov_schema) > +#define IOV_GET_STATUS _IOWR('p', 13, struct pci_iov_status) > > #endif > > --00000000000035b8a40658b9359e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

On Sunday, August 9, 2026, Kevin Bowling <kbowling@freebsd.org> wrote:
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=3D6f8b3be1fbd661bfa11c55081851c36ee1d5d2c1

commit 6f8b3be1fbd661bfa11c55081851c36ee1d5d2c1
Author:=C2=A0 =C2=A0 =C2=A0Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-09 02:03:49 +0000
Commit:=C2=A0 =C2=A0 =C2=A0Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-09 06:46:41 +0000

=C2=A0 =C2=A0 pci: Add SR-IOV status reporting

=C2=A0 =C2=A0 Add a generic packed-nvlist status query to each /dev/iov/<= ;PF>
=C2=A0 =C2=A0 control device.=C2=A0 Report the live VF Enable state, config= ured and total
=C2=A0 =C2=A0 VF counts, and one record for each configured VF.

=C2=A0 =C2=A0 Each VF record contains its PF-local index, computed PCI loca= tion,
=C2=A0 =C2=A0 newbus attachment state, attached driver, and ppt binding.=C2= =A0 Construct
=C2=A0 =C2=A0 records for hardware VFs whose newbus child is absent so atta= chment
=C2=A0 =C2=A0 failures remain visible.

=C2=A0 =C2=A0 Version the extensible schema in sys/iov.h.=C2=A0 Use fixed-w= idth request
=C2=A0 =C2=A0 fields so the ioctl command and layout are identical for 32-b= it callers.
=C2=A0 =C2=A0 Serialize the topology snapshot with Giant, then pack and cop= y it after
=C2=A0 =C2=A0 releasing Giant.

Hi!

Just curiosity, why introducing Giant lock usage in FreeBS= D in 2026? Wasn't there some very heavy efforts to kill it with fire fr= om the kernel before?
=C2=A0
---
=C2=A0sys/dev/pci/pci_iov.c | 174 ++++++++++++++++++++++++++++++++++++= +++++++++++++-
=C2=A0sys/sys/iov.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 46 +++++++++++= ++
=C2=A02 files changed, 219 insertions(+), 1 deletion(-)

diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c
index 643f0e59b9b8..00a9c8e8be72 100644
--- a/sys/dev/pci/pci_iov.c
+++ b/sys/dev/pci/pci_iov.c
@@ -27,6 +27,7 @@
=C2=A0#include <sys/cdefs.h>
=C2=A0#include "opt_bus.h"

+#include <sys/abi_compat.h>
=C2=A0#include <sys/param.h>
=C2=A0#include <sys/conf.h>
=C2=A0#include <sys/kernel.h>
@@ -875,6 +876,129 @@ pci_iov_is_child_vf(struct pcicfg_iov *pf, device_t c= hild)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return (pf =3D=3D vfinfo->cfg.iov);
=C2=A0}

+static int
+pci_iov_build_status(struct pci_devinfo *dinfo, nvlist_t **statusp)
+{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0const char *driver;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0device_t bus, child, dev, pcib, *devlist, *vfde= vs;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_t *pf, *status, **vfs;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0struct pcicfg_iov *iov;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0struct pci_devinfo *vfinfo;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0bool attached, passthrough;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int busno, devcount, error, func, i, slot;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint16_t rid_off, rid_stride, vf_rid;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_assert(&Giant, MA_OWNED);
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0iov =3D dinfo->cfg.iov;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0dev =3D dinfo->cfg.dev;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0bus =3D device_get_parent(dev);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0pcib =3D device_get_parent(bus);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0devlist =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0vfdevs =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0vfs =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0pf =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D 0;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (iov->iov_num_vfs !=3D 0) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vfdevs =3D mallocar= ray(iov->iov_num_vfs, sizeof(*vfdevs),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0M_SRI= OV, M_WAITOK | M_ZERO);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D device_ge= t_children(bus, &devlist, &devcount);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i <= ; devcount; i++) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0child =3D devlist[i];
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0if (!pci_iov_is_child_vf(iov, child))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0vfinfo =3D device_get_ivars(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0if (vfinfo->cfg.vf.index < iov->iov_num_vfs)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vfdevs[vfinfo->cfg.vf.index] =3D c= hild;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D nvlist_create(0);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0pf =3D nvlist_create(0);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (status =3D=3D NULL || pf =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D ENOMEM; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_number(status, IOV_STATUS_VERSION_NA= ME, IOV_STATUS_VERSION);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_string(pf, IOV_STATUS_DEVICE_NAME, d= evice_get_nameunit(dev));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_stringf(pf, IOV_STATUS_PCI_LOCATION_= NAME, "pci%u:%u:%u:%u",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(u_int)pci_get_domain(dev), (u_in= t)pci_get_bus(dev),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(u_int)pci_get_slot(dev), (u_int)= pci_get_function(dev));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_bool(pf, IOV_STATUS_ENABLED_NAME, +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(IOV_READ(dinfo, PCIR_SRIOV_CTL, = 2) & PCIM_SRIOV_VF_EN) !=3D 0);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_number(pf, IOV_STATUS_NUM_VFS_NAME, = iov->iov_num_vfs);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_number(pf, IOV_STATUS_TOTAL_VFS_NAME= ,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0IOV_READ(dinfo, PCIR_SRIOV_TOTAL_= VFS, 2));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nvlist_error(pf);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_move_nvlist(status, IOV_STATUS_PF_NAME, = pf);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0pf =3D NULL;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (iov->iov_num_vfs !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vfs =3D mallocarray= (iov->iov_num_vfs, sizeof(*vfs), M_SRIOV,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0M_WAI= TOK | M_ZERO);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0rid_off =3D IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, = 2);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0rid_stride =3D IOV_READ(dinfo, PCIR_SRIOV_VF_ST= RIDE, 2);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0vf_rid =3D pci_get_rid(dev) + rid_off;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < iov->iov_num_vfs; i++, = vf_rid +=3D rid_stride) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vfs[i] =3D nvlist_c= reate(0);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (vfs[i] =3D=3D N= ULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0error =3D ENOMEM;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_number(v= fs[i], IOV_STATUS_VF_INDEX_NAME, i);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0child =3D vfdevs[i]= ;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (child !=3D NULL= ) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0busno =3D pci_get_bus(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0slot =3D pci_get_slot(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0func =3D pci_get_function(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0PCIB_DECODE_RID(pcib, vf_rid, &busno, &slot, &func);<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_stringf(= vfs[i], IOV_STATUS_PCI_LOCATION_NAME,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"= ;pci%u:%u:%u:%u", (u_int)pci_get_domain(dev),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(u_in= t)busno, (u_int)slot, (u_int)func);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0attached =3D child = !=3D NULL && device_is_attached(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0passthrough =3D chi= ld !=3D NULL && device_get_name(child) !=3D NULL &&
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0strcm= p(device_get_name(child), "ppt") =3D=3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_bool(vfs= [i], IOV_STATUS_ATTACHED_NAME, attached);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_bool(vfs= [i], IOV_STATUS_PASSTHROUGH_NAME,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0passt= hrough);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (attached) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0driver =3D device_get_nameunit(child);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0if (driver !=3D NULL)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_string(vfs[i],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0IOV_STATUS_BOUND_DRIVER= _NAME, driver);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nvlist_er= ror(vfs[i]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (iov->iov_num_vfs !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_add_nvlist_a= rray(status, IOV_STATUS_VFS_NAME,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons= t nvlist_t * const *)vfs, iov->iov_num_vfs);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nvlist_error(status);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0*statusp =3D status;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D NULL;
+out:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (vfs !=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i <= ; iov->iov_num_vfs; i++)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0nvlist_destroy(vfs[i]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(vfs, M_SRIOV);=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_destroy(pf);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_destroy(status);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0free(vfdevs, M_SRIOV);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0free(devlist, M_TEMP);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);
+}
+
=C2=A0static int
=C2=A0pci_iov_delete_iov_children(struct pci_devinfo *dinfo)
=C2=A0{
@@ -985,7 +1109,8 @@ pci_iov_get_schema_ioctl(struct cdev *cdev, struc= t pci_iov_schema *output)
=C2=A0{
=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct pci_devinfo *dinfo;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 void *packed;
-=C2=A0 =C2=A0 =C2=A0 =C2=A0size_t output_len, size;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0size_t size;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t output_len;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 int error;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 packed =3D NULL;
@@ -1025,6 +1150,50 @@ fail:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return (error);
=C2=A0}

+static int
+pci_iov_get_status_ioctl(struct cdev *cdev, struct pci_iov_status *ou= tput)
+{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0struct pci_devinfo *dinfo;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_t *status;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0void *packed;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0size_t output_len, size;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int error;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0status =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0packed =3D NULL;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (output->reserved !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EINVAL); +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&Giant);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0dinfo =3D cdev->si_drv1;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D pci_iov_build_status(dinfo, &stat= us);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&Giant);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0packed =3D nvlist_pack(status, &size);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (packed =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D ENOMEM; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0output_len =3D output->len;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0output->len =3D size;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (size <=3D output_len) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D copyout(p= acked, PTRIN(output->status), size);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0goto out;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0output->error = =3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0} else {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Keep the ioctl s= uccessful so the required size is copied out. */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0output->error = =3D EMSGSIZE;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D 0;
+out:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0free(packed, M_NVLIST);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0nvlist_destroy(status);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);
+}
+
=C2=A0static int
=C2=A0pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,<= br> =C2=A0 =C2=A0 =C2=A0struct thread *td)
@@ -1038,6 +1207,9 @@ pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t d= ata, int fflag,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 case IOV_GET_SCHEMA:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return (pci_iov_get= _schema_ioctl(dev,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (stru= ct pci_iov_schema *)data));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0case IOV_GET_STATUS:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (pci_iov_get= _status_ioctl(dev,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(stru= ct pci_iov_status *)data));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 default:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return (EINVAL); =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
diff --git a/sys/sys/iov.h b/sys/sys/iov.h
index 2ae7e5ac6767..67a890bba66f 100644
--- a/sys/sys/iov.h
+++ b/sys/sys/iov.h
@@ -164,6 +164,51 @@ struct pci_iov_schema
=C2=A0 =C2=A0 =C2=A0 =C2=A0 int error;
=C2=A0};

+/*
+ * IOV_GET_STATUS schema contract.
+ *
+ * The top-level nvlist contains a version number, a PF nvlist, and, when = VFs
+ * are configured, an array of per-VF nvlists.=C2=A0 The "vfs" k= ey is omitted when
+ * "num-vfs" is zero; its absence therefore means no VFs are con= figured.=C2=A0 The
+ * PF record identifies the device, reports the live SR-IOV VF Enable stat= e,
+ * and gives the number of VFs configured by the PCI IOV framework and the=
+ * hardware limit.=C2=A0 When present, the array contains one VF record fo= r each
+ * configured VF, even when its newbus child could not be attached.
+ *
+ * PCI locations use FreeBSD's native decimal pciD:B:S:F notation (for=
+ * example, pci0:2:16:2).=C2=A0 "attached" means that newbus suc= cessfully attached
+ * a driver.=C2=A0 "bound-driver" is present only for an attache= d VF and contains
+ * the driver's nameunit.=C2=A0 "passthrough" means that the= VF has the ppt host
+ * devclass; it does not imply that a running virtual machine currently ow= ns
+ * the VF.
+ *
+ * Consumers must ignore unknown keys.=C2=A0 Additive optional keys retain= the
+ * status version; incompatible type or structural changes require a new + * version.
+ */
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_VERSION=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 1
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_VERSION_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0"version"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_PF_NAME=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 "pf"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_VFS_NAME=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0"vfs"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_DEVICE_NAME=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 "device"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_PCI_LOCATION_NAME=C2=A0 =C2= =A0 "pci-location"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_ENABLED_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0"enabled"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_NUM_VFS_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0"num-vfs"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_TOTAL_VFS_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0"total-vfs"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_VF_INDEX_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0 "index"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_ATTACHED_NAME=C2=A0 =C2=A0 = =C2=A0 =C2=A0 "attached"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_BOUND_DRIVER_NAME=C2=A0 =C2= =A0 "bound-driver"
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_STATUS_PASSTHROUGH_NAME=C2=A0 =C2= =A0 =C2=A0"passthrough"
+
+/* Fixed-width fields keep the ioctl ABI identical for 32-bit callers. */<= br> +struct pci_iov_status
+{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t status;=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* = User pointer to the packed nvlist. */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t len;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int32_t error;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t reserved;=C2=A0 =C2=A0 =C2=A0 /* Must = be zero. */
+};
+
=C2=A0/*
=C2=A0 * SR-IOV configuration is passed to the kernel as a packed nvlist.= =C2=A0 See nv(3)
=C2=A0 * for the details of the nvlist API.=C2=A0 The expected format of th= e nvlist is:
@@ -254,5 +299,6 @@ struct pci_iov_arg
=C2=A0#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_CONFIG=C2=A0 =C2=A0 =C2=A0 _IO= W('p', 10, struct pci_iov_arg)
=C2=A0#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_DELETE=C2=A0 =C2=A0 =C2=A0 _IO= ('p', 11)
=C2=A0#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_GET_SCHEMA=C2=A0 _IOWR('p&= #39;, 12, struct pci_iov_schema)
+#define=C2=A0 =C2=A0 =C2=A0 =C2=A0 IOV_GET_STATUS=C2=A0 _IOWR('p',= 13, struct pci_iov_status)

=C2=A0#endif

--00000000000035b8a40658b9359e--