2014-05-13 16:10:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* domain_addr.c: helper APIs for managing domain device addresses
|
|
|
|
|
*
|
conf/qemu: change the way VIR_PCI_CONNECT_TYPE_* flags work
The flags used to determine which devices could be plugged into which
controllers were quite confusing, as they tried to create classes of
connections, then put particular devices into possibly multiple
classes, while sometimes setting multiple flags for the controllers
themselves. The attempt to have a single flag indicate, e.g. that a
root-port or a switch-downstream-port could connect was not only
confusing, it was leading to a situation where it would be impossible
to specify exactly the right combinations for a new controller.
The solution is for the VIR_PCI_CONNECT_TYPE_* flags to have a 1:1
correspondence with each type of PCI controller, plus a flag for a PCI
endpoint device and another for a PCIe endpoint device (the only
exception to this is that pci-bridge and pcie-expander-bus controllers
have their upstream connection classified as
VIR_PCI_CONNECT_TYPE_PCI_DEVICE since they can be plugged into
*exactly* the same ports as any endpoint device). Each device then
has a single flag for connect type (plus the HOTPLUG flag if that
device can e hotplugged), and each controller sets the CONNECT bits
for all controllers that can be plugged into it, as well as for either
type of endpoint device that can be plugged in (and the HOTPLUG flag
if it can accept hotplugged devices).
With this change, it is *slightly* easier to understand the matching
of connections (as long as you remember that the flag for a
device/upstream-facing connection of a controller is the same as that
device's type, while the flags for a controller's downstream
connections is the OR of all device types that can be plugged into
that controller). More importantly, it will be possible to correctly
specify what can be plugged into a pcie-switch-expander-bus, when
support for it is added.
2016-03-15 19:49:22 +00:00
|
|
|
|
* Copyright (C) 2006-2016 Red Hat, Inc.
|
2014-05-13 16:10:40 +00:00
|
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library. If not, see
|
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include "viralloc.h"
|
|
|
|
|
#include "virlog.h"
|
|
|
|
|
#include "virstring.h"
|
|
|
|
|
#include "domain_addr.h"
|
|
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_DOMAIN
|
|
|
|
|
|
|
|
|
|
VIR_LOG_INIT("conf.domain_addr");
|
|
|
|
|
|
2018-11-08 11:00:28 +00:00
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReserveId(GHashTable *set,
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
virZPCIDeviceAddressID *id,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
const char *name)
|
|
|
|
|
{
|
2020-10-20 15:31:23 +00:00
|
|
|
|
int *idval;
|
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (!id->isSet) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("No zPCI %s to reserve"),
|
|
|
|
|
name);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
if (g_hash_table_lookup(set, &id->value)) {
|
2018-11-08 11:00:28 +00:00
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("zPCI %s %o is already reserved"),
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
name, id->value);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
idval = g_new0(int, 1);
|
|
|
|
|
*idval = (int) id->value;
|
|
|
|
|
|
|
|
|
|
g_hash_table_add(set, idval);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReserveUid(GHashTable *set,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
return virDomainZPCIAddressReserveId(set, &addr->uid, "uid");
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReserveFid(GHashTable *set,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
return virDomainZPCIAddressReserveId(set, &addr->fid, "fid");
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressAssignId(GHashTable *set,
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
virZPCIDeviceAddressID *id,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
unsigned int min,
|
|
|
|
|
unsigned int max,
|
|
|
|
|
const char *name)
|
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (id->isSet)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
while (g_hash_table_lookup(set, &min)) {
|
2018-11-08 11:00:28 +00:00
|
|
|
|
if (min == max) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("There is no more free %s."),
|
|
|
|
|
name);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
++min;
|
|
|
|
|
}
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
|
|
|
|
|
id->value = min;
|
|
|
|
|
id->isSet = true;
|
2018-11-08 11:00:28 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressAssignUid(GHashTable *set,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
return virDomainZPCIAddressAssignId(set, &addr->uid, 1,
|
|
|
|
|
VIR_DOMAIN_DEVICE_ZPCI_MAX_UID, "uid");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressAssignFid(GHashTable *set,
|
2018-11-08 11:00:28 +00:00
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
return virDomainZPCIAddressAssignId(set, &addr->fid, 0,
|
|
|
|
|
VIR_DOMAIN_DEVICE_ZPCI_MAX_FID, "fid");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReleaseId(GHashTable *set,
|
|
|
|
|
virZPCIDeviceAddressID *id)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (!id->isSet)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
g_hash_table_remove(set, &id->value);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
id->value = 0;
|
|
|
|
|
id->isSet = false;
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
virDomainZPCIAddressReleaseIds(virDomainZPCIAddressIdsPtr zpciIds,
|
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (!zpciIds)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReleaseId(zpciIds->uids, &addr->uid);
|
|
|
|
|
virDomainZPCIAddressReleaseId(zpciIds->fids, &addr->fid);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
virDomainZPCIAddressEnsureAddr(virDomainZPCIAddressIdsPtr zpciIds,
|
|
|
|
|
virZPCIDeviceAddressPtr addr)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
{
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (virDomainZPCIAddressAssignUid(zpciIds->uids, addr) < 0)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (virDomainZPCIAddressAssignFid(zpciIds->fids, addr) < 0)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (virDomainZPCIAddressReserveUid(zpciIds->uids, addr) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (virDomainZPCIAddressReserveFid(zpciIds->fids, addr) < 0) {
|
2020-10-20 15:31:23 +00:00
|
|
|
|
virDomainZPCIAddressReleaseId(zpciIds->uids, &addr->uid);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
|
|
|
|
|
/* Reserve uid/fid to ZPCI device which has defined uid/fid
|
|
|
|
|
* in the domain.
|
|
|
|
|
*/
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
return virDomainZPCIAddressEnsureAddr(addrs->zpciIds, &addr->zpci);
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
virZPCIDeviceAddress zpci = addr->zpci;
|
2018-11-08 11:00:28 +00:00
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (virDomainZPCIAddressEnsureAddr(addrs->zpciIds, &zpci) < 0)
|
2018-11-08 11:00:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (!addrs->dryRun)
|
|
|
|
|
addr->zpci = zpci;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
|
2018-11-08 11:00:28 +00:00
|
|
|
|
static int
|
|
|
|
|
virDomainPCIAddressExtensionEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
|
|
|
|
|
virZPCIDeviceAddressPtr zpci = &addr->zpci;
|
|
|
|
|
|
conf: fix zPCI address auto-generation on s390
Let us fix the issues with zPCI address validation and auto-generation
on s390.
Currently, there are two issues with handling the ZPCI address
extension. Firstly, when the uid is to be auto-generated with a
specified fid, .i.e.:
...
<address type='pci'>
<zpci fid='0x0000001f'/>
</address>
...
we expect uid='0x0001' (or the next available uid for the domain).
However, we get a parsing error:
$ virsh define zpci.xml
error: XML error: Invalid PCI address uid='0x0000', must be > 0x0000
and <= 0xffff
Secondly, when the uid is specified explicitly with the invalid
numerical value '0x0000', we actually expect the parsing error above.
However, the domain is being defined and the uid value is silently
changed to a valid value.
The first issue is a bug and the second one is undesired behaviour, and
both issues are related to how we (in-band) signal invalid values for
uid and fid. So let's fix the XML parsing to do validation based on what
is actually specified in the XML.
The first issue is also related to the current code behaviour, which
is, if either uid or fid is specified by the user, it is incorrectly
assumed that both uid and fid are specified. This bug is fixed by
identifying when the user specified ZPCI address is incomplete and
auto-generating the missing ZPCI address.
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
2020-06-18 08:25:15 +00:00
|
|
|
|
if (virDomainZPCIAddressEnsureAddr(addrs->zpciIds, zpci) < 0)
|
|
|
|
|
return -1;
|
2018-11-08 11:00:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-03-16 18:20:52 +00:00
|
|
|
|
virDomainPCIConnectFlags
|
|
|
|
|
virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
|
|
|
|
|
{
|
2017-02-20 14:56:18 +00:00
|
|
|
|
/* given a VIR_DOMAIN_CONTROLLER_MODEL_PCI*, return
|
|
|
|
|
* the equivalent VIR_PCI_CONNECT_TYPE_*.
|
2016-03-16 18:20:52 +00:00
|
|
|
|
*/
|
|
|
|
|
switch (model) {
|
2018-02-14 10:51:26 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
|
2016-03-16 18:20:52 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
|
|
|
|
|
/* pci-root and pcie-root are implicit in the machine,
|
|
|
|
|
* and have no upstream connection, "last" will never actually
|
|
|
|
|
* happen, it's just there so that all possible cases are
|
|
|
|
|
* covered in the switch (keeps the compiler happy).
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
|
2016-08-07 21:13:58 +00:00
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCI_BRIDGE;
|
2016-03-16 18:20:52 +00:00
|
|
|
|
|
2016-08-06 23:03:31 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
|
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS;
|
|
|
|
|
|
2016-03-16 17:37:14 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
|
2016-08-06 23:03:31 +00:00
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS;
|
2016-03-16 18:20:52 +00:00
|
|
|
|
|
2016-08-05 19:01:08 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
|
|
|
|
|
return VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE;
|
|
|
|
|
|
2018-01-11 16:28:43 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
|
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE;
|
|
|
|
|
|
2016-03-16 18:20:52 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
|
2016-10-20 19:46:01 +00:00
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT | VIR_PCI_CONNECT_AGGREGATE_SLOT;
|
2016-03-16 18:20:52 +00:00
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
|
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
|
|
|
|
|
return VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags)
|
|
|
|
|
{
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS;
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE)
|
|
|
|
|
return VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
|
|
|
|
|
|
|
|
|
|
/* some connect types don't correspond to a controller model */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-06-08 14:03:53 +00:00
|
|
|
|
static bool
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr,
|
2014-05-13 16:10:40 +00:00
|
|
|
|
const char *addrStr,
|
|
|
|
|
virDomainPCIConnectFlags busFlags,
|
|
|
|
|
virDomainPCIConnectFlags devFlags,
|
|
|
|
|
bool reportError,
|
|
|
|
|
bool fromConfig)
|
|
|
|
|
{
|
|
|
|
|
virErrorNumber errType = (fromConfig
|
|
|
|
|
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
|
|
|
|
|
2015-06-09 17:33:36 +00:00
|
|
|
|
if (fromConfig) {
|
|
|
|
|
/* If the requested connection was manually specified in
|
|
|
|
|
* config, allow a PCI device to connect to a PCIe slot, or
|
2016-10-12 15:02:37 +00:00
|
|
|
|
* vice versa. In order to do so, we add *both* the PCI_DEVICE
|
|
|
|
|
* and the PCIE_DEVICE flags to the bus if it already has either
|
|
|
|
|
* of them, using the ENDPOINT mask.
|
2015-06-09 17:33:36 +00:00
|
|
|
|
*/
|
|
|
|
|
if (busFlags & VIR_PCI_CONNECT_TYPES_ENDPOINT)
|
|
|
|
|
busFlags |= VIR_PCI_CONNECT_TYPES_ENDPOINT;
|
2016-08-07 21:13:58 +00:00
|
|
|
|
/* if the device is a pci-bridge, allow manually
|
|
|
|
|
* assigning to any bus that would also accept a
|
|
|
|
|
* standard PCI device.
|
|
|
|
|
*/
|
|
|
|
|
if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE)
|
|
|
|
|
devFlags |= VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
|
2020-04-05 22:01:43 +00:00
|
|
|
|
} else if ((devFlags & VIR_PCI_CONNECT_AUTOASSIGN) &&
|
|
|
|
|
!(busFlags & VIR_PCI_CONNECT_AUTOASSIGN)) {
|
|
|
|
|
if (reportError) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("The device at PCI address %s was auto-assigned "
|
|
|
|
|
"this address, but the PCI controller "
|
|
|
|
|
"with index='%d' doesn't allow auto-assignment"),
|
|
|
|
|
addrStr, addr->bus);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2015-06-09 17:33:36 +00:00
|
|
|
|
}
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
2020-04-06 02:57:43 +00:00
|
|
|
|
if ((devFlags & VIR_PCI_CONNECT_HOTPLUGGABLE) &&
|
|
|
|
|
!(busFlags & VIR_PCI_CONNECT_HOTPLUGGABLE)) {
|
|
|
|
|
if (reportError) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("The device at PCI address %s requires "
|
|
|
|
|
"hotplug capability, but the PCI controller "
|
|
|
|
|
"with index='%d' doesn't support hotplug"),
|
|
|
|
|
addrStr, addr->bus);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
/* If this bus doesn't allow the type of connection (PCI
|
|
|
|
|
* vs. PCIe) required by the device, or if the device requires
|
|
|
|
|
* hot-plug and this bus doesn't have it, return false.
|
|
|
|
|
*/
|
2015-06-09 17:33:36 +00:00
|
|
|
|
if (!(devFlags & busFlags & VIR_PCI_CONNECT_TYPES_MASK)) {
|
2016-08-06 01:19:27 +00:00
|
|
|
|
const char *connectStr;
|
|
|
|
|
|
|
|
|
|
if (!reportError)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) {
|
|
|
|
|
connectStr = "standard PCI device";
|
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_DEVICE) {
|
|
|
|
|
connectStr = "PCI Express device";
|
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT) {
|
|
|
|
|
connectStr = "pcie-root-port";
|
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT) {
|
2018-10-17 01:10:57 +00:00
|
|
|
|
connectStr = "pcie-switch-upstream-port";
|
2016-08-06 01:19:27 +00:00
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT) {
|
2018-10-17 01:10:57 +00:00
|
|
|
|
connectStr = "pcie-switch-downstream-port";
|
2016-08-05 19:01:08 +00:00
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE) {
|
|
|
|
|
connectStr = "dmi-to-pci-bridge";
|
2018-01-11 16:28:43 +00:00
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE) {
|
|
|
|
|
connectStr = "pcie-to-pci-bridge";
|
2016-08-06 23:03:31 +00:00
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS) {
|
|
|
|
|
connectStr = "pci-expander-bus";
|
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) {
|
|
|
|
|
connectStr = "pcie-expander-bus";
|
2016-08-07 21:13:58 +00:00
|
|
|
|
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) {
|
|
|
|
|
connectStr = "pci-bridge";
|
2016-08-06 01:19:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
/* this should never happen. If it does, there is a
|
|
|
|
|
* bug in the code that sets the flag bits for devices.
|
|
|
|
|
*/
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("The device at PCI address %s has "
|
|
|
|
|
"unrecognized connection type flags 0x%.2x"),
|
|
|
|
|
addrStr, devFlags & VIR_PCI_CONNECT_TYPES_MASK);
|
|
|
|
|
return false;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
2016-08-06 01:19:27 +00:00
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("The device at PCI address %s cannot be "
|
|
|
|
|
"plugged into the PCI controller with index='%d'. "
|
|
|
|
|
"It requires a controller that accepts a %s."),
|
|
|
|
|
addrStr, addr->bus, connectStr);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Verify that the address is in bounds for the chosen bus, and
|
|
|
|
|
* that the bus is of the correct type for the device (via
|
|
|
|
|
* comparing the flags).
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
virDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr addr,
|
2014-05-13 16:10:40 +00:00
|
|
|
|
const char *addrStr,
|
|
|
|
|
virDomainPCIConnectFlags flags,
|
|
|
|
|
bool fromConfig)
|
|
|
|
|
{
|
|
|
|
|
virDomainPCIAddressBusPtr bus;
|
|
|
|
|
virErrorNumber errType = (fromConfig
|
|
|
|
|
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
|
|
|
|
|
|
|
|
|
if (addrs->nbuses == 0) {
|
|
|
|
|
virReportError(errType, "%s", _("No PCI buses available"));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (addr->domain != 0) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Invalid PCI address %s. "
|
|
|
|
|
"Only PCI domain 0 is available"),
|
|
|
|
|
addrStr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (addr->bus >= addrs->nbuses) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Invalid PCI address %s. "
|
|
|
|
|
"Only PCI buses up to %zu are available"),
|
|
|
|
|
addrStr, addrs->nbuses - 1);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bus = &addrs->buses[addr->bus];
|
|
|
|
|
|
|
|
|
|
/* assure that at least one of the requested connection types is
|
|
|
|
|
* provided by this bus
|
|
|
|
|
*/
|
|
|
|
|
if (!virDomainPCIAddressFlagsCompatible(addr, addrStr, bus->flags,
|
|
|
|
|
flags, true, fromConfig))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* some "buses" are really just a single port */
|
|
|
|
|
if (bus->minSlot && addr->slot < bus->minSlot) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Invalid PCI address %s. slot must be >= %zu"),
|
|
|
|
|
addrStr, bus->minSlot);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (addr->slot > bus->maxSlot) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Invalid PCI address %s. slot must be <= %zu"),
|
|
|
|
|
addrStr, bus->maxSlot);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (addr->function > VIR_PCI_ADDRESS_FUNCTION_LAST) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Invalid PCI address %s. function must be <= %u"),
|
|
|
|
|
addrStr, VIR_PCI_ADDRESS_FUNCTION_LAST);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
|
2020-04-06 02:40:37 +00:00
|
|
|
|
virDomainControllerModelPCI model,
|
|
|
|
|
bool allowHotplug)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
conf/qemu: change the way VIR_PCI_CONNECT_TYPE_* flags work
The flags used to determine which devices could be plugged into which
controllers were quite confusing, as they tried to create classes of
connections, then put particular devices into possibly multiple
classes, while sometimes setting multiple flags for the controllers
themselves. The attempt to have a single flag indicate, e.g. that a
root-port or a switch-downstream-port could connect was not only
confusing, it was leading to a situation where it would be impossible
to specify exactly the right combinations for a new controller.
The solution is for the VIR_PCI_CONNECT_TYPE_* flags to have a 1:1
correspondence with each type of PCI controller, plus a flag for a PCI
endpoint device and another for a PCIe endpoint device (the only
exception to this is that pci-bridge and pcie-expander-bus controllers
have their upstream connection classified as
VIR_PCI_CONNECT_TYPE_PCI_DEVICE since they can be plugged into
*exactly* the same ports as any endpoint device). Each device then
has a single flag for connect type (plus the HOTPLUG flag if that
device can e hotplugged), and each controller sets the CONNECT bits
for all controllers that can be plugged into it, as well as for either
type of endpoint device that can be plugged in (and the HOTPLUG flag
if it can accept hotplugged devices).
With this change, it is *slightly* easier to understand the matching
of connections (as long as you remember that the flag for a
device/upstream-facing connection of a controller is the same as that
device's type, while the flags for a controller's downstream
connections is the OR of all device types that can be plugged into
that controller). More importantly, it will be possible to correctly
specify what can be plugged into a pcie-switch-expander-bus, when
support for it is added.
2016-03-15 19:49:22 +00:00
|
|
|
|
/* set flags for what can be connected *downstream* from each
|
|
|
|
|
* bus.
|
|
|
|
|
*/
|
2020-04-06 02:40:37 +00:00
|
|
|
|
virDomainPCIConnectFlags hotplugFlag = 0;
|
|
|
|
|
|
|
|
|
|
if (allowHotplug)
|
|
|
|
|
hotplugFlag = VIR_PCI_CONNECT_HOTPLUGGABLE;
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
switch (model) {
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
|
2020-04-05 21:16:55 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_AUTOASSIGN |
|
2016-08-06 23:03:31 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
|
2016-08-07 21:13:58 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_BRIDGE |
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS |
|
|
|
|
|
hotplugFlag);
|
2016-08-06 23:03:31 +00:00
|
|
|
|
bus->minSlot = 1;
|
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
|
2020-04-05 21:16:55 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_AUTOASSIGN |
|
2016-08-07 21:13:58 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_BRIDGE |
|
|
|
|
|
hotplugFlag);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
bus->minSlot = 1;
|
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
2016-03-04 15:26:23 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
|
2020-04-05 21:16:55 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_AUTOASSIGN |
|
2016-08-07 21:13:58 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_BRIDGE |
|
|
|
|
|
hotplugFlag);
|
2016-03-04 15:26:23 +00:00
|
|
|
|
bus->minSlot = 0;
|
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
|
conf/qemu: change the way VIR_PCI_CONNECT_TYPE_* flags work
The flags used to determine which devices could be plugged into which
controllers were quite confusing, as they tried to create classes of
connections, then put particular devices into possibly multiple
classes, while sometimes setting multiple flags for the controllers
themselves. The attempt to have a single flag indicate, e.g. that a
root-port or a switch-downstream-port could connect was not only
confusing, it was leading to a situation where it would be impossible
to specify exactly the right combinations for a new controller.
The solution is for the VIR_PCI_CONNECT_TYPE_* flags to have a 1:1
correspondence with each type of PCI controller, plus a flag for a PCI
endpoint device and another for a PCIe endpoint device (the only
exception to this is that pci-bridge and pcie-expander-bus controllers
have their upstream connection classified as
VIR_PCI_CONNECT_TYPE_PCI_DEVICE since they can be plugged into
*exactly* the same ports as any endpoint device). Each device then
has a single flag for connect type (plus the HOTPLUG flag if that
device can e hotplugged), and each controller sets the CONNECT bits
for all controllers that can be plugged into it, as well as for either
type of endpoint device that can be plugged in (and the HOTPLUG flag
if it can accept hotplugged devices).
With this change, it is *slightly* easier to understand the matching
of connections (as long as you remember that the flag for a
device/upstream-facing connection of a controller is the same as that
device's type, while the flags for a controller's downstream
connections is the OR of all device types that can be plugged into
that controller). More importantly, it will be possible to correctly
specify what can be plugged into a pcie-switch-expander-bus, when
support for it is added.
2016-03-15 19:49:22 +00:00
|
|
|
|
/* slots 1 - 31, no hotplug, PCIe endpoint device or
|
|
|
|
|
* pcie-root-port only, unless the address was specified in
|
|
|
|
|
* user config *and* the particular device being attached also
|
|
|
|
|
* allows it.
|
2014-05-13 16:10:40 +00:00
|
|
|
|
*/
|
2016-08-05 19:01:08 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT |
|
2016-08-06 23:03:31 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
bus->minSlot = 1;
|
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
|
2016-03-02 20:29:33 +00:00
|
|
|
|
/* slots 0 - 31, standard PCI slots,
|
2014-05-13 16:10:40 +00:00
|
|
|
|
* but *not* hot-pluggable */
|
2016-08-07 21:13:58 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_BRIDGE);
|
2016-03-02 20:29:33 +00:00
|
|
|
|
bus->minSlot = 0;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
2018-01-11 16:28:43 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
|
|
|
|
|
/* Same as pci-bridge: 32 hotpluggable traditional PCI slots (0-31),
|
|
|
|
|
* the first of which is not usable because of the SHPC */
|
2020-04-05 21:16:55 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_AUTOASSIGN |
|
2018-01-11 16:28:43 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCI_BRIDGE |
|
|
|
|
|
hotplugFlag);
|
2018-01-11 16:28:43 +00:00
|
|
|
|
bus->minSlot = 1;
|
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
|
|
|
|
break;
|
2015-06-17 17:21:16 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
|
2015-06-17 19:27:40 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
|
conf/qemu: change the way VIR_PCI_CONNECT_TYPE_* flags work
The flags used to determine which devices could be plugged into which
controllers were quite confusing, as they tried to create classes of
connections, then put particular devices into possibly multiple
classes, while sometimes setting multiple flags for the controllers
themselves. The attempt to have a single flag indicate, e.g. that a
root-port or a switch-downstream-port could connect was not only
confusing, it was leading to a situation where it would be impossible
to specify exactly the right combinations for a new controller.
The solution is for the VIR_PCI_CONNECT_TYPE_* flags to have a 1:1
correspondence with each type of PCI controller, plus a flag for a PCI
endpoint device and another for a PCIe endpoint device (the only
exception to this is that pci-bridge and pcie-expander-bus controllers
have their upstream connection classified as
VIR_PCI_CONNECT_TYPE_PCI_DEVICE since they can be plugged into
*exactly* the same ports as any endpoint device). Each device then
has a single flag for connect type (plus the HOTPLUG flag if that
device can e hotplugged), and each controller sets the CONNECT bits
for all controllers that can be plugged into it, as well as for either
type of endpoint device that can be plugged in (and the HOTPLUG flag
if it can accept hotplugged devices).
With this change, it is *slightly* easier to understand the matching
of connections (as long as you remember that the flag for a
device/upstream-facing connection of a controller is the same as that
device's type, while the flags for a controller's downstream
connections is the OR of all device types that can be plugged into
that controller). More importantly, it will be possible to correctly
specify what can be plugged into a pcie-switch-expander-bus, when
support for it is added.
2016-03-15 19:49:22 +00:00
|
|
|
|
/* provides one slot which is pcie, can be used by endpoint
|
2018-01-11 16:28:43 +00:00
|
|
|
|
* devices, pcie-switch-upstream-ports or pcie-to-pci-bridges,
|
|
|
|
|
* and is hotpluggable */
|
2020-04-05 21:16:55 +00:00
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_AUTOASSIGN |
|
2018-01-11 16:28:43 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_DEVICE |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT |
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE |
|
|
|
|
|
hotplugFlag);
|
2015-06-17 17:21:16 +00:00
|
|
|
|
bus->minSlot = 0;
|
|
|
|
|
bus->maxSlot = 0;
|
|
|
|
|
break;
|
2015-06-16 19:00:44 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
|
2018-12-04 17:08:14 +00:00
|
|
|
|
/* 32 slots, can only accept pcie-switch-downstream-ports,
|
conf/qemu: change the way VIR_PCI_CONNECT_TYPE_* flags work
The flags used to determine which devices could be plugged into which
controllers were quite confusing, as they tried to create classes of
connections, then put particular devices into possibly multiple
classes, while sometimes setting multiple flags for the controllers
themselves. The attempt to have a single flag indicate, e.g. that a
root-port or a switch-downstream-port could connect was not only
confusing, it was leading to a situation where it would be impossible
to specify exactly the right combinations for a new controller.
The solution is for the VIR_PCI_CONNECT_TYPE_* flags to have a 1:1
correspondence with each type of PCI controller, plus a flag for a PCI
endpoint device and another for a PCIe endpoint device (the only
exception to this is that pci-bridge and pcie-expander-bus controllers
have their upstream connection classified as
VIR_PCI_CONNECT_TYPE_PCI_DEVICE since they can be plugged into
*exactly* the same ports as any endpoint device). Each device then
has a single flag for connect type (plus the HOTPLUG flag if that
device can e hotplugged), and each controller sets the CONNECT bits
for all controllers that can be plugged into it, as well as for either
type of endpoint device that can be plugged in (and the HOTPLUG flag
if it can accept hotplugged devices).
With this change, it is *slightly* easier to understand the matching
of connections (as long as you remember that the flag for a
device/upstream-facing connection of a controller is the same as that
device's type, while the flags for a controller's downstream
connections is the OR of all device types that can be plugged into
that controller). More importantly, it will be possible to correctly
specify what can be plugged into a pcie-switch-expander-bus, when
support for it is added.
2016-03-15 19:49:22 +00:00
|
|
|
|
* no hotplug
|
|
|
|
|
*/
|
|
|
|
|
bus->flags = VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT;
|
2015-06-16 19:00:44 +00:00
|
|
|
|
bus->minSlot = 0;
|
2016-03-02 20:31:02 +00:00
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
2015-06-16 19:00:44 +00:00
|
|
|
|
break;
|
2016-03-16 17:37:14 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
|
2016-10-05 15:26:07 +00:00
|
|
|
|
/* 32 slots, no hotplug, only accepts pcie-root-port or
|
2016-08-05 19:01:08 +00:00
|
|
|
|
* dmi-to-pci-bridge
|
|
|
|
|
*/
|
|
|
|
|
bus->flags = (VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE);
|
2016-03-16 17:37:14 +00:00
|
|
|
|
bus->minSlot = 0;
|
2016-10-05 15:26:07 +00:00
|
|
|
|
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
2016-03-16 17:37:14 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2018-02-14 10:51:26 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
|
2017-02-21 19:13:47 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2017-02-21 19:13:47 +00:00
|
|
|
|
"%s", _("PCI controller model was not set correctly"));
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bus->model = model;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-06-29 14:13:02 +00:00
|
|
|
|
bool
|
|
|
|
|
virDomainPCIAddressBusIsFullyReserved(virDomainPCIAddressBusPtr bus)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = bus->minSlot; i <= bus->maxSlot; i++) {
|
|
|
|
|
if (!bus->slot[i].functions)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-07-03 20:19:48 +00:00
|
|
|
|
static bool ATTRIBUTE_NONNULL(1)
|
2017-06-15 08:40:42 +00:00
|
|
|
|
virDomainPCIAddressBusIsEmpty(virDomainPCIAddressBusPtr bus)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = bus->minSlot; i <= bus->maxSlot; i++) {
|
|
|
|
|
if (bus->slot[i].functions)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
/* Ensure addr fits in the address set, by expanding it if needed
|
2014-05-13 16:10:40 +00:00
|
|
|
|
*
|
|
|
|
|
* Return value:
|
|
|
|
|
* -1 = OOM
|
|
|
|
|
* 0 = no action performed
|
|
|
|
|
* >0 = number of buses added
|
|
|
|
|
*/
|
2017-05-26 08:27:41 +00:00
|
|
|
|
static int
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr addr,
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainPCIConnectFlags flags)
|
|
|
|
|
{
|
|
|
|
|
int add;
|
|
|
|
|
size_t i;
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
int model;
|
|
|
|
|
bool needDMIToPCIBridge = false;
|
2018-03-28 10:48:21 +00:00
|
|
|
|
bool needPCIeToPCIBridge = false;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
|
|
|
|
add = addr->bus - addrs->nbuses + 1;
|
|
|
|
|
if (add <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
/* remember that the flags aren't for the type of controller that
|
|
|
|
|
* we want to add, they are the type of *device* that we want to
|
|
|
|
|
* plug in, and this function must decide on the appropriate
|
|
|
|
|
* controller to add in order to give us a slot for that device.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) {
|
2018-03-28 10:28:38 +00:00
|
|
|
|
if (addrs->areMultipleRootsSupported) {
|
2017-05-29 15:18:35 +00:00
|
|
|
|
/* Use a pci-root controller to expand the guest's PCI
|
|
|
|
|
* topology if it supports having more than one */
|
|
|
|
|
model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT;
|
|
|
|
|
} else {
|
|
|
|
|
model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
|
2017-05-29 15:18:35 +00:00
|
|
|
|
/* if there aren't yet any buses that will accept a
|
2018-03-28 10:48:21 +00:00
|
|
|
|
* pci-bridge, but we need one for the device's PCI address
|
|
|
|
|
* to make sense, it means the guest only has a PCIe topology
|
|
|
|
|
* configured so far, and we need to create a traditional PCI
|
2018-12-04 17:08:14 +00:00
|
|
|
|
* topology to accommodate the new device.
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
*/
|
2017-05-29 15:18:35 +00:00
|
|
|
|
needDMIToPCIBridge = true;
|
2018-03-28 10:48:21 +00:00
|
|
|
|
needPCIeToPCIBridge = true;
|
2017-05-29 15:18:35 +00:00
|
|
|
|
for (i = 0; i < addrs->nbuses; i++) {
|
|
|
|
|
if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) {
|
|
|
|
|
needDMIToPCIBridge = false;
|
2018-03-28 10:48:21 +00:00
|
|
|
|
needPCIeToPCIBridge = false;
|
2017-05-29 15:18:35 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-28 10:48:21 +00:00
|
|
|
|
|
|
|
|
|
/* Prefer pcie-to-pci-bridge, fall back to dmi-to-pci-bridge */
|
|
|
|
|
if (addrs->isPCIeToPCIBridgeSupported)
|
|
|
|
|
needDMIToPCIBridge = false;
|
|
|
|
|
else
|
|
|
|
|
needPCIeToPCIBridge = false;
|
|
|
|
|
|
|
|
|
|
if ((needDMIToPCIBridge || needPCIeToPCIBridge) && add == 1) {
|
2017-05-29 15:18:35 +00:00
|
|
|
|
/* We need to add a single pci-bridge to provide the bus
|
|
|
|
|
* our legacy PCI device will be plugged into; however, we
|
|
|
|
|
* have also determined that there isn't yet any proper
|
2018-03-28 10:48:21 +00:00
|
|
|
|
* place to connect that pci-bridge we're about to add,
|
|
|
|
|
* which means we're dealing with a pure PCIe guest. We
|
|
|
|
|
* need to create a traditional PCI topology, and for that
|
|
|
|
|
* we have two options: dmi-to-pci-bridge + pci-bridge or
|
|
|
|
|
* pcie-root-port + pcie-to-pci-bridge (the latter of which
|
|
|
|
|
* is pretty much a pci-bridge as far as devices attached
|
|
|
|
|
* to it are concerned and as such makes the pci-bridge
|
|
|
|
|
* unnecessary). Either way, there's going to be one more
|
|
|
|
|
* controller than initially expected, and the 'bus' part
|
|
|
|
|
* of the device's address will need to be bumped.
|
2017-05-29 15:18:35 +00:00
|
|
|
|
*/
|
|
|
|
|
add++;
|
|
|
|
|
addr->bus++;
|
|
|
|
|
}
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (flags & (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE |
|
|
|
|
|
VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)) {
|
|
|
|
|
model = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
|
|
|
|
|
} else {
|
|
|
|
|
/* The types of devices that we can't auto-add a controller for:
|
|
|
|
|
*
|
|
|
|
|
* VIR_CONNECT_TYPE_DMI_TO_PCI_BRIDGE &
|
|
|
|
|
* VIR_PCI_CONNECT_TYPE_ROOT_PORT - these can only plug into
|
|
|
|
|
* pcie-root or pcie-expander-bus. By definition there is
|
|
|
|
|
* only 1 pcie-root, and we don't support auto-adding
|
|
|
|
|
* pcie-expander-bus (because it is intended for NUMA usage,
|
|
|
|
|
* and we can't automatically decide which numa node to
|
|
|
|
|
* associate it with)
|
|
|
|
|
*
|
|
|
|
|
* VIR_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT - we ndon't
|
|
|
|
|
* support this, because it can only plug into an
|
|
|
|
|
* upstream-port, and the upstream port might need a
|
|
|
|
|
* root-port; supporting this extra layer needlessly
|
|
|
|
|
* complicates the code, and upstream/downstream ports are
|
|
|
|
|
* outside the scope of our "automatic-bus-expansion" model
|
|
|
|
|
* anyway.
|
|
|
|
|
*
|
|
|
|
|
* VIR_CONNECT_TYPE_PCI[E]_EXPANDER_BUS - these were created
|
|
|
|
|
* to support guest awareness of the NUMA node placement of
|
|
|
|
|
* devices on the host, and are also outside the scope of our
|
|
|
|
|
* "automatic-bus-expansion".
|
|
|
|
|
*
|
|
|
|
|
* VIR_PCI_CONNECT_TYPE_PCI_BRIDGE (when the root bus is
|
|
|
|
|
* pci-root) - see the comment above in the case that handles
|
|
|
|
|
* adding a slot for pci-bridge to a guest with pcie-root.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
int existingContModel = virDomainPCIControllerConnectTypeToModel(flags);
|
|
|
|
|
|
|
|
|
|
if (existingContModel >= 0) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("a PCI slot is needed to connect a PCI controller "
|
|
|
|
|
"model='%s', but none is available, and it "
|
|
|
|
|
"cannot be automatically added"),
|
|
|
|
|
virDomainControllerModelPCITypeToString(existingContModel));
|
|
|
|
|
} else {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("Cannot automatically add a new PCI bus for a "
|
|
|
|
|
"device with connect flags %.2x"), flags);
|
|
|
|
|
}
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
i = addrs->nbuses;
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
if (needDMIToPCIBridge) {
|
|
|
|
|
/* first of the new buses is dmi-to-pci-bridge, the
|
|
|
|
|
* rest are of the requested type
|
2014-05-13 16:10:40 +00:00
|
|
|
|
*/
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
if (virDomainPCIAddressBusSetModel(&addrs->buses[i++],
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE, false) < 0) {
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
|
2018-03-28 10:48:21 +00:00
|
|
|
|
if (needPCIeToPCIBridge) {
|
|
|
|
|
/* We need a pcie-root-port to plug pcie-to-pci-bridge into; however,
|
|
|
|
|
* qemuDomainAssignPCIAddresses() will, in some cases, create a dummy
|
|
|
|
|
* PCIe device and reserve an address for it in order to leave the
|
|
|
|
|
* user with an empty pcie-root-port ready for hotplugging, and if
|
|
|
|
|
* we didn't do anything other than adding the pcie-root-port here
|
|
|
|
|
* it would be used for that, which we don't want. So we change the
|
|
|
|
|
* connect flags to make sure only the pcie-to-pci-bridge will be
|
|
|
|
|
* connected to the pcie-root-port we just added, and another one
|
|
|
|
|
* will be allocated for the dummy PCIe device later on.
|
|
|
|
|
*/
|
|
|
|
|
if (virDomainPCIAddressBusSetModel(&addrs->buses[i],
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT, true) < 0) {
|
2018-03-28 10:48:21 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
addrs->buses[i].flags = VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE;
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
if (virDomainPCIAddressBusSetModel(&addrs->buses[i++],
|
2020-04-06 02:40:37 +00:00
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE, true) < 0) {
|
2018-03-28 10:48:21 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
for (; i < addrs->nbuses; i++) {
|
2020-04-06 02:40:37 +00:00
|
|
|
|
if (virDomainPCIAddressBusSetModel(&addrs->buses[i], model, true) < 0)
|
qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically
adding pcie-root-ports is fairly straightforward. The
dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that
there is a reasonable place to plug in a pci-bridge controller,
most of the time it's not the presence of a pci-bridge *in the
config* that triggers the requirement to add a dmi-to-pci-bridge.
Rather, it is the presence of a legacy-PCI device in the config,
which triggers auto-add of a pci-bridge, which triggers auto-add of
a dmi-to-pci-bridge (this is handled in
virDomainPCIAddressSetGrow() - if there's a request to add a
pci-bridge we'll check if there is a suitable bus to plug it into;
if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system,
there won't be a need for any more, even if it's full, as long as
there is a pci-bridge with an open slot - you can also plug
pci-bridges into existing pci-bridges. So we have to make sure we
don't add a dmi-to-pci-bridge unless there aren't any
dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge
to be directly plugged into pcie-root, and we don't want to
auto-add a dmi-to-pci-bridge if there is already a pci-bridge
that's been forced directly into pcie-root.
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in a future
patch.
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
2016-09-19 18:38:47 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return add;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check if the PCI slot is used by another device.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr addr)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2016-10-16 21:14:25 +00:00
|
|
|
|
return !!addrs->buses[addr->bus].slot[addr->slot].functions;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2016-10-19 16:43:04 +00:00
|
|
|
|
* Reserve a function in a slot. If fromConfig is true, the address
|
|
|
|
|
* being requested came directly from the config and errors should be
|
|
|
|
|
* worded appropriately. If fromConfig is false, the address was
|
2014-05-13 16:10:40 +00:00
|
|
|
|
* automatically created by libvirt, so it is an internal error (not
|
|
|
|
|
* XML).
|
|
|
|
|
*/
|
2016-10-23 16:03:47 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
2016-10-23 16:07:20 +00:00
|
|
|
|
virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressPtr addr,
|
|
|
|
|
virDomainPCIConnectFlags flags,
|
2017-06-15 08:40:42 +00:00
|
|
|
|
unsigned int isolationGroup,
|
2016-10-23 16:07:20 +00:00
|
|
|
|
bool fromConfig)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *addrStr = NULL;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainPCIAddressBusPtr bus;
|
|
|
|
|
virErrorNumber errType = (fromConfig
|
|
|
|
|
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
|
|
|
|
|
2018-09-04 16:50:32 +00:00
|
|
|
|
if (!(addrStr = virPCIDeviceAddressAsString(addr)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
|
|
|
|
/* Add an extra bus if necessary */
|
|
|
|
|
if (addrs->dryRun && virDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
/* Check that the requested bus exists, is the correct type, and we
|
|
|
|
|
* are asking for a valid slot
|
|
|
|
|
*/
|
|
|
|
|
if (!virDomainPCIAddressValidate(addrs, addr, addrStr, flags, fromConfig))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
|
|
|
|
bus = &addrs->buses[addr->bus];
|
|
|
|
|
|
2016-10-19 16:43:04 +00:00
|
|
|
|
if (bus->slot[addr->slot].functions & (1 << addr->function)) {
|
|
|
|
|
virReportError(errType,
|
|
|
|
|
_("Attempted double use of PCI Address %s"), addrStr);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
2016-10-19 18:15:01 +00:00
|
|
|
|
|
|
|
|
|
/* if this is the first function to be reserved on this slot, and
|
|
|
|
|
* the device it's being reserved for can aggregate multiples on a
|
|
|
|
|
* slot, set the slot's aggregate flag.
|
|
|
|
|
*/
|
|
|
|
|
if (!bus->slot[addr->slot].functions &&
|
|
|
|
|
flags & VIR_PCI_CONNECT_AGGREGATE_SLOT) {
|
|
|
|
|
bus->slot[addr->slot].aggregate = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-15 08:40:42 +00:00
|
|
|
|
if (virDomainPCIAddressBusIsEmpty(bus) && !bus->isolationGroupLocked) {
|
|
|
|
|
/* The first device decides the isolation group for the
|
|
|
|
|
* entire bus */
|
|
|
|
|
bus->isolationGroup = isolationGroup;
|
2019-07-30 14:24:39 +00:00
|
|
|
|
VIR_DEBUG("PCI bus %04x:%02x assigned isolation group %u because of "
|
2017-06-15 08:40:42 +00:00
|
|
|
|
"first device %s",
|
|
|
|
|
addr->domain, addr->bus, isolationGroup, addrStr);
|
|
|
|
|
} else if (bus->isolationGroup != isolationGroup && fromConfig) {
|
|
|
|
|
/* If this is not the first function and its isolation group
|
|
|
|
|
* doesn't match the bus', then it should not be using this
|
|
|
|
|
* address. However, if the address comes from the user then
|
|
|
|
|
* we comply with the request and change the isolation group
|
|
|
|
|
* back to the default (because at that point isolation can't
|
|
|
|
|
* be guaranteed anymore) */
|
|
|
|
|
bus->isolationGroup = 0;
|
2019-07-30 14:24:39 +00:00
|
|
|
|
VIR_DEBUG("PCI bus %04x:%02x assigned isolation group %u because of "
|
2017-06-15 08:40:42 +00:00
|
|
|
|
"user assigned address %s",
|
|
|
|
|
addr->domain, addr->bus, isolationGroup, addrStr);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-19 18:15:01 +00:00
|
|
|
|
/* mark the requested function as reserved */
|
2016-10-19 16:43:04 +00:00
|
|
|
|
bus->slot[addr->slot].functions |= (1 << addr->function);
|
2016-10-19 18:15:01 +00:00
|
|
|
|
VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr,
|
|
|
|
|
bus->slot[addr->slot].aggregate ? "true" : "false");
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2016-10-23 16:14:16 +00:00
|
|
|
|
virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr addr,
|
2017-06-15 08:38:33 +00:00
|
|
|
|
virDomainPCIConnectFlags flags,
|
|
|
|
|
unsigned int isolationGroup)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2017-06-15 08:38:33 +00:00
|
|
|
|
return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags,
|
|
|
|
|
isolationGroup, true);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
2016-09-07 16:29:30 +00:00
|
|
|
|
virDomainDeviceInfoPtr dev,
|
|
|
|
|
virDomainPCIConnectFlags flags)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *addrStr = NULL;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
2016-10-07 22:08:13 +00:00
|
|
|
|
/* if flags is 0, the particular model of this device on this
|
|
|
|
|
* machinetype doesn't need a PCI address, so we're done.
|
|
|
|
|
*/
|
|
|
|
|
if (!flags)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-04-06 03:44:16 +00:00
|
|
|
|
/* This function is only called during hotplug, so we require hotplug
|
|
|
|
|
* support from the controller.
|
|
|
|
|
*/
|
|
|
|
|
flags |= VIR_PCI_CONNECT_HOTPLUGGABLE;
|
|
|
|
|
|
2018-09-04 16:50:32 +00:00
|
|
|
|
if (!(addrStr = virPCIDeviceAddressAsString(&dev->addr.pci)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
2018-08-17 13:12:42 +00:00
|
|
|
|
if (virDeviceInfoPCIAddressIsPresent(dev)) {
|
2014-05-13 16:10:40 +00:00
|
|
|
|
/* We do not support hotplug multi-function PCI device now, so we should
|
|
|
|
|
* reserve the whole slot. The function of the PCI device must be 0.
|
|
|
|
|
*/
|
|
|
|
|
if (dev->addr.pci.function != 0) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
|
_("Only PCI device addresses with function=0"
|
|
|
|
|
" are supported"));
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!virDomainPCIAddressValidate(addrs, &dev->addr.pci,
|
|
|
|
|
addrStr, flags, true))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
2018-11-16 14:04:07 +00:00
|
|
|
|
if (virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
|
|
|
|
|
flags, dev->isolationGroup,
|
|
|
|
|
true) < 0) {
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2018-11-16 14:04:07 +00:00
|
|
|
|
}
|
2014-05-13 16:10:40 +00:00
|
|
|
|
} else {
|
2018-11-16 14:04:07 +00:00
|
|
|
|
if (virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1) < 0)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:00:28 +00:00
|
|
|
|
dev->addr.pci.extFlags = dev->pciAddrExtFlags;
|
2018-11-16 14:04:07 +00:00
|
|
|
|
if (virDomainPCIAddressExtensionEnsureAddr(addrs, &dev->addr.pci) < 0)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2018-11-08 11:00:28 +00:00
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-11-08 11:00:28 +00:00
|
|
|
|
void
|
|
|
|
|
virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
|
|
|
|
|
virDomainZPCIAddressReleaseIds(addrs->zpciIds, &addr->zpci);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-10-18 14:12:53 +00:00
|
|
|
|
void
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr addr)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2016-10-16 21:14:25 +00:00
|
|
|
|
addrs->buses[addr->bus].slot[addr->slot].functions &= ~(1 << addr->function);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:00:24 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
virDomainPCIAddressSetExtensionFree(virDomainPCIAddressSetPtr addrs)
|
|
|
|
|
{
|
|
|
|
|
if (!addrs || !addrs->zpciIds)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
g_clear_pointer(&addrs->zpciIds->uids, g_hash_table_unref);
|
|
|
|
|
g_clear_pointer(&addrs->zpciIds->fids, g_hash_table_unref);
|
|
|
|
|
|
2018-11-08 11:00:24 +00:00
|
|
|
|
VIR_FREE(addrs->zpciIds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainPCIAddressSetExtensionAlloc(virDomainPCIAddressSetPtr addrs,
|
|
|
|
|
virPCIDeviceAddressExtensionFlags extFlags)
|
|
|
|
|
{
|
|
|
|
|
if (extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
|
|
|
|
|
if (addrs->zpciIds)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
addrs->zpciIds = g_new0(virDomainZPCIAddressIds, 1);
|
2018-11-08 11:00:24 +00:00
|
|
|
|
|
2020-10-20 15:31:23 +00:00
|
|
|
|
addrs->zpciIds->uids = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
|
|
|
|
|
addrs->zpciIds->fids = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
|
2018-11-08 11:00:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainPCIAddressSetPtr
|
2018-11-08 11:00:24 +00:00
|
|
|
|
virDomainPCIAddressSetAlloc(unsigned int nbuses,
|
|
|
|
|
virPCIDeviceAddressExtensionFlags extFlags)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
|
|
|
|
virDomainPCIAddressSetPtr addrs;
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
addrs = g_new0(virDomainPCIAddressSet, 1);
|
|
|
|
|
addrs->buses = g_new0(virDomainPCIAddressBus, nbuses);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
addrs->nbuses = nbuses;
|
2018-11-08 11:00:24 +00:00
|
|
|
|
|
|
|
|
|
if (virDomainPCIAddressSetExtensionAlloc(addrs, extFlags) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return addrs;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
virDomainPCIAddressSetFree(addrs);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
|
|
|
|
|
{
|
|
|
|
|
if (!addrs)
|
|
|
|
|
return;
|
|
|
|
|
|
2018-11-08 11:00:24 +00:00
|
|
|
|
virDomainPCIAddressSetExtensionFree(addrs);
|
2014-05-13 16:10:40 +00:00
|
|
|
|
VIR_FREE(addrs->buses);
|
|
|
|
|
VIR_FREE(addrs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-19 17:58:42 +00:00
|
|
|
|
static int
|
|
|
|
|
virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
|
|
|
|
|
virPCIDeviceAddressPtr searchAddr,
|
2016-10-19 18:15:01 +00:00
|
|
|
|
int function,
|
2016-10-19 17:58:42 +00:00
|
|
|
|
virDomainPCIConnectFlags flags,
|
|
|
|
|
bool *found)
|
|
|
|
|
{
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *addrStr = NULL;
|
2016-10-19 17:58:42 +00:00
|
|
|
|
|
|
|
|
|
*found = false;
|
|
|
|
|
|
2018-09-04 16:50:32 +00:00
|
|
|
|
if (!(addrStr = virPCIDeviceAddressAsString(searchAddr)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2016-10-19 17:58:42 +00:00
|
|
|
|
|
|
|
|
|
if (!virDomainPCIAddressFlagsCompatible(searchAddr, addrStr, bus->flags,
|
|
|
|
|
flags, false, false)) {
|
2019-07-30 14:24:39 +00:00
|
|
|
|
VIR_DEBUG("PCI bus %04x:%02x is not compatible with the device",
|
2016-10-19 17:58:42 +00:00
|
|
|
|
searchAddr->domain, searchAddr->bus);
|
|
|
|
|
} else {
|
|
|
|
|
while (searchAddr->slot <= bus->maxSlot) {
|
|
|
|
|
if (bus->slot[searchAddr->slot].functions == 0) {
|
|
|
|
|
*found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-19 18:15:01 +00:00
|
|
|
|
if (flags & VIR_PCI_CONNECT_AGGREGATE_SLOT &&
|
|
|
|
|
bus->slot[searchAddr->slot].aggregate) {
|
|
|
|
|
/* slot and device are okay with aggregating devices */
|
|
|
|
|
if ((bus->slot[searchAddr->slot].functions &
|
|
|
|
|
(1 << searchAddr->function)) == 0) {
|
|
|
|
|
*found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* also check for *any* unused function if caller
|
|
|
|
|
* sent function = -1
|
|
|
|
|
*/
|
|
|
|
|
if (function == -1) {
|
|
|
|
|
while (searchAddr->function < 8) {
|
|
|
|
|
if ((bus->slot[searchAddr->slot].functions &
|
|
|
|
|
(1 << searchAddr->function)) == 0) {
|
|
|
|
|
*found = true;
|
|
|
|
|
break; /* out of inner while */
|
|
|
|
|
}
|
|
|
|
|
searchAddr->function++;
|
|
|
|
|
}
|
|
|
|
|
if (*found)
|
|
|
|
|
break; /* out of outer while */
|
|
|
|
|
searchAddr->function = 0; /* reset for next try */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-30 14:24:39 +00:00
|
|
|
|
VIR_DEBUG("PCI slot %04x:%02x:%02x already in use",
|
2016-10-19 17:58:42 +00:00
|
|
|
|
searchAddr->domain, searchAddr->bus, searchAddr->slot);
|
|
|
|
|
searchAddr->slot++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2016-10-19 17:58:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-09-01 15:38:02 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
2016-10-22 17:10:10 +00:00
|
|
|
|
virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddressPtr next_addr,
|
2017-05-29 12:05:54 +00:00
|
|
|
|
virDomainPCIConnectFlags flags,
|
2017-06-15 08:40:42 +00:00
|
|
|
|
unsigned int isolationGroup,
|
2017-05-29 12:05:54 +00:00
|
|
|
|
int function)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2016-10-19 17:58:42 +00:00
|
|
|
|
virPCIDeviceAddress a = { 0 };
|
2014-05-13 16:10:40 +00:00
|
|
|
|
|
|
|
|
|
if (addrs->nbuses == 0) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
|
2020-01-06 21:57:26 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-19 16:43:04 +00:00
|
|
|
|
/* if the caller asks for "any function", give them function 0 */
|
|
|
|
|
if (function == -1)
|
|
|
|
|
a.function = 0;
|
|
|
|
|
else
|
|
|
|
|
a.function = function;
|
|
|
|
|
|
2017-06-15 08:40:42 +00:00
|
|
|
|
/* When looking for a suitable bus for the device, start by being
|
|
|
|
|
* very strict and ignoring all those where the isolation groups
|
|
|
|
|
* don't match. This ensures all devices sharing the same isolation
|
|
|
|
|
* group will end up on the same bus */
|
2017-06-01 13:18:50 +00:00
|
|
|
|
for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
|
|
|
|
|
virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus];
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
2017-06-15 08:40:42 +00:00
|
|
|
|
if (bus->isolationGroup != isolationGroup)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
a.slot = bus->minSlot;
|
|
|
|
|
|
|
|
|
|
if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
|
|
|
|
|
flags, &found) < 0) {
|
2020-01-06 21:57:26 +00:00
|
|
|
|
return -1;
|
2017-06-15 08:40:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We haven't been able to find a perfectly matching bus, but we
|
|
|
|
|
* might still be able to make this work by altering the isolation
|
|
|
|
|
* group for a bus that's currently empty. So let's try that */
|
|
|
|
|
for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
|
|
|
|
|
virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus];
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
|
|
/* We can only change the isolation group for a bus when
|
|
|
|
|
* plugging in the first device; moreover, some buses are
|
|
|
|
|
* prevented from ever changing it */
|
|
|
|
|
if (!virDomainPCIAddressBusIsEmpty(bus) || bus->isolationGroupLocked)
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-06-01 13:18:50 +00:00
|
|
|
|
a.slot = bus->minSlot;
|
|
|
|
|
|
|
|
|
|
if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
|
2016-10-19 17:58:42 +00:00
|
|
|
|
flags, &found) < 0) {
|
2020-01-06 21:57:26 +00:00
|
|
|
|
return -1;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
2016-10-19 17:58:42 +00:00
|
|
|
|
|
2017-06-15 08:40:42 +00:00
|
|
|
|
/* The isolation group for the bus will actually be changed
|
|
|
|
|
* later, in virDomainPCIAddressReserveAddrInternal() */
|
2016-10-19 17:58:42 +00:00
|
|
|
|
if (found)
|
|
|
|
|
goto success;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* There were no free slots after the last used one */
|
|
|
|
|
if (addrs->dryRun) {
|
2015-07-16 20:28:47 +00:00
|
|
|
|
/* a is already set to the first new bus */
|
2014-05-13 16:10:40 +00:00
|
|
|
|
if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
|
2020-01-06 21:57:26 +00:00
|
|
|
|
return -1;
|
2015-07-16 20:28:47 +00:00
|
|
|
|
/* this device will use the first slot of the new bus */
|
|
|
|
|
a.slot = addrs->buses[a.bus].minSlot;
|
2014-05-13 16:10:40 +00:00
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
"%s", _("No more available PCI slots"));
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
success:
|
2019-07-30 14:24:39 +00:00
|
|
|
|
VIR_DEBUG("Found free PCI slot %04x:%02x:%02x",
|
2014-05-13 16:10:40 +00:00
|
|
|
|
a.domain, a.bus, a.slot);
|
|
|
|
|
*next_addr = a;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-01 13:29:01 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* virDomainPCIAddressReserveNextAddr:
|
|
|
|
|
*
|
|
|
|
|
* @addrs: a set of PCI addresses.
|
|
|
|
|
* @dev: virDomainDeviceInfo that should get the new address.
|
|
|
|
|
* @flags: CONNECT_TYPE flags for the device that needs an address.
|
|
|
|
|
* @function: which function on the slot to mark as reserved
|
|
|
|
|
*
|
|
|
|
|
* Find the next *completely unreserved* slot with compatible
|
2016-10-19 16:43:04 +00:00
|
|
|
|
* connection @flags, mark one function of the slot as in-use
|
|
|
|
|
* (according to @function), then set @dev->addr.pci with this newly
|
|
|
|
|
* reserved address. If @function is -1, then the lowest unused
|
|
|
|
|
* function of the slot will be reserved (and since we only look for
|
|
|
|
|
* completely unused slots, that means "0").
|
2016-09-01 13:29:01 +00:00
|
|
|
|
*
|
|
|
|
|
* returns 0 on success, or -1 on failure.
|
|
|
|
|
*/
|
2014-05-13 16:10:40 +00:00
|
|
|
|
int
|
2016-09-01 13:29:01 +00:00
|
|
|
|
virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
|
2014-05-13 16:10:40 +00:00
|
|
|
|
virDomainDeviceInfoPtr dev,
|
2016-09-01 13:29:01 +00:00
|
|
|
|
virDomainPCIConnectFlags flags,
|
2016-10-19 16:43:04 +00:00
|
|
|
|
int function)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
{
|
2016-04-03 18:16:51 +00:00
|
|
|
|
virPCIDeviceAddress addr;
|
2016-09-01 13:29:01 +00:00
|
|
|
|
|
2017-06-15 08:38:33 +00:00
|
|
|
|
if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags,
|
|
|
|
|
dev->isolationGroup, function) < 0)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return -1;
|
|
|
|
|
|
2017-06-15 08:38:33 +00:00
|
|
|
|
if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags,
|
|
|
|
|
dev->isolationGroup, false) < 0)
|
2014-05-13 16:10:40 +00:00
|
|
|
|
return -1;
|
|
|
|
|
|
2018-11-08 11:00:26 +00:00
|
|
|
|
addr.extFlags = dev->addr.pci.extFlags;
|
|
|
|
|
addr.zpci = dev->addr.pci.zpci;
|
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
|
if (!addrs->dryRun) {
|
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
|
dev->addr.pci = addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-06-17 14:17:41 +00:00
|
|
|
|
|
|
|
|
|
|
2017-01-10 05:02:40 +00:00
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
|
virDomainPCIAddressSetMultiIter(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
|
virDomainDeviceDefPtr dev G_GNUC_UNUSED,
|
2017-01-10 05:02:40 +00:00
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
virPCIDeviceAddressPtr testAddr = data;
|
|
|
|
|
virPCIDeviceAddressPtr thisAddr;
|
|
|
|
|
|
|
|
|
|
if (!info || info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
thisAddr = &info->addr.pci;
|
|
|
|
|
|
|
|
|
|
if (thisAddr->domain == testAddr->domain &&
|
|
|
|
|
thisAddr->bus == testAddr->bus &&
|
|
|
|
|
thisAddr->slot == testAddr->slot &&
|
|
|
|
|
thisAddr->function == 0) {
|
|
|
|
|
|
|
|
|
|
/* only set to ON if it wasn't previously set
|
|
|
|
|
* (assuming that the user must have better information
|
|
|
|
|
* than us if they explicitly set it OFF)
|
|
|
|
|
*/
|
|
|
|
|
if (thisAddr->multi == VIR_TRISTATE_SWITCH_ABSENT)
|
|
|
|
|
thisAddr->multi = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
|
|
|
|
|
|
return -1; /* finish early, *NOT* an error */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainPCIAddressSetAllMultiIter(virDomainDefPtr def,
|
2019-10-14 12:45:33 +00:00
|
|
|
|
virDomainDeviceDefPtr dev G_GNUC_UNUSED,
|
2017-01-10 05:02:40 +00:00
|
|
|
|
virDomainDeviceInfoPtr info,
|
2019-10-14 12:45:33 +00:00
|
|
|
|
void *data G_GNUC_UNUSED)
|
2017-01-10 05:02:40 +00:00
|
|
|
|
{
|
|
|
|
|
virPCIDeviceAddressPtr testAddr;
|
|
|
|
|
|
|
|
|
|
if (!info || info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
testAddr = &info->addr.pci;
|
|
|
|
|
|
|
|
|
|
if (testAddr->function != 0) {
|
|
|
|
|
ignore_value(virDomainDeviceInfoIterate(def,
|
|
|
|
|
virDomainPCIAddressSetMultiIter,
|
|
|
|
|
testAddr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* virDomainPCIAddressSetAllMulti():
|
|
|
|
|
*
|
|
|
|
|
* @def: the domain definition whose devices may need adjusting
|
|
|
|
|
* @addrs: address set keeping track of all addresses in use.
|
|
|
|
|
*
|
|
|
|
|
* Look for any PCI slots that have multiple functions assigned, and
|
|
|
|
|
* set multi to ON in the address for the device at function 0
|
|
|
|
|
* (unless it has been explicitly set to OFF).
|
|
|
|
|
*
|
|
|
|
|
* No return code, since there is no possibility of failure.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
virDomainPCIAddressSetAllMulti(virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
/* Use nested iterators over all the devices - the outer iterator
|
|
|
|
|
* scans through all the devices looking for those whose address
|
|
|
|
|
* has a non-0 function; when one is found, the inner iterator looks
|
|
|
|
|
* for the device that uses function 0 on the same slot and marks
|
|
|
|
|
* it as multi = ON
|
|
|
|
|
*/
|
|
|
|
|
ignore_value(virDomainDeviceInfoIterate(def,
|
|
|
|
|
virDomainPCIAddressSetAllMultiIter,
|
|
|
|
|
NULL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-14 19:11:47 +00:00
|
|
|
|
char*
|
2014-06-17 14:17:41 +00:00
|
|
|
|
virDomainCCWAddressAsString(virDomainDeviceCCWAddressPtr addr)
|
|
|
|
|
{
|
2020-05-04 15:03:42 +00:00
|
|
|
|
return g_strdup_printf("%x.%x.%04x", addr->cssid, addr->ssid, addr->devno);
|
2014-06-17 14:17:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainCCWAddressIncrement(virDomainDeviceCCWAddressPtr addr)
|
|
|
|
|
{
|
|
|
|
|
virDomainDeviceCCWAddress ccwaddr = *addr;
|
|
|
|
|
|
|
|
|
|
/* We are not touching subchannel sets and channel subsystems */
|
|
|
|
|
if (++ccwaddr.devno > VIR_DOMAIN_DEVICE_CCW_MAX_DEVNO)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
*addr = ccwaddr;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainCCWAddressAssign(virDomainDeviceInfoPtr dev,
|
|
|
|
|
virDomainCCWAddressSetPtr addrs,
|
|
|
|
|
bool autoassign)
|
|
|
|
|
{
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *addr = NULL;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
|
|
|
|
|
if (dev->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!autoassign && dev->addr.ccw.assigned) {
|
|
|
|
|
if (!(addr = virDomainCCWAddressAsString(&dev->addr.ccw)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
|
|
|
|
|
if (virHashLookup(addrs->defined, addr)) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2020-09-23 15:31:40 +00:00
|
|
|
|
_("The CCW devno '%s' is in use already"),
|
2014-06-17 14:17:41 +00:00
|
|
|
|
addr);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (autoassign && !dev->addr.ccw.assigned) {
|
2014-06-23 06:31:53 +00:00
|
|
|
|
if (!(addr = virDomainCCWAddressAsString(&addrs->next)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
|
|
|
|
|
while (virHashLookup(addrs->defined, addr)) {
|
|
|
|
|
if (virDomainCCWAddressIncrement(&addrs->next) < 0) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
|
_("There are no more free CCW devnos."));
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
}
|
|
|
|
|
VIR_FREE(addr);
|
2014-06-23 06:31:53 +00:00
|
|
|
|
if (!(addr = virDomainCCWAddressAsString(&addrs->next)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
}
|
|
|
|
|
dev->addr.ccw = addrs->next;
|
|
|
|
|
dev->addr.ccw.assigned = true;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (virHashAddEntry(addrs->defined, addr, addr) < 0)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
else
|
|
|
|
|
addr = NULL; /* memory will be freed by hash table */
|
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2014-06-17 14:17:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 20:19:49 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
2019-10-14 12:45:33 +00:00
|
|
|
|
virDomainCCWAddressAllocate(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
|
virDomainDeviceDefPtr dev G_GNUC_UNUSED,
|
2014-06-17 14:17:41 +00:00
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
return virDomainCCWAddressAssign(info, data, true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 20:19:49 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
2019-10-14 12:45:33 +00:00
|
|
|
|
virDomainCCWAddressValidate(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
|
virDomainDeviceDefPtr dev G_GNUC_UNUSED,
|
2014-06-17 14:17:41 +00:00
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
return virDomainCCWAddressAssign(info, data, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void virDomainCCWAddressSetFree(virDomainCCWAddressSetPtr addrs)
|
|
|
|
|
{
|
|
|
|
|
if (!addrs)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
virHashFree(addrs->defined);
|
|
|
|
|
VIR_FREE(addrs);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 20:19:49 +00:00
|
|
|
|
static virDomainCCWAddressSetPtr
|
2014-06-17 14:17:41 +00:00
|
|
|
|
virDomainCCWAddressSetCreate(void)
|
|
|
|
|
{
|
|
|
|
|
virDomainCCWAddressSetPtr addrs = NULL;
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
addrs = g_new0(virDomainCCWAddressSet, 1);
|
2014-06-17 14:17:41 +00:00
|
|
|
|
|
|
|
|
|
if (!(addrs->defined = virHashCreate(10, virHashValueFree)))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
/* must use cssid = 0xfe (254) for virtio-ccw devices */
|
|
|
|
|
addrs->next.cssid = 254;
|
|
|
|
|
addrs->next.ssid = 0;
|
|
|
|
|
addrs->next.devno = 0;
|
|
|
|
|
addrs->next.assigned = 0;
|
|
|
|
|
return addrs;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
virDomainCCWAddressSetFree(addrs);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2015-03-02 09:57:51 +00:00
|
|
|
|
|
|
|
|
|
|
2018-07-03 15:25:28 +00:00
|
|
|
|
virDomainCCWAddressSetPtr
|
|
|
|
|
virDomainCCWAddressSetCreateFromDomain(virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
virDomainCCWAddressSetPtr addrs = NULL;
|
|
|
|
|
|
|
|
|
|
if (!(addrs = virDomainCCWAddressSetCreate()))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
if (virDomainDeviceInfoIterate(def, virDomainCCWAddressValidate,
|
|
|
|
|
addrs) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
if (virDomainDeviceInfoIterate(def, virDomainCCWAddressAllocate,
|
|
|
|
|
addrs) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
return addrs;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
virDomainCCWAddressSetFree(addrs);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-03-02 09:57:51 +00:00
|
|
|
|
#define VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS 31
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* virDomainVirtioSerialAddrSetCreate
|
|
|
|
|
*
|
|
|
|
|
* Allocates an address set for virtio serial addresses
|
|
|
|
|
*/
|
2018-07-03 20:19:50 +00:00
|
|
|
|
static virDomainVirtioSerialAddrSetPtr
|
2015-03-02 09:57:51 +00:00
|
|
|
|
virDomainVirtioSerialAddrSetCreate(void)
|
|
|
|
|
{
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr ret = NULL;
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
ret = g_new0(virDomainVirtioSerialAddrSet, 1);
|
2015-03-02 09:57:51 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
virDomainVirtioSerialControllerFree(virDomainVirtioSerialControllerPtr cont)
|
|
|
|
|
{
|
|
|
|
|
if (cont) {
|
|
|
|
|
virBitmapFree(cont->ports);
|
|
|
|
|
VIR_FREE(cont);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
|
virDomainVirtioSerialAddrPlaceController(virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainVirtioSerialControllerPtr cont)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < addrs->ncontrollers; i++) {
|
|
|
|
|
if (addrs->controllers[i]->idx == cont->idx) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("virtio serial controller with index %u already exists"
|
|
|
|
|
" in the address set"),
|
|
|
|
|
cont->idx);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
if (addrs->controllers[i]->idx > cont->idx)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
|
virDomainVirtioSerialAddrFindController(virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
unsigned int idx)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < addrs->ncontrollers; i++) {
|
|
|
|
|
if (addrs->controllers[i]->idx == idx)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virDomainVirtioSerialAddrSetAddController
|
|
|
|
|
*
|
|
|
|
|
* Adds virtio serial ports of the existing controller
|
|
|
|
|
* to the address set.
|
|
|
|
|
*/
|
2015-08-12 14:52:12 +00:00
|
|
|
|
static int
|
2015-03-02 09:57:51 +00:00
|
|
|
|
virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainControllerDefPtr cont)
|
|
|
|
|
{
|
|
|
|
|
int ret = -1;
|
|
|
|
|
int ports;
|
|
|
|
|
virDomainVirtioSerialControllerPtr cnt = NULL;
|
|
|
|
|
ssize_t insertAt;
|
|
|
|
|
|
|
|
|
|
if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ports = cont->opts.vioserial.ports;
|
|
|
|
|
if (ports == -1)
|
|
|
|
|
ports = VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS;
|
|
|
|
|
|
|
|
|
|
VIR_DEBUG("Adding virtio serial controller index %u with %d"
|
|
|
|
|
" ports to the address set", cont->idx, ports);
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
cnt = g_new0(virDomainVirtioSerialController, 1);
|
2015-03-02 09:57:51 +00:00
|
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
|
cnt->ports = virBitmapNew(ports);
|
2015-03-02 09:57:51 +00:00
|
|
|
|
cnt->idx = cont->idx;
|
|
|
|
|
|
|
|
|
|
if ((insertAt = virDomainVirtioSerialAddrPlaceController(addrs, cnt)) < -1)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
if (VIR_INSERT_ELEMENT(addrs->controllers, insertAt,
|
|
|
|
|
addrs->ncontrollers, cnt) < 0)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
virDomainVirtioSerialControllerFree(cnt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virDomainVirtioSerialAddrSetAddControllers
|
|
|
|
|
*
|
|
|
|
|
* Adds virtio serial ports of controllers present in the domain definition
|
|
|
|
|
* to the address set.
|
|
|
|
|
*/
|
2018-07-03 20:19:50 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
2015-03-02 09:57:51 +00:00
|
|
|
|
virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
|
if (virDomainVirtioSerialAddrSetAddController(addrs,
|
|
|
|
|
def->controllers[i]) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
if (addrs) {
|
|
|
|
|
for (i = 0; i < addrs->ncontrollers; i++)
|
|
|
|
|
virDomainVirtioSerialControllerFree(addrs->controllers[i]);
|
2015-04-03 18:14:01 +00:00
|
|
|
|
VIR_FREE(addrs->controllers);
|
2015-03-02 09:57:51 +00:00
|
|
|
|
VIR_FREE(addrs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 20:19:50 +00:00
|
|
|
|
/* virDomainVirtioSerialAddrReserve
|
|
|
|
|
*
|
|
|
|
|
* Reserve the virtio serial address of the device
|
|
|
|
|
*
|
|
|
|
|
* For use with virDomainDeviceInfoIterate,
|
|
|
|
|
* opaque should be the address set
|
|
|
|
|
*/
|
|
|
|
|
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
2019-10-14 12:45:33 +00:00
|
|
|
|
virDomainVirtioSerialAddrReserve(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
|
virDomainDeviceDefPtr dev G_GNUC_UNUSED,
|
2018-07-03 20:19:50 +00:00
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs = data;
|
|
|
|
|
virBitmapPtr map = NULL;
|
|
|
|
|
bool b;
|
|
|
|
|
ssize_t i;
|
|
|
|
|
|
|
|
|
|
if (!virDomainVirtioSerialAddrIsComplete(info))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
VIR_DEBUG("Reserving virtio serial %u %u", info->addr.vioserial.controller,
|
|
|
|
|
info->addr.vioserial.port);
|
|
|
|
|
|
|
|
|
|
i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller);
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("virtio serial controller %u is missing"),
|
|
|
|
|
info->addr.vioserial.controller);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
map = addrs->controllers[i]->ports;
|
|
|
|
|
if (virBitmapGetBit(map, info->addr.vioserial.port, &b) < 0) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("virtio serial controller %u does not have port %u"),
|
|
|
|
|
info->addr.vioserial.controller,
|
|
|
|
|
info->addr.vioserial.port);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("virtio serial port %u on controller %u is already occupied"),
|
|
|
|
|
info->addr.vioserial.port,
|
|
|
|
|
info->addr.vioserial.controller);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ignore_value(virBitmapSetBit(map, info->addr.vioserial.port));
|
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
2016-07-23 01:47:06 +00:00
|
|
|
|
|
|
|
|
|
/* virDomainVirtioSerialAddrSetCreateFromDomain
|
2018-06-26 15:49:54 +00:00
|
|
|
|
*
|
|
|
|
|
* @def: Domain def to introspect
|
|
|
|
|
*
|
|
|
|
|
* Inspect the domain definition and return an address set containing
|
|
|
|
|
* every virtio serial address we find
|
|
|
|
|
*/
|
2016-07-23 01:47:06 +00:00
|
|
|
|
virDomainVirtioSerialAddrSetPtr
|
|
|
|
|
virDomainVirtioSerialAddrSetCreateFromDomain(virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs = NULL;
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr ret = NULL;
|
|
|
|
|
|
|
|
|
|
if (!(addrs = virDomainVirtioSerialAddrSetCreate()))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (virDomainVirtioSerialAddrSetAddControllers(addrs, def) < 0)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (virDomainDeviceInfoIterate(def, virDomainVirtioSerialAddrReserve,
|
|
|
|
|
addrs) < 0)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
2019-10-16 11:43:01 +00:00
|
|
|
|
ret = g_steal_pointer(&addrs);
|
2016-07-23 01:47:06 +00:00
|
|
|
|
cleanup:
|
|
|
|
|
virDomainVirtioSerialAddrSetFree(addrs);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 09:57:51 +00:00
|
|
|
|
static int
|
2015-03-24 14:23:46 +00:00
|
|
|
|
virDomainVirtioSerialAddrSetAutoaddController(virDomainDefPtr def,
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
unsigned int idx)
|
|
|
|
|
{
|
|
|
|
|
int contidx;
|
|
|
|
|
|
|
|
|
|
if (virDomainDefMaybeAddController(def,
|
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
|
|
|
|
|
idx, -1) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
contidx = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx);
|
|
|
|
|
|
|
|
|
|
if (virDomainVirtioSerialAddrSetAddController(addrs, def->controllers[contidx]) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainVirtioSerialAddrNext(virDomainDefPtr def,
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs,
|
2015-03-02 09:57:51 +00:00
|
|
|
|
virDomainDeviceVirtioSerialAddress *addr,
|
|
|
|
|
bool allowZero)
|
|
|
|
|
{
|
|
|
|
|
ssize_t port, startPort = 0;
|
|
|
|
|
ssize_t i;
|
|
|
|
|
unsigned int controller;
|
|
|
|
|
|
|
|
|
|
/* port number 0 is reserved for virtconsoles */
|
|
|
|
|
if (allowZero)
|
|
|
|
|
startPort = -1;
|
|
|
|
|
|
|
|
|
|
if (addrs->ncontrollers == 0) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
|
_("no virtio-serial controllers are available"));
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2015-03-02 09:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < addrs->ncontrollers; i++) {
|
|
|
|
|
virBitmapPtr map = addrs->controllers[i]->ports;
|
|
|
|
|
if ((port = virBitmapNextClearBit(map, startPort)) >= 0) {
|
|
|
|
|
controller = addrs->controllers[i]->idx;
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-24 14:23:46 +00:00
|
|
|
|
if (def) {
|
|
|
|
|
for (i = 0; i < INT_MAX; i++) {
|
|
|
|
|
int idx = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, i);
|
|
|
|
|
|
|
|
|
|
if (idx == -1) {
|
|
|
|
|
if (virDomainVirtioSerialAddrSetAutoaddController(def, addrs, i) < 0)
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2015-03-24 14:23:46 +00:00
|
|
|
|
controller = i;
|
|
|
|
|
port = startPort + 1;
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 09:57:51 +00:00
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
|
_("Unable to find a free virtio-serial port"));
|
|
|
|
|
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2015-03-02 09:57:51 +00:00
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
addr->bus = 0;
|
|
|
|
|
addr->port = port;
|
|
|
|
|
addr->controller = controller;
|
|
|
|
|
VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller,
|
|
|
|
|
addr->port);
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return 0;
|
2015-03-02 09:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainDeviceVirtioSerialAddress *addr)
|
|
|
|
|
{
|
|
|
|
|
ssize_t port;
|
|
|
|
|
ssize_t i;
|
|
|
|
|
virBitmapPtr map;
|
|
|
|
|
|
|
|
|
|
i = virDomainVirtioSerialAddrFindController(addrs, addr->controller);
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
|
_("virtio-serial controller %u not available"),
|
|
|
|
|
addr->controller);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
map = addrs->controllers[i]->ports;
|
|
|
|
|
if ((port = virBitmapNextClearBit(map, 0)) <= 0) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("Unable to find a free port on virtio-serial controller %u"),
|
|
|
|
|
addr->controller);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addr->bus = 0;
|
|
|
|
|
addr->port = port;
|
|
|
|
|
VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller,
|
|
|
|
|
addr->port);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 20:19:50 +00:00
|
|
|
|
static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
|
|
|
virDomainVirtioSerialAddrAssign(virDomainDefPtr def,
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
bool allowZero,
|
|
|
|
|
bool portOnly)
|
|
|
|
|
{
|
|
|
|
|
virDomainDeviceInfo nfo = { 0 };
|
|
|
|
|
virDomainDeviceInfoPtr ptr = allowZero ? &nfo : info;
|
|
|
|
|
|
|
|
|
|
ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
|
|
|
|
|
|
|
|
|
|
if (portOnly) {
|
|
|
|
|
if (virDomainVirtioSerialAddrNextFromController(addrs,
|
|
|
|
|
&ptr->addr.vioserial) < 0)
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (virDomainVirtioSerialAddrNext(def, addrs, &ptr->addr.vioserial,
|
|
|
|
|
allowZero) < 0)
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (virDomainVirtioSerialAddrReserve(NULL, NULL, ptr, addrs) < 0)
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return -1;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
|
2019-10-21 18:18:51 +00:00
|
|
|
|
return 0;
|
2018-07-03 20:19:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 09:57:51 +00:00
|
|
|
|
/* virDomainVirtioSerialAddrAutoAssign
|
|
|
|
|
*
|
|
|
|
|
* reserve a virtio serial address of the device (if it has one)
|
|
|
|
|
* or assign a virtio serial address to the device
|
|
|
|
|
*/
|
|
|
|
|
int
|
2016-10-21 10:58:54 +00:00
|
|
|
|
virDomainVirtioSerialAddrAutoAssignFromCache(virDomainDefPtr def,
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
bool allowZero)
|
2015-03-02 09:57:51 +00:00
|
|
|
|
{
|
|
|
|
|
bool portOnly = info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
|
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
|
|
|
|
|
info->addr.vioserial.port)
|
|
|
|
|
return virDomainVirtioSerialAddrReserve(NULL, NULL, info, addrs);
|
|
|
|
|
else
|
2015-03-24 14:23:46 +00:00
|
|
|
|
return virDomainVirtioSerialAddrAssign(def, addrs, info, allowZero, portOnly);
|
2015-03-02 09:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 11:09:36 +00:00
|
|
|
|
int
|
|
|
|
|
virDomainVirtioSerialAddrAutoAssign(virDomainDefPtr def,
|
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
bool allowZero)
|
|
|
|
|
{
|
|
|
|
|
virDomainVirtioSerialAddrSetPtr addrs = NULL;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
if (!(addrs = virDomainVirtioSerialAddrSetCreateFromDomain(def)))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (virDomainVirtioSerialAddrAutoAssignFromCache(def, addrs, info, allowZero) < 0)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
virDomainVirtioSerialAddrSetFree(addrs);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 09:57:51 +00:00
|
|
|
|
|
|
|
|
|
/* virDomainVirtioSerialAddrIsComplete
|
|
|
|
|
*
|
|
|
|
|
* Check if the address is complete, or it needs auto-assignment
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info)
|
|
|
|
|
{
|
|
|
|
|
return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
|
|
|
|
|
info->addr.vioserial.port != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-12 14:52:13 +00:00
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
virDomainUSBAddressPortIsValid(unsigned int *port)
|
|
|
|
|
{
|
|
|
|
|
return port[0] != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
virDomainUSBAddressPortFormatBuf(virBufferPtr buf,
|
|
|
|
|
unsigned int *port)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_DOMAIN_DEVICE_USB_MAX_PORT_DEPTH; i++) {
|
|
|
|
|
if (port[i] == 0)
|
|
|
|
|
break;
|
|
|
|
|
virBufferAsprintf(buf, "%u.", port[i]);
|
|
|
|
|
}
|
2020-02-02 19:26:38 +00:00
|
|
|
|
virBufferTrim(buf, ".");
|
2015-08-12 14:52:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-07-03 20:19:51 +00:00
|
|
|
|
static char * ATTRIBUTE_NONNULL(1)
|
2015-08-12 14:52:13 +00:00
|
|
|
|
virDomainUSBAddressPortFormat(unsigned int *port)
|
|
|
|
|
{
|
2020-07-03 02:19:01 +00:00
|
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2015-08-12 14:52:13 +00:00
|
|
|
|
virDomainUSBAddressPortFormatBuf(&buf, port);
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
}
|
2015-08-12 14:52:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
virDomainUSBAddressSetPtr
|
|
|
|
|
virDomainUSBAddressSetCreate(void)
|
|
|
|
|
{
|
|
|
|
|
virDomainUSBAddressSetPtr addrs;
|
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
addrs = g_new0(virDomainUSBAddressSet, 1);
|
2015-08-12 14:52:15 +00:00
|
|
|
|
|
|
|
|
|
return addrs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
virDomainUSBAddressHubFree(virDomainUSBAddressHubPtr hub)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
if (!hub)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < hub->nports; i++)
|
|
|
|
|
virDomainUSBAddressHubFree(hub->ports[i]);
|
2016-08-15 15:21:32 +00:00
|
|
|
|
VIR_FREE(hub->ports);
|
2015-08-12 14:52:15 +00:00
|
|
|
|
virBitmapFree(hub->portmap);
|
|
|
|
|
VIR_FREE(hub);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
if (!addrs)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < addrs->nbuses; i++)
|
|
|
|
|
virDomainUSBAddressHubFree(addrs->buses[i]);
|
|
|
|
|
VIR_FREE(addrs->buses);
|
|
|
|
|
VIR_FREE(addrs);
|
|
|
|
|
}
|
2015-08-12 14:52:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
|
virDomainUSBAddressControllerModelToPorts(virDomainControllerDefPtr cont)
|
|
|
|
|
{
|
2018-02-14 10:51:26 +00:00
|
|
|
|
switch ((virDomainControllerModelUSB) cont->model) {
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT:
|
2015-08-12 14:52:16 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
|
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
|
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
|
|
|
|
|
/* These have two ports each and are used to provide USB1.1
|
|
|
|
|
* ports while ICH9_EHCI1 provides 6 USB2.0 ports.
|
|
|
|
|
* Ignore these since we will add the EHCI1 too. */
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
|
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI:
|
2017-04-13 10:25:25 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI:
|
2015-08-12 14:52:16 +00:00
|
|
|
|
if (cont->opts.usbopts.ports != -1)
|
|
|
|
|
return cont->opts.usbopts.ports;
|
|
|
|
|
return 4;
|
|
|
|
|
|
2016-06-15 06:00:08 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2:
|
|
|
|
|
if (cont->opts.usbopts.ports != -1)
|
|
|
|
|
return cont->opts.usbopts.ports;
|
|
|
|
|
return 8;
|
|
|
|
|
|
2015-08-12 14:52:16 +00:00
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE:
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainUSBAddressHubPtr
|
|
|
|
|
virDomainUSBAddressHubNew(size_t nports)
|
|
|
|
|
{
|
2020-10-06 14:42:51 +00:00
|
|
|
|
virDomainUSBAddressHubPtr hub;
|
2015-08-12 14:52:16 +00:00
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
hub = g_new0(virDomainUSBAddressHub, 1);
|
2015-08-12 14:52:16 +00:00
|
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
|
hub->portmap = virBitmapNew(nports);
|
2015-08-12 14:52:16 +00:00
|
|
|
|
|
2020-10-07 19:13:27 +00:00
|
|
|
|
hub->ports = g_new0(virDomainUSBAddressHubPtr, nports);
|
2015-08-12 14:52:16 +00:00
|
|
|
|
hub->nports = nports;
|
|
|
|
|
|
2020-10-06 14:42:51 +00:00
|
|
|
|
return hub;
|
2015-08-12 14:52:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
virDomainUSBAddressSetAddController(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainControllerDefPtr cont)
|
|
|
|
|
{
|
|
|
|
|
size_t nports = virDomainUSBAddressControllerModelToPorts(cont);
|
|
|
|
|
virDomainUSBAddressHubPtr hub = NULL;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
VIR_DEBUG("Adding a USB controller model=%s with %zu ports",
|
|
|
|
|
virDomainControllerModelUSBTypeToString(cont->model),
|
|
|
|
|
nports);
|
|
|
|
|
|
|
|
|
|
/* Skip UHCI{1,2,3} companions; only add the EHCI1 */
|
|
|
|
|
if (nports == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (addrs->nbuses <= cont->idx) {
|
|
|
|
|
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, cont->idx - addrs->nbuses + 1) < 0)
|
|
|
|
|
goto cleanup;
|
|
|
|
|
} else if (addrs->buses[cont->idx]) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("Duplicate USB controllers with index %u"),
|
|
|
|
|
cont->idx);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(hub = virDomainUSBAddressHubNew(nports)))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
addrs->buses[cont->idx] = hub;
|
|
|
|
|
hub = NULL;
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
cleanup:
|
|
|
|
|
virDomainUSBAddressHubFree(hub);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-27 13:54:14 +00:00
|
|
|
|
static ssize_t
|
|
|
|
|
virDomainUSBAddressGetLastIdx(virDomainDeviceInfoPtr info)
|
|
|
|
|
{
|
|
|
|
|
ssize_t i;
|
|
|
|
|
for (i = VIR_DOMAIN_DEVICE_USB_MAX_PORT_DEPTH - 1; i > 0; i--) {
|
|
|
|
|
if (info->addr.usb.port[i] != 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find the USBAddressHub structure representing the hub/controller
|
|
|
|
|
* that corresponds to the bus/port path specified by info.
|
|
|
|
|
* Returns the index of the requested port in targetIdx.
|
|
|
|
|
*/
|
|
|
|
|
static virDomainUSBAddressHubPtr
|
|
|
|
|
virDomainUSBAddressFindPort(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
int *targetIdx,
|
|
|
|
|
const char *portStr)
|
|
|
|
|
{
|
|
|
|
|
virDomainUSBAddressHubPtr hub = NULL;
|
2017-01-30 14:56:10 +00:00
|
|
|
|
ssize_t i, lastIdx, targetPort;
|
2016-04-27 13:54:14 +00:00
|
|
|
|
|
|
|
|
|
if (info->addr.usb.bus >= addrs->nbuses ||
|
|
|
|
|
!addrs->buses[info->addr.usb.bus]) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, _("Missing USB bus %u"),
|
|
|
|
|
info->addr.usb.bus);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
hub = addrs->buses[info->addr.usb.bus];
|
|
|
|
|
|
|
|
|
|
lastIdx = virDomainUSBAddressGetLastIdx(info);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < lastIdx; i++) {
|
|
|
|
|
/* ports are numbered from 1 */
|
|
|
|
|
int portIdx = info->addr.usb.port[i] - 1;
|
|
|
|
|
|
|
|
|
|
if (hub->nports <= portIdx) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("port %u out of range in USB address bus: %u port: %s"),
|
|
|
|
|
info->addr.usb.port[i],
|
|
|
|
|
info->addr.usb.bus,
|
|
|
|
|
portStr);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
hub = hub->ports[portIdx];
|
2016-08-15 15:39:35 +00:00
|
|
|
|
if (!hub) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("there is no hub at port %u in USB address bus: %u port: %s"),
|
|
|
|
|
info->addr.usb.port[i],
|
|
|
|
|
info->addr.usb.bus,
|
|
|
|
|
portStr);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-04-27 13:54:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-30 14:56:10 +00:00
|
|
|
|
targetPort = info->addr.usb.port[lastIdx] - 1;
|
|
|
|
|
if (targetPort >= virBitmapSize(hub->portmap)) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("requested USB port %s not present on USB bus %u"),
|
|
|
|
|
portStr, info->addr.usb.bus);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*targetIdx = targetPort;
|
2016-04-27 13:54:14 +00:00
|
|
|
|
return hub;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-08-12 14:52:18 +00:00
|
|
|
|
int
|
2016-04-27 13:54:14 +00:00
|
|
|
|
virDomainUSBAddressSetAddHub(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainHubDefPtr hub)
|
|
|
|
|
{
|
|
|
|
|
virDomainUSBAddressHubPtr targetHub = NULL, newHub = NULL;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
int targetPort;
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *portStr = NULL;
|
2016-04-27 13:54:14 +00:00
|
|
|
|
|
|
|
|
|
if (hub->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
|
_("Wrong address type for USB hub"));
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(portStr = virDomainUSBAddressPortFormat(hub->info.addr.usb.port)))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
VIR_DEBUG("Adding a USB hub with 8 ports on bus=%u port=%s",
|
|
|
|
|
hub->info.addr.usb.bus, portStr);
|
|
|
|
|
|
|
|
|
|
if (!(newHub = virDomainUSBAddressHubNew(VIR_DOMAIN_USB_HUB_PORTS)))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (!(targetHub = virDomainUSBAddressFindPort(addrs, &(hub->info), &targetPort,
|
|
|
|
|
portStr)))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
if (targetHub->ports[targetPort]) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("Duplicate USB hub on bus %u port %s"),
|
|
|
|
|
hub->info.addr.usb.bus, portStr);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
ignore_value(virBitmapSetBit(targetHub->portmap, targetPort));
|
|
|
|
|
targetHub->ports[targetPort] = newHub;
|
|
|
|
|
newHub = NULL;
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
cleanup:
|
|
|
|
|
virDomainUSBAddressHubFree(newHub);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-08-12 14:52:16 +00:00
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
|
|
|
|
|
if (virDomainUSBAddressSetAddController(addrs, cont) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-27 13:54:14 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < def->nhubs; i++) {
|
|
|
|
|
virDomainHubDefPtr hub = def->hubs[i];
|
|
|
|
|
if (hub->type == VIR_DOMAIN_HUB_TYPE_USB &&
|
|
|
|
|
hub->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB &&
|
|
|
|
|
virDomainUSBAddressPortIsValid(hub->info.addr.usb.port)) {
|
|
|
|
|
/* USB hubs that do not yet have an USB address have to be
|
|
|
|
|
* dealt with later */
|
|
|
|
|
if (virDomainUSBAddressSetAddHub(addrs, hub) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-12 14:52:16 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-08-12 14:52:17 +00:00
|
|
|
|
|
|
|
|
|
|
2015-08-12 14:52:18 +00:00
|
|
|
|
static int
|
|
|
|
|
virDomainUSBAddressFindFreePort(virDomainUSBAddressHubPtr hub,
|
|
|
|
|
unsigned int *portpath,
|
|
|
|
|
unsigned int level)
|
|
|
|
|
{
|
|
|
|
|
unsigned int port;
|
|
|
|
|
ssize_t portIdx;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
/* Look for free ports on the current hub */
|
|
|
|
|
if ((portIdx = virBitmapNextClearBit(hub->portmap, -1)) >= 0) {
|
|
|
|
|
port = portIdx + 1;
|
|
|
|
|
VIR_DEBUG("Found a free port %u at level %u", port, level);
|
|
|
|
|
portpath[level] = port;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VIR_DEBUG("No ports found on hub %p, trying the hubs on it", hub);
|
|
|
|
|
|
|
|
|
|
if (level >= VIR_DOMAIN_DEVICE_USB_MAX_PORT_DEPTH - 1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* Recursively search through the ports that contain another hub */
|
|
|
|
|
for (i = 0; i < hub->nports; i++) {
|
|
|
|
|
if (!hub->ports[i])
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
port = i + 1;
|
|
|
|
|
VIR_DEBUG("Looking at USB hub at level: %u port: %u", level, port);
|
|
|
|
|
if (virDomainUSBAddressFindFreePort(hub->ports[i], portpath,
|
|
|
|
|
level + 1) < 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
portpath[level] = port;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-17 07:49:54 +00:00
|
|
|
|
size_t
|
|
|
|
|
virDomainUSBAddressCountAllPorts(virDomainDefPtr def)
|
|
|
|
|
{
|
|
|
|
|
size_t i, ret = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
|
|
|
|
|
ret += virDomainUSBAddressControllerModelToPorts(cont);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < def->nhubs; i++) {
|
|
|
|
|
virDomainHubDefPtr hub = def->hubs[i];
|
|
|
|
|
if (hub->type == VIR_DOMAIN_HUB_TYPE_USB)
|
|
|
|
|
ret += VIR_DOMAIN_USB_HUB_PORTS;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-08-12 14:52:18 +00:00
|
|
|
|
/* Try to find a free port on bus @bus.
|
|
|
|
|
*
|
|
|
|
|
* Returns 0 on success
|
|
|
|
|
* -1 on fatal error (OOM)
|
|
|
|
|
* -2 if there is no bus at @bus or no free port on this bus
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
virDomainUSBAddressAssignFromBus(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
|
size_t bus)
|
|
|
|
|
{
|
|
|
|
|
unsigned int portpath[VIR_DOMAIN_DEVICE_USB_MAX_PORT_DEPTH] = { 0 };
|
|
|
|
|
virDomainUSBAddressHubPtr hub = addrs->buses[bus];
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *portStr = NULL;
|
2015-08-12 14:52:18 +00:00
|
|
|
|
|
|
|
|
|
if (!hub)
|
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
|
|
if (virDomainUSBAddressFindFreePort(hub, portpath, 0) < 0)
|
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
|
|
/* we found a free port */
|
|
|
|
|
if (!(portStr = virDomainUSBAddressPortFormat(portpath)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:18 +00:00
|
|
|
|
|
|
|
|
|
info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB;
|
|
|
|
|
info->addr.usb.bus = bus;
|
|
|
|
|
memcpy(info->addr.usb.port, portpath, sizeof(portpath));
|
|
|
|
|
VIR_DEBUG("Assigning USB addr bus=%u port=%s",
|
|
|
|
|
info->addr.usb.bus, portStr);
|
|
|
|
|
if (virDomainUSBAddressReserve(info, addrs) < 0)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:18 +00:00
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2015-08-12 14:52:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressAssign(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
|
|
|
|
VIR_DEBUG("A USB port on bus %u was requested", info->addr.usb.bus);
|
2017-04-12 10:40:57 +00:00
|
|
|
|
if (info->addr.usb.bus >= addrs->nbuses ||
|
|
|
|
|
!addrs->buses[info->addr.usb.bus]) {
|
2015-08-12 14:52:18 +00:00
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("USB bus %u requested but no controller "
|
|
|
|
|
"with that index is present"), info->addr.usb.bus);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
rc = virDomainUSBAddressAssignFromBus(addrs, info, info->addr.usb.bus);
|
|
|
|
|
if (rc >= -1)
|
|
|
|
|
return rc;
|
|
|
|
|
} else {
|
|
|
|
|
VIR_DEBUG("Looking for a free USB port on all the buses");
|
|
|
|
|
for (i = 0; i < addrs->nbuses; i++) {
|
|
|
|
|
rc = virDomainUSBAddressAssignFromBus(addrs, info, i);
|
|
|
|
|
if (rc >= -1)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No free USB ports"));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-21 11:09:04 +00:00
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressPresent(virDomainDeviceInfoPtr info,
|
2019-10-14 12:45:33 +00:00
|
|
|
|
void *data G_GNUC_UNUSED)
|
2016-10-21 11:09:04 +00:00
|
|
|
|
{
|
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB &&
|
|
|
|
|
virDomainUSBAddressPortIsValid(info->addr.usb.port))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-08-12 14:52:17 +00:00
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressReserve(virDomainDeviceInfoPtr info,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
virDomainUSBAddressSetPtr addrs = data;
|
|
|
|
|
virDomainUSBAddressHubPtr targetHub = NULL;
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *portStr = NULL;
|
2015-08-12 14:52:17 +00:00
|
|
|
|
int targetPort;
|
|
|
|
|
|
|
|
|
|
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!virDomainUSBAddressPortIsValid(info->addr.usb.port))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
portStr = virDomainUSBAddressPortFormat(info->addr.usb.port);
|
|
|
|
|
if (!portStr)
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:17 +00:00
|
|
|
|
VIR_DEBUG("Reserving USB address bus=%u port=%s", info->addr.usb.bus, portStr);
|
|
|
|
|
|
|
|
|
|
if (!(targetHub = virDomainUSBAddressFindPort(addrs, info, &targetPort,
|
|
|
|
|
portStr)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:17 +00:00
|
|
|
|
|
|
|
|
|
if (virBitmapIsBitSet(targetHub->portmap, targetPort)) {
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
|
_("Duplicate USB address bus %u port %s"),
|
|
|
|
|
info->addr.usb.bus, portStr);
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ignore_value(virBitmapSetBit(targetHub->portmap, targetPort));
|
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2015-08-12 14:52:17 +00:00
|
|
|
|
}
|
2015-08-12 14:52:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressEnsure(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info)
|
|
|
|
|
{
|
2017-10-20 11:28:21 +00:00
|
|
|
|
if (!addrs)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-08-12 14:52:18 +00:00
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
|
|
|
|
|
(info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB &&
|
|
|
|
|
!virDomainUSBAddressPortIsValid(info->addr.usb.port))) {
|
|
|
|
|
if (virDomainUSBAddressAssign(addrs, info) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
|
|
|
|
if (virDomainUSBAddressReserve(info, addrs) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-08-12 14:52:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
virDomainUSBAddressRelease(virDomainUSBAddressSetPtr addrs,
|
|
|
|
|
virDomainDeviceInfoPtr info)
|
|
|
|
|
{
|
|
|
|
|
virDomainUSBAddressHubPtr targetHub = NULL;
|
2020-01-09 18:33:41 +00:00
|
|
|
|
g_autofree char *portStr = NULL;
|
2015-08-12 14:52:19 +00:00
|
|
|
|
int targetPort;
|
|
|
|
|
|
2017-10-20 11:24:49 +00:00
|
|
|
|
if (!addrs || info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB ||
|
2015-08-12 14:52:19 +00:00
|
|
|
|
!virDomainUSBAddressPortIsValid(info->addr.usb.port))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
portStr = virDomainUSBAddressPortFormat(info->addr.usb.port);
|
|
|
|
|
VIR_DEBUG("Releasing USB addr bus=%u port=%s", info->addr.usb.bus, portStr);
|
|
|
|
|
|
|
|
|
|
if (!(targetHub = virDomainUSBAddressFindPort(addrs, info, &targetPort,
|
|
|
|
|
portStr)))
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return -1;
|
2015-08-12 14:52:19 +00:00
|
|
|
|
|
|
|
|
|
ignore_value(virBitmapClearBit(targetHub->portmap, targetPort));
|
|
|
|
|
|
2020-01-09 18:33:42 +00:00
|
|
|
|
return 0;
|
2015-08-12 14:52:19 +00:00
|
|
|
|
}
|