| /*************************************************************************/ /*! |
| @File |
| @Title PVR Bridge Module (kernel side) |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description Receives calls from the user portion of services and |
| despatches them to functions in the kernel portion. |
| @License Dual MIT/GPLv2 |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| 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. |
| |
| Alternatively, the contents of this file may be used under the terms of |
| the GNU General Public License Version 2 ("GPL") in which case the provisions |
| of GPL are applicable instead of those above. |
| |
| If you wish to allow use of your version of this file only under the terms of |
| GPL, and not to allow others to use your version of this file under the terms |
| of the MIT license, indicate your decision by deleting the provisions above |
| and replace them with the notice and other provisions required by GPL as set |
| out in the file called "GPL-COPYING" included in this distribution. If you do |
| not delete the provisions above, a recipient may use your version of this file |
| under the terms of either the MIT license or GPL. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS 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. |
| */ /**************************************************************************/ |
| |
| #include <linux/mm_types.h> |
| |
| #include "img_defs.h" |
| #include "pvr_bridge.h" |
| #include "connection_server.h" |
| #include "syscommon.h" |
| #include "pvr_debug.h" |
| #include "pvr_debugfs.h" |
| #include "private_data.h" |
| #include "linkage.h" |
| #include "pmr.h" |
| #include "rgx_bvnc_defs_km.h" |
| |
| #include <drm/drmP.h> |
| #include "pvr_drm.h" |
| #include "pvr_drv.h" |
| |
| #include "env_connection.h" |
| #include <linux/sched.h> |
| |
| /* RGX: */ |
| #if defined(SUPPORT_RGX) |
| #include "rgx_bridge.h" |
| #endif |
| |
| #include "srvcore.h" |
| #include "common_srvcore_bridge.h" |
| |
| #if defined(SUPPORT_DRM_EXT) |
| #define CAST_BRIDGE_CMD_PTR_TO_PTR(ptr) (ptr) |
| #else |
| #define CAST_BRIDGE_CMD_PTR_TO_PTR(ptr) (void *)(uintptr_t)(ptr) |
| #endif |
| |
| #if defined(MODULE_TEST) |
| /************************************************************************/ |
| // additional includes for services testing |
| /************************************************************************/ |
| #include "pvr_test_bridge.h" |
| #include "kern_test.h" |
| /************************************************************************/ |
| // end of additional includes |
| /************************************************************************/ |
| #endif |
| |
| /* WARNING! |
| * The mmap code has its own mutex, to prevent a possible deadlock, |
| * when using gPVRSRVLock. |
| * The Linux kernel takes the mm->mmap_sem before calling the mmap |
| * entry points (PVRMMap, MMapVOpen, MMapVClose), but the ioctl |
| * entry point may take mm->mmap_sem during fault handling, or |
| * before calling get_user_pages. If gPVRSRVLock was used in the |
| * mmap entry points, a deadlock could result, due to the ioctl |
| * and mmap code taking the two locks in different orders. |
| * As a corollary to this, the mmap entry points must not call |
| * any driver code that relies on gPVRSRVLock is held. |
| */ |
| static DEFINE_MUTEX(g_sMMapMutex); |
| |
| #if defined(DEBUG_BRIDGE_KM) |
| static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSBridgeStatsEntry = NULL; |
| static struct seq_operations gsBridgeStatsReadOps; |
| #endif |
| |
| /* These will go when full bridge gen comes in */ |
| #if defined(PDUMP) |
| PVRSRV_ERROR InitPDUMPCTRLBridge(void); |
| PVRSRV_ERROR DeinitPDUMPCTRLBridge(void); |
| PVRSRV_ERROR InitPDUMPBridge(void); |
| PVRSRV_ERROR DeinitPDUMPBridge(void); |
| PVRSRV_ERROR InitRGXPDUMPBridge(void); |
| PVRSRV_ERROR DeinitRGXPDUMPBridge(void); |
| #endif |
| #if defined(SUPPORT_DISPLAY_CLASS) |
| PVRSRV_ERROR InitDCBridge(void); |
| PVRSRV_ERROR DeinitDCBridge(void); |
| #endif |
| PVRSRV_ERROR InitMMBridge(void); |
| PVRSRV_ERROR DeinitMMBridge(void); |
| #if !defined(EXCLUDE_CMM_BRIDGE) |
| PVRSRV_ERROR InitCMMBridge(void); |
| PVRSRV_ERROR DeinitCMMBridge(void); |
| #endif |
| PVRSRV_ERROR InitPDUMPMMBridge(void); |
| PVRSRV_ERROR DeinitPDUMPMMBridge(void); |
| PVRSRV_ERROR InitSRVCOREBridge(void); |
| PVRSRV_ERROR DeinitSRVCOREBridge(void); |
| PVRSRV_ERROR InitSYNCBridge(void); |
| PVRSRV_ERROR DeinitSYNCBridge(void); |
| |
| #if defined(SUPPORT_SERVER_SYNC) |
| #if defined(SUPPORT_INSECURE_EXPORT) |
| PVRSRV_ERROR InitSYNCEXPORTBridge(void); |
| PVRSRV_ERROR DeinitSYNCEXPORTBridge(void); |
| #endif |
| #if defined(SUPPORT_SECURE_EXPORT) |
| PVRSRV_ERROR InitSYNCSEXPORTBridge(void); |
| PVRSRV_ERROR DeinitSYNCSEXPORTBridge(void); |
| #endif |
| #endif /* defined(SUPPORT_SERVER_SYNC) */ |
| |
| #if defined (SUPPORT_RGX) |
| #if !defined(SUPPORT_KERNEL_SRVINIT) |
| PVRSRV_ERROR InitRGXINITBridge(void); |
| PVRSRV_ERROR DeinitRGXINITBridge(void); |
| #endif |
| PVRSRV_ERROR InitRGXTA3DBridge(void); |
| PVRSRV_ERROR DeinitRGXTA3DBridge(void); |
| PVRSRV_ERROR InitRGXTQBridge(void); |
| PVRSRV_ERROR DeinitRGXTQBridge(void); |
| PVRSRV_ERROR InitRGXTQ2Bridge(void); |
| PVRSRV_ERROR DeinitRGXTQ2Bridge(void); |
| PVRSRV_ERROR InitRGXCMPBridge(void); |
| PVRSRV_ERROR DeinitRGXCMPBridge(void); |
| #if !defined(EXCLUDE_BREAKPOINT_BRIDGE) |
| PVRSRV_ERROR InitBREAKPOINTBridge(void); |
| PVRSRV_ERROR DeinitBREAKPOINTBridge(void); |
| #endif |
| PVRSRV_ERROR InitDEBUGMISCBridge(void); |
| PVRSRV_ERROR DeinitDEBUGMISCBridge(void); |
| PVRSRV_ERROR InitRGXHWPERFBridge(void); |
| PVRSRV_ERROR DeinitRGXHWPERFBridge(void); |
| PVRSRV_ERROR InitRGXRAYBridge(void); |
| PVRSRV_ERROR DeinitRGXRAYBridge(void); |
| #if !defined(EXCLUDE_REGCONFIG_BRIDGE) |
| PVRSRV_ERROR InitREGCONFIGBridge(void); |
| PVRSRV_ERROR DeinitREGCONFIGBridge(void); |
| #endif |
| PVRSRV_ERROR InitTIMERQUERYBridge(void); |
| PVRSRV_ERROR DeinitTIMERQUERYBridge(void); |
| PVRSRV_ERROR InitRGXKICKSYNCBridge(void); |
| PVRSRV_ERROR DeinitRGXKICKSYNCBridge(void); |
| PVRSRV_ERROR InitRGXSIGNALSBridge(void); |
| PVRSRV_ERROR DeinitRGXSIGNALSBridge(void); |
| #endif /* SUPPORT_RGX */ |
| PVRSRV_ERROR InitCACHEBridge(void); |
| PVRSRV_ERROR DeinitCACHEBridge(void); |
| #if defined(SUPPORT_SECURE_EXPORT) |
| PVRSRV_ERROR InitSMMBridge(void); |
| PVRSRV_ERROR DeinitSMMBridge(void); |
| #endif |
| #if !defined(EXCLUDE_HTBUFFER_BRIDGE) |
| PVRSRV_ERROR InitHTBUFFERBridge(void); |
| PVRSRV_ERROR DeinitHTBUFFERBridge(void); |
| #endif |
| PVRSRV_ERROR InitPVRTLBridge(void); |
| PVRSRV_ERROR DeinitPVRTLBridge(void); |
| #if defined(PVR_RI_DEBUG) |
| PVRSRV_ERROR InitRIBridge(void); |
| PVRSRV_ERROR DeinitRIBridge(void); |
| #endif |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| PVRSRV_ERROR InitDEVICEMEMHISTORYBridge(void); |
| PVRSRV_ERROR DeinitDEVICEMEMHISTORYBridge(void); |
| #endif |
| PVRSRV_ERROR InitDMABUFBridge(void); |
| PVRSRV_ERROR DeinitDMABUFBridge(void); |
| #if defined(SUPPORT_VALIDATION_BRIDGE) |
| PVRSRV_ERROR InitVALIDATIONBridge(void); |
| #endif |
| |
| #if defined(PVR_TESTING_UTILS) |
| PVRSRV_ERROR InitTUTILSBridge(void); |
| PVRSRV_ERROR DeinitTUTILSBridge(void); |
| #endif |
| #if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) |
| PVRSRV_ERROR InitSYNCTRACKINGBridge(void); |
| PVRSRV_ERROR DeinitSYNCTRACKINGBridge(void); |
| #endif |
| #if defined(SUPPORT_WRAP_EXTMEM) |
| PVRSRV_ERROR InitMMEXTMEMBridge(void); |
| PVRSRV_ERROR DeinitMMEXTMEMBridge(void); |
| #endif |
| |
| PVRSRV_ERROR |
| DeviceDepBridgeInit(IMG_UINT64 ui64Features) |
| { |
| PVRSRV_ERROR eError; |
| |
| if(ui64Features & RGX_FEATURE_COMPUTE_BIT_MASK) |
| { |
| eError = InitRGXCMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| |
| if(ui64Features & RGX_FEATURE_SIGNAL_SNOOPING_BIT_MASK) |
| { |
| eError = InitRGXSIGNALSBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| if(ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| eError = InitRGXRAYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| if(ui64Features & RGX_FEATURE_FASTRENDER_DM_BIT_MASK) |
| { |
| eError = InitRGXTQ2Bridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| return PVRSRV_OK; |
| } |
| |
| |
| PVRSRV_ERROR |
| DeviceDepBridgeDeInit(IMG_UINT64 ui64Features) |
| { |
| PVRSRV_ERROR eError; |
| |
| if(ui64Features & RGX_FEATURE_COMPUTE_BIT_MASK) |
| { |
| eError = DeinitRGXCMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| |
| if(ui64Features & RGX_FEATURE_SIGNAL_SNOOPING_BIT_MASK) |
| { |
| eError = DeinitRGXSIGNALSBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| if(ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| eError = DeinitRGXRAYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| if(ui64Features & RGX_FEATURE_FASTRENDER_DM_BIT_MASK) |
| { |
| eError = DeinitRGXTQ2Bridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } |
| |
| return PVRSRV_OK; |
| } |
| |
| |
| |
| PVRSRV_ERROR |
| LinuxBridgeInit(void) |
| { |
| PVRSRV_ERROR eError; |
| #if defined(DEBUG_BRIDGE_KM) |
| IMG_INT iResult; |
| |
| iResult = PVRDebugFSCreateEntry("bridge_stats", |
| NULL, |
| &gsBridgeStatsReadOps, |
| NULL, |
| NULL, |
| NULL, |
| &g_BridgeDispatchTable[0], |
| &gpsPVRDebugFSBridgeStatsEntry); |
| if (iResult != 0) |
| { |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| #endif |
| |
| BridgeDispatchTableStartOffsetsInit(); |
| |
| eError = InitSRVCOREBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| eError = InitSYNCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(SUPPORT_SERVER_SYNC) |
| #if defined(SUPPORT_INSECURE_EXPORT) |
| eError = InitSYNCEXPORTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| #if defined(SUPPORT_SECURE_EXPORT) |
| eError = InitSYNCSEXPORTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| #endif /* defined(SUPPORT_SERVER_SYNC) */ |
| |
| #if defined(PDUMP) |
| eError = InitPDUMPCTRLBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #if !defined(EXCLUDE_CMM_BRIDGE) |
| eError = InitCMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(PDUMP) |
| eError = InitPDUMPMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| eError = InitPDUMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitDMABUFBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(SUPPORT_DISPLAY_CLASS) |
| eError = InitDCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitCACHEBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(SUPPORT_SECURE_EXPORT) |
| eError = InitSMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if !defined(EXCLUDE_HTBUFFER_BRIDGE) |
| eError = InitHTBUFFERBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitPVRTLBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(PVR_RI_DEBUG) |
| eError = InitRIBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(SUPPORT_VALIDATION_BRIDGE) |
| eError = InitVALIDATIONBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(PVR_TESTING_UTILS) |
| eError = InitTUTILSBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| eError = InitDEVICEMEMHISTORYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| |
| #if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) |
| eError = InitSYNCTRACKINGBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined (SUPPORT_RGX) |
| |
| eError = InitRGXTQBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if !defined(SUPPORT_KERNEL_SRVINIT) |
| eError = InitRGXINITBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitRGXTA3DBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if !defined(EXCLUDE_BREAKPOINT_BRIDGE) |
| eError = InitBREAKPOINTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitDEBUGMISCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(PDUMP) |
| eError = InitRGXPDUMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitRGXHWPERFBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if !defined(EXCLUDE_REGCONFIG_BRIDGE) |
| eError = InitREGCONFIGBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = InitTIMERQUERYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| eError = InitRGXKICKSYNCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #endif /* SUPPORT_RGX */ |
| |
| #if defined(SUPPORT_WRAP_EXTMEM) |
| eError = InitMMEXTMEMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| LinuxBridgeDeInit(void) |
| { |
| PVRSRV_ERROR eError; |
| |
| #if defined(SUPPORT_WRAP_EXTMEM) |
| eError = DeinitMMEXTMEMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(DEBUG_BRIDGE_KM) |
| if (gpsPVRDebugFSBridgeStatsEntry != NULL) |
| { |
| PVRDebugFSRemoveEntry(&gpsPVRDebugFSBridgeStatsEntry); |
| } |
| #endif |
| |
| eError = DeinitSRVCOREBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| eError = DeinitSYNCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(SUPPORT_SERVER_SYNC) |
| #if defined(SUPPORT_INSECURE_EXPORT) |
| eError = DeinitSYNCEXPORTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| #if defined(SUPPORT_SECURE_EXPORT) |
| eError = DeinitSYNCSEXPORTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| #endif /* defined(SUPPORT_SERVER_SYNC) */ |
| |
| #if defined(PDUMP) |
| eError = DeinitPDUMPCTRLBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #if !defined(EXCLUDE_CMM_BRIDGE) |
| eError = DeinitCMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(PDUMP) |
| eError = DeinitPDUMPMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| eError = DeinitPDUMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitDMABUFBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(PVR_TESTING_UTILS) |
| eError = DeinitTUTILSBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(SUPPORT_DISPLAY_CLASS) |
| eError = DeinitDCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitCACHEBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(SUPPORT_SECURE_EXPORT) |
| eError = DeinitSMMBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if !defined(EXCLUDE_HTBUFFER_BRIDGE) |
| eError = DeinitHTBUFFERBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitPVRTLBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(PVR_RI_DEBUG) |
| eError = DeinitRIBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| eError = DeinitDEVICEMEMHISTORYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| |
| #if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) |
| eError = DeinitSYNCTRACKINGBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| #if defined (SUPPORT_RGX) |
| |
| eError = DeinitRGXTQBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| |
| #if !defined(SUPPORT_KERNEL_SRVINIT) |
| eError = DeinitRGXINITBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitRGXTA3DBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if !defined(EXCLUDE_BREAKPOINT_BRIDGE) |
| eError = DeinitBREAKPOINTBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitDEBUGMISCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if defined(PDUMP) |
| eError = DeinitRGXPDUMPBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitRGXHWPERFBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #if !defined(EXCLUDE_REGCONFIG_BRIDGE) |
| eError = DeinitREGCONFIGBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| #endif |
| |
| eError = DeinitTIMERQUERYBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| eError = DeinitRGXKICKSYNCBridge(); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| #endif /* SUPPORT_RGX */ |
| |
| return eError; |
| } |
| |
| #if defined(DEBUG_BRIDGE_KM) |
| static void *BridgeStatsSeqStart(struct seq_file *psSeqFile, loff_t *puiPosition) |
| { |
| PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psDispatchTable = (PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *)psSeqFile->private; |
| |
| OSAcquireBridgeLock(); |
| |
| if (psDispatchTable == NULL || (*puiPosition) > BRIDGE_DISPATCH_TABLE_ENTRY_COUNT) |
| { |
| return NULL; |
| } |
| |
| if ((*puiPosition) == 0) |
| { |
| return SEQ_START_TOKEN; |
| } |
| |
| return &(psDispatchTable[(*puiPosition) - 1]); |
| } |
| |
| static void BridgeStatsSeqStop(struct seq_file *psSeqFile, void *pvData) |
| { |
| PVR_UNREFERENCED_PARAMETER(psSeqFile); |
| PVR_UNREFERENCED_PARAMETER(pvData); |
| |
| OSReleaseBridgeLock(); |
| } |
| |
| static void *BridgeStatsSeqNext(struct seq_file *psSeqFile, |
| void *pvData, |
| loff_t *puiPosition) |
| { |
| PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psDispatchTable = (PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *)psSeqFile->private; |
| loff_t uiItemAskedFor = *puiPosition; /* puiPosition on entry is the index to return */ |
| |
| PVR_UNREFERENCED_PARAMETER(pvData); |
| |
| /* Is the item asked for (starts at 0) a valid table index? */ |
| if (uiItemAskedFor < BRIDGE_DISPATCH_TABLE_ENTRY_COUNT) |
| { |
| (*puiPosition)++; /* on exit it is the next seq index to ask for */ |
| return &(psDispatchTable[uiItemAskedFor]); |
| } |
| |
| /* Now passed the end of the table to indicate stop */ |
| return NULL; |
| } |
| |
| static int BridgeStatsSeqShow(struct seq_file *psSeqFile, void *pvData) |
| { |
| if (pvData == SEQ_START_TOKEN) |
| { |
| seq_printf(psSeqFile, |
| "Total ioctl call count = %u\n" |
| "Total number of bytes copied via copy_from_user = %u\n" |
| "Total number of bytes copied via copy_to_user = %u\n" |
| "Total number of bytes copied via copy_*_user = %u\n\n" |
| "%3s: %-60s | %-48s | %10s | %20s | %20s | %20s | %20s \n", |
| g_BridgeGlobalStats.ui32IOCTLCount, |
| g_BridgeGlobalStats.ui32TotalCopyFromUserBytes, |
| g_BridgeGlobalStats.ui32TotalCopyToUserBytes, |
| g_BridgeGlobalStats.ui32TotalCopyFromUserBytes + g_BridgeGlobalStats.ui32TotalCopyToUserBytes, |
| "#", |
| "Bridge Name", |
| "Wrapper Function", |
| "Call Count", |
| "copy_from_user (B)", |
| "copy_to_user (B)", |
| "Total Time (us)", |
| "Max Time (us)"); |
| } |
| else if (pvData != NULL) |
| { |
| PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry = ( PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *)pvData; |
| IMG_UINT32 ui32Remainder; |
| |
| seq_printf(psSeqFile, |
| "%3d: %-60s %-48s %-10u %-20u %-20u %-20llu %-20llu\n", |
| (IMG_UINT32)(((size_t)psEntry-(size_t)g_BridgeDispatchTable)/sizeof(*g_BridgeDispatchTable)), |
| psEntry->pszIOCName, |
| (psEntry->pfFunction != NULL) ? psEntry->pszFunctionName : "(null)", |
| psEntry->ui32CallCount, |
| psEntry->ui32CopyFromUserTotalBytes, |
| psEntry->ui32CopyToUserTotalBytes, |
| (unsigned long long) OSDivide64r64(psEntry->ui64TotalTimeNS, 1000, &ui32Remainder), |
| (unsigned long long) OSDivide64r64(psEntry->ui64MaxTimeNS, 1000, &ui32Remainder)); |
| } |
| |
| return 0; |
| } |
| |
| static struct seq_operations gsBridgeStatsReadOps = |
| { |
| .start = BridgeStatsSeqStart, |
| .stop = BridgeStatsSeqStop, |
| .next = BridgeStatsSeqNext, |
| .show = BridgeStatsSeqShow, |
| }; |
| #endif /* defined(DEBUG_BRIDGE_KM) */ |
| |
| int |
| PVRSRV_BridgeDispatchKM(struct drm_device __maybe_unused *dev, void *arg, struct drm_file *pDRMFile) |
| { |
| struct drm_pvr_srvkm_cmd *psSrvkmCmd = (struct drm_pvr_srvkm_cmd *) arg; |
| PVRSRV_BRIDGE_PACKAGE sBridgePackageKM = { 0 }; |
| CONNECTION_DATA *psConnection = LinuxConnectionFromFile(pDRMFile->filp); |
| PVRSRV_ERROR error; |
| |
| if(psConnection == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Connection is closed", __FUNCTION__)); |
| return -EFAULT; |
| } |
| |
| if(OSGetDriverSuspended()) |
| { |
| return -EINTR; |
| } |
| |
| PVR_ASSERT(psSrvkmCmd != NULL); |
| |
| DRM_DEBUG("tgid=%d, tgid_connection=%d, bridge_id=%d, func_id=%d", |
| task_tgid_nr(current), |
| ((ENV_CONNECTION_DATA *)PVRSRVConnectionPrivateData(psConnection))->owner, |
| psSrvkmCmd->bridge_id, |
| psSrvkmCmd->bridge_func_id); |
| |
| sBridgePackageKM.ui32BridgeID = psSrvkmCmd->bridge_id; |
| sBridgePackageKM.ui32FunctionID = psSrvkmCmd->bridge_func_id; |
| sBridgePackageKM.ui32Size = sizeof(sBridgePackageKM); |
| sBridgePackageKM.pvParamIn = CAST_BRIDGE_CMD_PTR_TO_PTR(psSrvkmCmd->in_data_ptr); |
| sBridgePackageKM.ui32InBufferSize = psSrvkmCmd->in_data_size; |
| sBridgePackageKM.pvParamOut = CAST_BRIDGE_CMD_PTR_TO_PTR(psSrvkmCmd->out_data_ptr); |
| sBridgePackageKM.ui32OutBufferSize = psSrvkmCmd->out_data_size; |
| |
| error = BridgedDispatchKM(psConnection, &sBridgePackageKM); |
| return OSPVRSRVToNativeError(error); |
| } |
| |
| int |
| PVRSRV_MMap(struct file *pFile, struct vm_area_struct *ps_vma) |
| { |
| CONNECTION_DATA *psConnection = LinuxConnectionFromFile(pFile); |
| IMG_HANDLE hSecurePMRHandle = (IMG_HANDLE)((uintptr_t)ps_vma->vm_pgoff); |
| PMR *psPMR; |
| PVRSRV_ERROR eError; |
| |
| if(psConnection == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "Invalid connection data")); |
| return -ENOENT; |
| } |
| |
| /* |
| * The bridge lock used here to protect PVRSRVLookupHandle is replaced |
| * by a specific lock considering that the handle functions have now |
| * their own lock. This change was necessary to solve the lockdep issues |
| * related with the PVRSRV_MMap. |
| */ |
| mutex_lock(&g_sMMapMutex); |
| |
| eError = PVRSRVLookupHandle(psConnection->psHandleBase, |
| (void **)&psPMR, |
| hSecurePMRHandle, |
| PVRSRV_HANDLE_TYPE_PHYSMEM_PMR, |
| IMG_TRUE); |
| if (eError != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| /* Note: PMRMMapPMR will take a reference on the PMR. |
| * Unref the handle immediately, because we have now done |
| * the required operation on the PMR (whether it succeeded or not) |
| */ |
| eError = PMRMMapPMR(psPMR, ps_vma); |
| PVRSRVReleaseHandle(psConnection->psHandleBase, hSecurePMRHandle, PVRSRV_HANDLE_TYPE_PHYSMEM_PMR); |
| if (eError != PVRSRV_OK) |
| { |
| goto e1; |
| } |
| |
| mutex_unlock(&g_sMMapMutex); |
| |
| return 0; |
| |
| e1: |
| PMRUnrefPMR(psPMR); |
| goto em1; |
| e0: |
| PVR_DPF((PVR_DBG_ERROR, "Error in mmap critical section")); |
| em1: |
| mutex_unlock(&g_sMMapMutex); |
| |
| PVR_DPF((PVR_DBG_ERROR, "Unable to translate error %d", eError)); |
| PVR_ASSERT(eError != PVRSRV_OK); |
| |
| return -ENOENT; // -EAGAIN // or what? |
| } |