xf86: allow DDX driver for GPU/PCI hot-plug

The current X server infrastructure sets modesetting driver as default driver
to handle PCI-hotplug of a GPU device. This prevents the respective DDX driver
(like AMDGPU DDX driver) to take control of the card.

This patch:
- Adds a few functions and fine-tunes the GPU hotplug infrastructure to allow
  the DDX driver to be loaded, if it is configured in the X config file
  options as "hotplug-driver".
- Scans and updates the PCI device list before adding the new GPU device
  in platform, so that the association of the platform device and PCI device
  is in place (dev->pdev).
- Adds documentation of this new option

An example usage in the config file would look like:

Section "OutputClass"
        Identifier "AMDgpu"
        MatchDriver "amdgpu"
        Driver "amdgpu"
	HotplugDriver "amdgpu"
EndSection

V2:
Fixed typo in commit message (Martin)
Added R-B from Adam.
Added ACK from Alex and Martin.

V3:
Added an output class based approach for finding the DDX driver (Aaron)
Rebase

V4:
Addressed review comment from Aaron:
GPU hot-plug handling driver's name to be read from the DDX config file options.
In this way only the DDX drivers interested in handling GPU hot-plug will be
picked and loaded, for others modesetting driver will be used as usual.

V5:
Addressed review comments from Aaron:
- X config option to be listed in CamelCase.
- Indentation fix at one place.
- Code readability related optimization.

V6:
Addressed review comments from Aaron:
- Squash the doc in the same patch
- Doc formatting changes

Cc: Alex Deucher <alexander.deucher@amd.com>
Suggested-by: Aaron Plattner aplattner@nvidia.com (v3)
Acked-by: Martin Roukala martin.roukala@mupuf.org(v1)
Acked-by: Alex Deucher alexander.deucher@amd.com (v1)
Reviewed-by: Adam Jackson ajax@redhat.com(v1)
Signed-off-by: Shashank Sharma shashank.sharma@amd.com
This commit is contained in:
Shashank Sharma 2022-08-16 13:39:59 +02:00 committed by Shashank Sharma
parent 8c54d590cb
commit 82bf391c93
4 changed files with 74 additions and 10 deletions

View File

@ -272,6 +272,22 @@ xf86PlatformMatchDriver(XF86MatchedDrivers *md)
}
}
void xf86PlatformScanPciDev(void)
{
int i;
if (!xf86scanpci())
return;
xf86Msg(X_CONFIG, "Scanning the platform PCI devices\n");
for (i = 0; i < xf86_num_platform_devices; i++) {
char *busid = xf86_platform_odev_attributes(i)->busid;
if (strncmp(busid, "pci:", 4) == 0)
platform_find_pci_info(&xf86_platform_devices[i], busid);
}
}
int
xf86platformProbe(void)
{
@ -613,31 +629,58 @@ xf86platformAddGPUDevices(DriverPtr drvp)
return foundScreen;
}
const char *
xf86PlatformFindHotplugDriver(int dev_index)
{
XF86ConfOutputClassPtr cl;
const char *hp_driver = NULL;
struct xf86_platform_device *dev = &xf86_platform_devices[dev_index];
for (cl = xf86configptr->conf_outputclass_lst; cl; cl = cl->list.next) {
if (!OutputClassMatches(cl, dev) || !cl->option_lst)
continue;
hp_driver = xf86FindOptionValue(cl->option_lst, "HotplugDriver");
if (hp_driver)
xf86MarkOptionUsed(cl->option_lst);
}
/* Return the first driver from the match list */
xf86Msg(X_INFO, "matching hotplug-driver is %s\n",
hp_driver ? hp_driver : "none");
return hp_driver;
}
int
xf86platformAddDevice(int index)
xf86platformAddDevice(const char *driver_name, int index)
{
int i, old_screens, scr_index, scrnum;
DriverPtr drvp = NULL;
screenLayoutPtr layout;
static const char *hotplug_driver_name = "modesetting";
if (!xf86Info.autoAddGPU)
return -1;
/* force load the driver for now */
xf86LoadOneModule(hotplug_driver_name, NULL);
/* Load modesetting driver if no driver given, or driver open failed */
if (!driver_name || !xf86LoadOneModule(driver_name, NULL)) {
driver_name = "modesetting";
xf86LoadOneModule(driver_name, NULL);
}
for (i = 0; i < xf86NumDrivers; i++) {
if (!xf86DriverList[i])
continue;
if (!strcmp(xf86DriverList[i]->driverName, hotplug_driver_name)) {
if (!strcmp(xf86DriverList[i]->driverName, driver_name)) {
drvp = xf86DriverList[i];
break;
}
}
if (i == xf86NumDrivers)
if (i == xf86NumDrivers) {
ErrorF("can't find driver %s for hotplugged device\n", driver_name);
return -1;
}
old_screens = xf86NumGPUScreens;
doPlatformProbe(&xf86_platform_devices[index], drvp, NULL,

View File

@ -44,6 +44,8 @@ int xf86platformProbe(void);
int xf86platformProbeDev(DriverPtr drvp);
int xf86platformAddGPUDevices(DriverPtr drvp);
void xf86MergeOutputClassOptions(int entityIndex, void **options);
void xf86PlatformScanPciDev(void);
const char *xf86PlatformFindHotplugDriver(int dev_index);
extern int xf86_num_platform_devices;
extern struct xf86_platform_device *xf86_platform_devices;
@ -56,7 +58,7 @@ extern Bool
xf86_get_platform_device_unowned(int index);
extern int
xf86platformAddDevice(int index);
xf86platformAddDevice(const char *driver_name, int index);
extern void
xf86platformRemoveDevice(int index);

View File

@ -1296,7 +1296,20 @@ This option specifies that the matched device should be treated as the
primary GPU, replacing the selection of the GPU used as output by the
firmware. If multiple output devices match an OutputClass section with
the PrimaryGPU option set, the first one enumerated becomes the primary GPU.
.PP
.TP 7
.BI "Option \*qHotplugDriver\*q \*q" driver \*q
This option specifies that the matched driver should be used to handle a
hot-plugged GPU device.
The module specified by
.I driver
will be loaded during setup of the GPU device.
If loading of this module fails or there is no driver by that name, the
modesetting driver will be used, which is the default behavior.
If multiple output devices match an
.B OutputClass
section with the
.B HotplugDriver
option, the first one enumerated becomes the hotplug driver.
A
.B OutputClass
Section may contain

View File

@ -125,7 +125,7 @@ xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs)
xf86_remove_platform_device(index);
return;
}
ret = xf86platformAddDevice(index);
ret = xf86platformAddDevice(xf86PlatformFindHotplugDriver(index), index);
if (ret == -1)
xf86_remove_platform_device(index);
}
@ -173,6 +173,8 @@ void NewGPUDeviceRequest(struct OdevAttributes *attribs)
{
int old_num = xf86_num_platform_devices;
int ret;
const char *driver_name;
xf86PlatformDeviceProbe(attribs);
if (old_num == xf86_num_platform_devices)
@ -181,7 +183,11 @@ void NewGPUDeviceRequest(struct OdevAttributes *attribs)
if (xf86_get_platform_device_unowned(xf86_num_platform_devices - 1) == TRUE)
return;
ret = xf86platformAddDevice(xf86_num_platform_devices-1);
/* Scan and update PCI devices before adding new platform device */
xf86PlatformScanPciDev();
driver_name = xf86PlatformFindHotplugDriver(xf86_num_platform_devices - 1);
ret = xf86platformAddDevice(driver_name, xf86_num_platform_devices-1);
if (ret == -1)
xf86_remove_platform_device(xf86_num_platform_devices-1);