Edit

IABSD.fr/xenocara/driver/xf86-video-amdgpu/src/amdgpu_probe.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2026-03-12 04:31:28
    Hash : bedc11b3
    Message : update to xf86-video-amdgpu 25.0.0 tested by matthieu and myself on multiple machines

  • driver/xf86-video-amdgpu/src/amdgpu_probe.c
  • /*
     * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
     *                VA Linux Systems Inc., Fremont, California.
     *
     * All Rights Reserved.
     *
     * 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 on 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 (including the
     * next paragraph) 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
     * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
     * THEIR SUPPLIERS 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.
     */
    
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    /*
     * Authors:
     *   Kevin E. Martin <martin@xfree86.org>
     *   Rickard E. Faith <faith@valinux.com>
     * KMS support - Dave Airlie <airlied@redhat.com>
     */
    
    #include "amdgpu_probe.h"
    #include "amdgpu_version.h"
    #include "amdgpu_drv.h"
    
    #include "xf86.h"
    
    #include "xf86drmMode.h"
    
    #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    #include <xf86_OSproc.h>
    #endif
    
    #ifdef X_PRIVSEP
    extern int priv_open_device(const char *);
    #else
    #define priv_open_device(n)	open(n,O_RDWR|O_CLOEXEC)
    #endif
    
    #include <xf86platformBus.h>
    
    _X_EXPORT int gAMDGPUEntityIndex = -1;
    
    /* Return the options for supported chipset 'n'; NULL otherwise */
    static const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid)
    {
    	return AMDGPUOptionsWeak();
    }
    
    static SymTabRec AMDGPUAny[] = {
    	{ 0, "All GPUs supported by the amdgpu kernel driver" },
    	{ -1, NULL }
    };
    
    /* Return the string name for supported chipset 'n'; NULL otherwise. */
    static void AMDGPUIdentify(int flags)
    {
    	xf86PrintChipsets(AMDGPU_NAME, "Driver for AMD Radeon", AMDGPUAny);
    }
    
    static Bool amdgpu_device_matches(const drmDevicePtr device,
    				  const struct pci_device *dev)
    {
    	return (device->bustype == DRM_BUS_PCI &&
    		device->businfo.pci->domain == dev->domain &&
    		device->businfo.pci->bus == dev->bus &&
    		device->businfo.pci->dev == dev->dev &&
    		device->businfo.pci->func == dev->func);
    }
    
    static Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn)
    {
    #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
    	const char *busIdString = pAMDGPUEnt->busid;
    	int ret = drmCheckModesettingSupported(busIdString);
    
    	if (ret) {
    		if (xf86LoadKernelModule("amdgpukms"))
    			ret = drmCheckModesettingSupported(busIdString);
    	}
    	if (ret) {
    		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
    			       "[KMS] drm report modesetting isn't supported.\n");
    		return FALSE;
    	}
    
    #endif
    	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
    		       "[KMS] Kernel modesetting enabled.\n");
    	return TRUE;
    }
    
    static int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn,
    				 struct pci_device *pci_dev,
    				 struct xf86_platform_device *platform_dev,
    				 AMDGPUEntPtr pAMDGPUEnt)
    {
    #define MAX_DRM_DEVICES 64
    	drmDevicePtr devices[MAX_DRM_DEVICES];
    	struct pci_device *dev;
    	const char *path;
    	int fd = -1, i, ret;
    
    	if (platform_dev)
    		dev = platform_dev->pdev;
    	else
    		dev = pci_dev;
    
    	XNFasprintf(&pAMDGPUEnt->busid, "pci:%04x:%02x:%02x.%u",
    		    dev->domain, dev->bus, dev->dev, dev->func);
    
    	if (platform_dev) {
    #ifdef ODEV_ATTRIB_FD
    		fd = xf86_get_platform_device_int_attrib(platform_dev,
    							 ODEV_ATTRIB_FD, -1);
    		if (fd != -1)
    			return fd;
    #endif
    
    #ifdef ODEV_ATTRIB_PATH
    		path = xf86_get_platform_device_attrib(platform_dev,
    						       ODEV_ATTRIB_PATH);
    
    		fd = priv_open_device(path);
    		if (fd != -1)
    			return fd;
    #endif
    	}
    
    	if (!amdgpu_kernel_mode_enabled(pScrn))
    		return -1;
    
    	ret = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
    	if (ret == -1) {
    		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    			   "[drm] Failed to retrieve DRM devices information.\n");
    		return -1;
    	}
    	for (i = 0; i < ret; i++) {
    		if (amdgpu_device_matches(devices[i], dev) &&
    		    devices[i]->available_nodes & (1 << DRM_NODE_PRIMARY)) {
    			path = devices[i]->nodes[DRM_NODE_PRIMARY];
    			fd = priv_open_device(path);
    			break;
    		}
    	}
    	drmFreeDevices(devices, ret);
    
    	if (fd == -1)
    		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    			   "[drm] Failed to open DRM device for %s: %s\n",
    			   pAMDGPUEnt->busid, strerror(errno));
    	return fd;
    #undef MAX_DRM_DEVICES
    }
    
    void amdgpu_kernel_close_fd(AMDGPUEntPtr pAMDGPUEnt)
    {
    #if defined(XSERVER_PLATFORM_BUS) && defined(XF86_PDEV_SERVER_FD)
    	if (!(pAMDGPUEnt->platform_dev &&
    	      pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
    #endif
    		close(pAMDGPUEnt->fd);
    	pAMDGPUEnt->fd = -1;
    }
    
    /* Pull a local version of the helper. It's available since 2.4.98 yet
     * it may be too new for some distributions.
     */
    static int local_drmIsMaster(int fd)
    {
    	return drmAuthMagic(fd, 0) != -EACCES;
    }
    
    static Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn,
    				   struct pci_device *pci_dev,
    				   struct xf86_platform_device *platform_dev,
    				   AMDGPUEntPtr pAMDGPUEnt)
    {
    	pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, pci_dev, platform_dev, pAMDGPUEnt);
    	if (pAMDGPUEnt->fd == -1)
    		return FALSE;
    
    	/* Check that what we opened is a master or a master-capable FD */
    	if (!local_drmIsMaster(pAMDGPUEnt->fd)) {
    		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    			   "[drm] device is not DRM master.\n");
    		amdgpu_kernel_close_fd(pAMDGPUEnt);
    		return FALSE;
    	}
    
    	return TRUE;
    }
    
    static Bool amdgpu_device_setup(ScrnInfoPtr pScrn,
    				struct pci_device *pci_dev,
    				struct xf86_platform_device *platform_dev,
    				AMDGPUEntPtr pAMDGPUEnt)
    {
    	uint32_t major_version;
    	uint32_t minor_version;
    
    	pAMDGPUEnt->platform_dev = platform_dev;
    	if (!amdgpu_open_drm_master(pScrn, pci_dev, platform_dev,
    				    pAMDGPUEnt))
    		return FALSE;
    
    	if (amdgpu_device_initialize(pAMDGPUEnt->fd,
    				     &major_version,
    				     &minor_version,
    				     &pAMDGPUEnt->pDev)) {
    		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    			   "amdgpu_device_initialize failed\n");
    		goto error_amdgpu;
    	}
    
    	return TRUE;
    
    error_amdgpu:
    	amdgpu_kernel_close_fd(pAMDGPUEnt);
    	return FALSE;
    }
    
    static Bool
    amdgpu_probe(ScrnInfoPtr pScrn, int entity_num,
    	     struct pci_device *pci_dev, struct xf86_platform_device *dev)
    {
    	EntityInfoPtr pEnt = NULL;
    	DevUnion *pPriv;
    	AMDGPUEntPtr pAMDGPUEnt;
    
    	if (!pScrn)
    		return FALSE;
    
    	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
    	pScrn->driverName = AMDGPU_DRIVER_NAME;
    	pScrn->name = AMDGPU_NAME;
    	pScrn->Probe = NULL;
    	pScrn->PreInit = AMDGPUPreInit_KMS;
    	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
    	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
    	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
    	pScrn->EnterVT = AMDGPUEnterVT_KMS;
    	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
    	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
    	pScrn->ValidMode = AMDGPUValidMode;
    
    	pEnt = xf86GetEntityInfo(entity_num);
    
    	/* Create a AMDGPUEntity for all chips, even with old single head
    	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
    	 */
    	xf86SetEntitySharable(entity_num);
    
    	if (gAMDGPUEntityIndex == -1)
    		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
    
    	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
    
    	if (!pPriv->ptr) {
    		pPriv->ptr = XNFcallocarray(sizeof(AMDGPUEntRec), 1);
    		if (!pPriv->ptr)
    			goto error;
    
    		pAMDGPUEnt = pPriv->ptr;
    		if (!amdgpu_device_setup(pScrn, pci_dev, dev, pAMDGPUEnt))
    			goto error;
    
    		pAMDGPUEnt->fd_ref = 1;
    
    	} else {
    		pAMDGPUEnt = pPriv->ptr;
    
    		if (pAMDGPUEnt->fd_ref == ARRAY_SIZE(pAMDGPUEnt->scrn)) {
    			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    				   "Only up to %u Zaphod instances supported\n",
    				   (unsigned)ARRAY_SIZE(pAMDGPUEnt->scrn));
    			goto error;
    		}
    
    		pAMDGPUEnt->fd_ref++;
    	}
    
    	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
    				       xf86GetNumEntityInstances(pEnt->
    								 index)
    				       - 1);
    	free(pEnt);
    
    	return TRUE;
    
    error:
    	free(pEnt);
    	return FALSE;
    }
    
    static Bool
    amdgpu_pci_probe(DriverPtr pDriver,
    		 int entity_num, struct pci_device *device, intptr_t match_data)
    {
    	ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
    						NULL, NULL, NULL, NULL, NULL);
    
    	return amdgpu_probe(pScrn, entity_num, device, NULL);
    }
    
    static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
    {
    	xorgHWFlags *flag;
    
    	switch (op) {
    	case GET_REQUIRED_HW_INTERFACES:
    		flag = (CARD32 *) data;
    		(*flag) = 0;
    		return TRUE;
    	case SUPPORTS_SERVER_FDS:
    		return TRUE;
           default:
    		return FALSE;
    	}
    }
    
    #ifdef XSERVER_PLATFORM_BUS
    static Bool
    amdgpu_platform_probe(DriverPtr pDriver,
    		      int entity_num, int flags,
    		      struct xf86_platform_device *dev, intptr_t match_data)
    {
    	ScrnInfoPtr pScrn;
    	int scr_flags = 0;
    
    	if (!dev->pdev)
    		return FALSE;
    
    	if (flags & PLATFORM_PROBE_GPU_SCREEN)
    		scr_flags = XF86_ALLOCATE_GPU_SCREEN;
    
    	pScrn = xf86AllocateScreen(pDriver, scr_flags);
    	if (xf86IsEntitySharable(entity_num))
    		xf86SetEntityShared(entity_num);
    	xf86AddEntityToScreen(pScrn, entity_num);
    
    	return amdgpu_probe(pScrn, entity_num, NULL, dev);
    }
    #endif
    
    static const struct pci_id_match amdgpu_device_match[] = {
        {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
        {0, 0, 0},
    };
    
    DriverRec AMDGPU = {
    	AMDGPU_VERSION_CURRENT,
    	AMDGPU_DRIVER_NAME,
    	AMDGPUIdentify,
    	NULL,
    	AMDGPUAvailableOptions,
    	NULL,
    	0,
    	AMDGPUDriverFunc,
    	amdgpu_device_match,
    	amdgpu_pci_probe,
    #ifdef XSERVER_PLATFORM_BUS
    	amdgpu_platform_probe
    #endif
    };