xserver-multidpi/hw/xfree86/common/xf86Bus.c
Zoltán Böszörményi f08bc32f5a xf86: Assign GPUs to screens according to configuration
If there is an explicit configuration, assign the RandR provider
of the GPUDevice to the screen it was specified for.

If there is no configuration (default case) the screen number is
still 0 so it doesn't change behaviour.

The result is e.g:

  # DISPLAY=:0.2 xrandr --listproviders
  Providers: number : 2
  Provider 0: id: 0xd2 cap: 0x2, Sink Output crtcs: 1 outputs: 1 associated providers: 0 name:modesetting
  Provider 1: id: 0xfd cap: 0xb, Source Output, Sink Output, Sink Offload crtcs: 2 outputs: 2 associated providers: 0 name:Intel

Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2021-07-30 00:27:39 +00:00

672 lines
18 KiB
C

/*
* Copyright (c) 1997-2003 by The XFree86 Project, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
/*
* This file contains the interfaces to the bus-specific code
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/X.h>
#include "os.h"
#include "xf86.h"
#include "xf86Priv.h"
/* Bus-specific headers */
#include "xf86Bus.h"
#define XF86_OS_PRIVS
#include "xf86_OSproc.h"
#ifdef XSERVER_LIBPCIACCESS
#include "xf86VGAarbiter.h"
#endif
/* Entity data */
EntityPtr *xf86Entities = NULL; /* Bus slots claimed by drivers */
int xf86NumEntities = 0;
static int xf86EntityPrivateCount = 0;
BusRec primaryBus = { BUS_NONE, {0} };
/**
* Call the driver's correct probe function.
*
* If the driver implements the \c DriverRec::PciProbe entry-point and an
* appropriate PCI device (with matching Device section in the xorg.conf file)
* is found, it is called. If \c DriverRec::PciProbe or no devices can be
* successfully probed with it (e.g., only non-PCI devices are available),
* the driver's \c DriverRec::Probe function is called.
*
* \param drv Driver to probe
*
* \return
* If a device can be successfully probed by the driver, \c TRUE is
* returned. Otherwise, \c FALSE is returned.
*/
Bool
xf86CallDriverProbe(DriverPtr drv, Bool detect_only)
{
Bool foundScreen = FALSE;
#ifdef XSERVER_PLATFORM_BUS
/* xf86platformBus.c does not support Xorg -configure */
if (!xf86DoConfigure && drv->platformProbe != NULL) {
foundScreen = xf86platformProbeDev(drv);
}
#endif
#ifdef XSERVER_LIBPCIACCESS
if (!foundScreen && (drv->PciProbe != NULL)) {
if (xf86DoConfigure && xf86DoConfigurePass1) {
assert(detect_only);
foundScreen = xf86PciAddMatchingDev(drv);
}
else {
assert(!detect_only);
foundScreen = xf86PciProbeDev(drv);
}
}
#endif
if (!foundScreen && (drv->Probe != NULL)) {
xf86Msg(X_WARNING, "Falling back to old probe method for %s\n",
drv->driverName);
foundScreen = (*drv->Probe) (drv, (detect_only) ? PROBE_DETECT
: PROBE_DEFAULT);
}
return foundScreen;
}
static screenLayoutPtr
xf86BusConfigMatch(ScrnInfoPtr scrnInfo, Bool is_gpu) {
screenLayoutPtr layout;
int i, j;
for (layout = xf86ConfigLayout.screens; layout->screen != NULL;
layout++) {
for (i = 0; i < scrnInfo->numEntities; i++) {
GDevPtr dev =
xf86GetDevFromEntity(scrnInfo->entityList[i],
scrnInfo->entityInstanceList[i]);
if (is_gpu) {
for (j = 0; j < layout->screen->num_gpu_devices; j++) {
if (dev == layout->screen->gpu_devices[j]) {
/* A match has been found */
return layout;
}
}
} else {
if (dev == layout->screen->device) {
/* A match has been found */
return layout;
}
}
}
}
return NULL;
}
/**
* @return TRUE if all buses are configured and set up correctly and FALSE
* otherwise.
*/
Bool
xf86BusConfig(void)
{
screenLayoutPtr layout;
int i;
/*
* 3 step probe to (hopefully) ensure that we always find at least 1
* (non GPU) screen:
*
* 1. Call each drivers probe function normally,
* Each successful probe will result in an extra entry added to the
* xf86Screens[] list for each instance of the hardware found.
*/
for (i = 0; i < xf86NumDrivers; i++) {
xf86CallDriverProbe(xf86DriverList[i], FALSE);
}
/*
* 2. If no Screens were found, call each drivers probe function with
* ignorePrimary = TRUE, to ensure that we do actually get a
* Screen if there is at least one supported video card.
*/
if (xf86NumScreens == 0) {
xf86ProbeIgnorePrimary = TRUE;
for (i = 0; i < xf86NumDrivers && xf86NumScreens == 0; i++) {
xf86CallDriverProbe(xf86DriverList[i], FALSE);
}
xf86ProbeIgnorePrimary = FALSE;
}
/*
* 3. Call xf86platformAddGPUDevices() to add any additional video cards as
* GPUScreens (GPUScreens are only supported by platformBus drivers).
*/
for (i = 0; i < xf86NumDrivers; i++) {
xf86platformAddGPUDevices(xf86DriverList[i]);
}
/* If nothing was detected, return now */
if (xf86NumScreens == 0) {
xf86Msg(X_ERROR, "No devices detected.\n");
return FALSE;
}
xf86VGAarbiterInit();
/*
* Match up the screens found by the probes against those specified
* in the config file. Remove the ones that won't be used. Sort
* them in the order specified.
*
* What is the best way to do this?
*
* For now, go through the screens allocated by the probes, and
* look for screen config entry which refers to the same device
* section as picked out by the probe.
*
*/
for (i = 0; i < xf86NumScreens; i++) {
layout = xf86BusConfigMatch(xf86Screens[i], FALSE);
if (layout && layout->screen)
xf86Screens[i]->confScreen = layout->screen;
else {
/* No match found */
xf86Msg(X_ERROR,
"Screen %d deleted because of no matching config section.\n",
i);
xf86DeleteScreen(xf86Screens[i--]);
}
}
/* bind GPU conf screen to the configured protocol screen, or 0 if not configured */
for (i = 0; i < xf86NumGPUScreens; i++) {
layout = xf86BusConfigMatch(xf86GPUScreens[i], TRUE);
int scrnum = (layout && layout->screen) ? layout->screen->screennum : 0;
xf86GPUScreens[i]->confScreen = xf86Screens[scrnum]->confScreen;
}
/* If no screens left, return now. */
if (xf86NumScreens == 0) {
xf86Msg(X_ERROR,
"Device(s) detected, but none match those in the config file.\n");
return FALSE;
}
return TRUE;
}
/*
* Call the bus probes relevant to the architecture.
*
* The only one available so far is for PCI and SBUS.
*/
void
xf86BusProbe(void)
{
#ifdef XSERVER_PLATFORM_BUS
xf86platformProbe();
if (ServerIsNotSeat0() && xf86_num_platform_devices > 0)
return;
#endif
#ifdef XSERVER_LIBPCIACCESS
xf86PciProbe();
#endif
#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
xf86SbusProbe();
#endif
#ifdef XSERVER_PLATFORM_BUS
xf86platformPrimary();
#endif
}
/*
* Determine what bus type the busID string represents. The start of the
* bus-dependent part of the string is returned as retID.
*/
BusType
StringToBusType(const char *busID, const char **retID)
{
char *p, *s;
BusType ret = BUS_NONE;
/* If no type field, Default to PCI */
if (isdigit(busID[0])) {
if (retID)
*retID = busID;
return BUS_PCI;
}
s = xstrdup(busID);
p = strtok(s, ":");
if (p == NULL || *p == 0) {
free(s);
return BUS_NONE;
}
if (!xf86NameCmp(p, "pci") || !xf86NameCmp(p, "agp"))
ret = BUS_PCI;
if (!xf86NameCmp(p, "sbus"))
ret = BUS_SBUS;
if (!xf86NameCmp(p, "platform"))
ret = BUS_PLATFORM;
if (!xf86NameCmp(p, "usb"))
ret = BUS_USB;
if (ret != BUS_NONE)
if (retID)
*retID = busID + strlen(p) + 1;
free(s);
return ret;
}
int
xf86AllocateEntity(void)
{
xf86NumEntities++;
xf86Entities = xnfreallocarray(xf86Entities,
xf86NumEntities, sizeof(EntityPtr));
xf86Entities[xf86NumEntities - 1] = xnfcalloc(1, sizeof(EntityRec));
xf86Entities[xf86NumEntities - 1]->entityPrivates =
xnfcalloc(xf86EntityPrivateCount, sizeof(DevUnion));
return xf86NumEntities - 1;
}
Bool
xf86IsEntityPrimary(int entityIndex)
{
EntityPtr pEnt = xf86Entities[entityIndex];
#ifdef XSERVER_LIBPCIACCESS
if (primaryBus.type == BUS_PLATFORM && pEnt->bus.type == BUS_PCI)
if (primaryBus.id.plat->pdev)
return MATCH_PCI_DEVICES(pEnt->bus.id.pci, primaryBus.id.plat->pdev);
#endif
if (primaryBus.type != pEnt->bus.type)
return FALSE;
switch (pEnt->bus.type) {
case BUS_PCI:
return pEnt->bus.id.pci == primaryBus.id.pci;
case BUS_SBUS:
return pEnt->bus.id.sbus.fbNum == primaryBus.id.sbus.fbNum;
case BUS_PLATFORM:
return pEnt->bus.id.plat == primaryBus.id.plat;
default:
return FALSE;
}
}
Bool
xf86DriverHasEntities(DriverPtr drvp)
{
int i;
for (i = 0; i < xf86NumEntities; i++) {
if (xf86Entities[i]->driver == drvp)
return TRUE;
}
return FALSE;
}
void
xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex)
{
if (entityIndex == -1)
return;
if (xf86Entities[entityIndex]->inUse &&
!(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL)) {
ErrorF("Requested Entity already in use!\n");
return;
}
pScrn->numEntities++;
pScrn->entityList = xnfreallocarray(pScrn->entityList,
pScrn->numEntities, sizeof(int));
pScrn->entityList[pScrn->numEntities - 1] = entityIndex;
xf86Entities[entityIndex]->inUse = TRUE;
pScrn->entityInstanceList = xnfreallocarray(pScrn->entityInstanceList,
pScrn->numEntities,
sizeof(int));
pScrn->entityInstanceList[pScrn->numEntities - 1] = 0;
}
void
xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, int instance)
{
int i;
if (entityIndex == -1 || entityIndex >= xf86NumEntities)
return;
for (i = 0; i < pScrn->numEntities; i++) {
if (pScrn->entityList[i] == entityIndex) {
pScrn->entityInstanceList[i] = instance;
break;
}
}
}
/*
* XXX This needs to be updated for the case where a single entity may have
* instances associated with more than one screen.
*/
ScrnInfoPtr
xf86FindScreenForEntity(int entityIndex)
{
int i, j;
if (entityIndex == -1)
return NULL;
if (xf86Screens) {
for (i = 0; i < xf86NumScreens; i++) {
for (j = 0; j < xf86Screens[i]->numEntities; j++) {
if (xf86Screens[i]->entityList[j] == entityIndex)
return xf86Screens[i];
}
}
}
return NULL;
}
void
xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex)
{
int i;
for (i = 0; i < pScrn->numEntities; i++) {
if (pScrn->entityList[i] == entityIndex) {
for (i++; i < pScrn->numEntities; i++)
pScrn->entityList[i - 1] = pScrn->entityList[i];
pScrn->numEntities--;
xf86Entities[entityIndex]->inUse = FALSE;
break;
}
}
}
/*
* xf86ClearEntityListForScreen() - called when a screen is deleted
* to mark its entities unused. Called by xf86DeleteScreen().
*/
void
xf86ClearEntityListForScreen(ScrnInfoPtr pScrn)
{
int i, entityIndex;
if (pScrn->entityList == NULL || pScrn->numEntities == 0)
return;
for (i = 0; i < pScrn->numEntities; i++) {
entityIndex = pScrn->entityList[i];
xf86Entities[entityIndex]->inUse = FALSE;
/* disable resource: call the disable function */
}
free(pScrn->entityList);
free(pScrn->entityInstanceList);
pScrn->entityList = NULL;
pScrn->entityInstanceList = NULL;
}
/*
* Add an extra device section (GDevPtr) to an entity.
*/
void
xf86AddDevToEntity(int entityIndex, GDevPtr dev)
{
EntityPtr pEnt;
if (entityIndex >= xf86NumEntities)
return;
pEnt = xf86Entities[entityIndex];
pEnt->numInstances++;
pEnt->devices = xnfreallocarray(pEnt->devices,
pEnt->numInstances, sizeof(GDevPtr));
pEnt->devices[pEnt->numInstances - 1] = dev;
dev->claimed = TRUE;
}
void
xf86RemoveDevFromEntity(int entityIndex, GDevPtr dev)
{
EntityPtr pEnt;
int i, j;
if (entityIndex >= xf86NumEntities)
return;
pEnt = xf86Entities[entityIndex];
for (i = 0; i < pEnt->numInstances; i++) {
if (pEnt->devices[i] == dev) {
for (j = i; j < pEnt->numInstances - 1; j++)
pEnt->devices[j] = pEnt->devices[j + 1];
break;
}
}
pEnt->numInstances--;
dev->claimed = FALSE;
}
/*
* xf86GetEntityInfo() -- This function hands information from the
* EntityRec struct to the drivers. The EntityRec structure itself
* remains invisible to the driver.
*/
EntityInfoPtr
xf86GetEntityInfo(int entityIndex)
{
EntityInfoPtr pEnt;
int i;
if (entityIndex == -1)
return NULL;
if (entityIndex >= xf86NumEntities)
return NULL;
pEnt = xnfcalloc(1, sizeof(EntityInfoRec));
pEnt->index = entityIndex;
pEnt->location = xf86Entities[entityIndex]->bus;
pEnt->active = xf86Entities[entityIndex]->active;
pEnt->chipset = xf86Entities[entityIndex]->chipset;
pEnt->driver = xf86Entities[entityIndex]->driver;
if ((xf86Entities[entityIndex]->devices) &&
(xf86Entities[entityIndex]->devices[0])) {
for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++)
if (xf86Entities[entityIndex]->devices[i]->screen == 0)
break;
pEnt->device = xf86Entities[entityIndex]->devices[i];
}
else
pEnt->device = NULL;
return pEnt;
}
int
xf86GetNumEntityInstances(int entityIndex)
{
if (entityIndex >= xf86NumEntities)
return -1;
return xf86Entities[entityIndex]->numInstances;
}
GDevPtr
xf86GetDevFromEntity(int entityIndex, int instance)
{
int i;
/* We might not use AddDevtoEntity */
if ((!xf86Entities[entityIndex]->devices) ||
(!xf86Entities[entityIndex]->devices[0]))
return NULL;
if (entityIndex >= xf86NumEntities ||
instance >= xf86Entities[entityIndex]->numInstances)
return NULL;
for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++)
if (xf86Entities[entityIndex]->devices[i]->screen == instance)
return xf86Entities[entityIndex]->devices[i];
return NULL;
}
/*
* xf86PostProbe() -- Allocate all non conflicting resources
* This function gets called by xf86Init().
*/
void
xf86PostProbe(void)
{
if (fbSlotClaimed && (
#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
sbusSlotClaimed ||
#endif
#ifdef XSERVER_PLATFORM_BUS
platformSlotClaimed ||
#endif
#ifdef XSERVER_LIBPCIACCESS
pciSlotClaimed
#else
TRUE
#endif
))
FatalError("Cannot run in framebuffer mode. Please specify busIDs "
" for all framebuffer devices\n");
}
Bool
xf86IsEntityShared(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
if (xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL) {
return TRUE;
}
}
return FALSE;
}
void
xf86SetEntityShared(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
xf86Entities[entityIndex]->entityProp |= IS_SHARED_ACCEL;
}
}
Bool
xf86IsEntitySharable(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
if (xf86Entities[entityIndex]->entityProp & ACCEL_IS_SHARABLE) {
return TRUE;
}
}
return FALSE;
}
void
xf86SetEntitySharable(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
xf86Entities[entityIndex]->entityProp |= ACCEL_IS_SHARABLE;
}
}
Bool
xf86IsPrimInitDone(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
if (xf86Entities[entityIndex]->entityProp & SA_PRIM_INIT_DONE) {
return TRUE;
}
}
return FALSE;
}
void
xf86SetPrimInitDone(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
xf86Entities[entityIndex]->entityProp |= SA_PRIM_INIT_DONE;
}
}
void
xf86ClearPrimInitDone(int entityIndex)
{
if (entityIndex < xf86NumEntities) {
xf86Entities[entityIndex]->entityProp &= ~SA_PRIM_INIT_DONE;
}
}
/*
* Allocate a private in the entities.
*/
int
xf86AllocateEntityPrivateIndex(void)
{
int idx, i;
EntityPtr pEnt;
DevUnion *nprivs;
idx = xf86EntityPrivateCount++;
for (i = 0; i < xf86NumEntities; i++) {
pEnt = xf86Entities[i];
nprivs = xnfreallocarray(pEnt->entityPrivates,
xf86EntityPrivateCount, sizeof(DevUnion));
/* Zero the new private */
memset(&nprivs[idx], 0, sizeof(DevUnion));
pEnt->entityPrivates = nprivs;
}
return idx;
}
DevUnion *
xf86GetEntityPrivate(int entityIndex, int privIndex)
{
if (entityIndex >= xf86NumEntities || privIndex >= xf86EntityPrivateCount)
return NULL;
return &(xf86Entities[entityIndex]->entityPrivates[privIndex]);
}