1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2017-2017 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "eventbufferproducer.h" 25 #include "nvport/nvport.h" 26 27 // 28 // This file contains generic event buffer producer implementation for adding variable length data 29 // 30 // Data format: 31 // 32 // Event Record buffer holds fixed size records 33 // 34 // |---------|---------|---------|---------|...|---------| 35 // | record1 | record2 | record3 | record4 |...| recordn | 36 // |---------|---------|---------|---------|...|---------| 37 // 38 // Variable length data buffer: 39 // The fixed event record can optionally contain a pointer to variable length data. 40 // This buffer stores the varlength data that doesn't fit in the fixed size records. 41 // 42 // |------------|--------|...|---------| 43 // | data2 | data4 |...| data n | 44 // |------------|--------|...|---------| 45 // 46 47 static NV_EVENT_BUFFER_RECORD* _eventBufferGetFreeRecord(EVENT_BUFFER_PRODUCER_INFO *); 48 static void _eventBufferAddVardata(EVENT_BUFFER_PRODUCER_INFO*, NvP64, NvU32, NV_EVENT_BUFFER_RECORD_HEADER*); 49 static void _eventBufferUpdateRecordBufferCount(EVENT_BUFFER_PRODUCER_INFO*); 50 static void _eventBufferUpdateVarRemaingSize(EVENT_BUFFER_PRODUCER_INFO* info); 51 52 void 53 eventBufferInitRecordBuffer 54 ( 55 EVENT_BUFFER_PRODUCER_INFO *info, 56 NV_EVENT_BUFFER_HEADER* pHeader, 57 NvP64 recordBuffAddr, 58 NvU32 recordSize, 59 NvU32 recordCount, 60 NvU32 bufferSize, 61 NvU32 notificationThreshold 62 ) 63 { 64 RECORD_BUFFER_INFO* pRecordBuffer = &info->recordBuffer; 65 pRecordBuffer->pHeader = pHeader; 66 pRecordBuffer->recordBuffAddr = recordBuffAddr; 67 pRecordBuffer->recordSize = recordSize; 68 pRecordBuffer->totalRecordCount = recordCount; 69 pRecordBuffer->bufferSize = bufferSize; 70 pRecordBuffer->notificationThreshold = notificationThreshold; 71 } 72 73 void 74 eventBufferInitVardataBuffer 75 ( 76 EVENT_BUFFER_PRODUCER_INFO *info, 77 NvP64 vardataBuffAddr, 78 NvU32 bufferSize, 79 NvU32 notificationThreshold 80 ) 81 { 82 VARDATA_BUFFER_INFO* pVardataBuffer = &info->vardataBuffer; 83 pVardataBuffer->vardataBuffAddr = vardataBuffAddr; 84 pVardataBuffer->bufferSize = bufferSize; 85 pVardataBuffer->notificationThreshold = notificationThreshold; 86 pVardataBuffer->get = 0; 87 pVardataBuffer->put = 0; 88 pVardataBuffer->remainingSize = bufferSize; 89 } 90 91 void 92 eventBufferInitNotificationHandle(EVENT_BUFFER_PRODUCER_INFO *info, NvP64 notificationHandle) 93 { 94 info->notificationHandle = notificationHandle; 95 } 96 97 void 98 eventBufferSetEnable(EVENT_BUFFER_PRODUCER_INFO *info, NvBool isEnabled) 99 { 100 info->isEnabled = isEnabled; 101 } 102 103 void 104 eventBufferSetKeepNewest(EVENT_BUFFER_PRODUCER_INFO *info,NvBool isKeepNewest) 105 { 106 info->isKeepNewest = isKeepNewest; 107 } 108 109 void 110 eventBufferUpdateRecordBufferGet(EVENT_BUFFER_PRODUCER_INFO *info, NvU32 get) 111 { 112 RECORD_BUFFER_INFO* pRecordBuffer = &info->recordBuffer; 113 pRecordBuffer->pHeader->recordGet = get; 114 115 // used for notification 116 _eventBufferUpdateRecordBufferCount(info); 117 118 // dropCounts get reset on every updateGet call 119 pRecordBuffer->pHeader->recordDropcount = 0; 120 pRecordBuffer->pHeader->vardataDropcount = 0; 121 122 } 123 124 void 125 _eventBufferUpdateRecordBufferCount(EVENT_BUFFER_PRODUCER_INFO *info) 126 { 127 RECORD_BUFFER_INFO* pRecordBuffer = &info->recordBuffer; 128 NV_EVENT_BUFFER_HEADER* pHeader = info->recordBuffer.pHeader; 129 130 if (pHeader->recordGet <= pHeader->recordPut) 131 pHeader->recordCount = (pHeader->recordPut - pHeader->recordGet); 132 else 133 pHeader->recordCount = pHeader->recordPut + (pRecordBuffer->totalRecordCount - pHeader->recordGet); 134 } 135 136 void 137 eventBufferUpdateVardataBufferGet(EVENT_BUFFER_PRODUCER_INFO *info, NvU32 get) 138 { 139 VARDATA_BUFFER_INFO* pVardataBuffer = &info->vardataBuffer; 140 pVardataBuffer->get = get; 141 142 _eventBufferUpdateVarRemaingSize(info); 143 } 144 145 NvU32 146 eventBufferGetRecordBufferCount(EVENT_BUFFER_PRODUCER_INFO *info) 147 { 148 return info->recordBuffer.totalRecordCount; 149 } 150 151 NvU32 152 eventBufferGetVardataBufferCount(EVENT_BUFFER_PRODUCER_INFO *info) 153 { 154 return info->vardataBuffer.bufferSize; 155 } 156 157 // 158 // eventBufferProducerAddEvent 159 // 160 // Adds an event to an event buffer 161 // This function is called after acquiring correct locks (depending on which module includes it) 162 // and bound checks for input parameters 163 // eventType : for RM this would be either 2080 subdevice events or 0000 system events 164 // eventSubtype: optional 165 // payloadSize and vardataSize must be 64 bit aligned 166 // 167 void 168 eventBufferProducerAddEvent 169 ( 170 EVENT_BUFFER_PRODUCER_INFO *info, 171 NvU16 eventType, 172 NvU16 eventSubtype, 173 EVENT_BUFFER_PRODUCER_DATA* pData 174 ) 175 { 176 NV_EVENT_BUFFER_RECORD *record; 177 178 if (info->isEnabled) 179 { 180 record = _eventBufferGetFreeRecord(info); 181 if (record) 182 { 183 record->recordHeader.type = eventType; 184 record->recordHeader.subtype = eventSubtype; 185 186 if (pData->payloadSize) 187 portMemCopy(record->inlinePayload, pData->payloadSize, 188 NvP64_VALUE(pData->pPayload), pData->payloadSize); 189 190 _eventBufferAddVardata(info, pData->pVardata, pData->vardataSize, &record->recordHeader); 191 } 192 } 193 } 194 195 NV_EVENT_BUFFER_RECORD* 196 _eventBufferGetFreeRecord(EVENT_BUFFER_PRODUCER_INFO *info) 197 { 198 RECORD_BUFFER_INFO* pRecInfo = &info->recordBuffer; 199 NV_EVENT_BUFFER_HEADER* pHeader = pRecInfo->pHeader; 200 NvU32 recordOffset = 0; 201 NV_EVENT_BUFFER_RECORD* pFreeRecord = NULL; 202 203 NvU32 putNext = pHeader->recordPut + 1; 204 205 if (putNext == pRecInfo->totalRecordCount) 206 putNext = 0; 207 208 if ((!info->isKeepNewest) && (putNext == pHeader->recordGet)) 209 { 210 pHeader->recordDropcount++; 211 } 212 else 213 { 214 recordOffset = pHeader->recordPut * pRecInfo->recordSize; 215 pFreeRecord = (NV_EVENT_BUFFER_RECORD*)((NvUPtr)pRecInfo->recordBuffAddr + recordOffset); 216 217 pHeader->recordCount++; 218 pHeader->recordPut = putNext; 219 } 220 return pFreeRecord; 221 } 222 223 void 224 _eventBufferAddVardata 225 ( 226 EVENT_BUFFER_PRODUCER_INFO *info, 227 NvP64 data, 228 NvU32 size, 229 NV_EVENT_BUFFER_RECORD_HEADER* recordHeader 230 ) 231 { 232 VARDATA_BUFFER_INFO *pVarInfo = &info->vardataBuffer; 233 NV_EVENT_BUFFER_HEADER* pHeader = info->recordBuffer.pHeader; 234 NvU32 pVardataOffset; 235 NvU32 alignedSize = NV_ALIGN_UP(size, NV_EVENT_VARDATA_GRANULARITY); 236 NvU32 vardataOffsetEnd = pVarInfo->put + alignedSize; 237 238 if (vardataOffsetEnd <= pVarInfo->bufferSize) 239 { 240 if ((!info->isKeepNewest) && (pVarInfo->remainingSize < alignedSize)) 241 goto skip; 242 243 pVardataOffset = pVarInfo->put; 244 recordHeader->varData = vardataOffsetEnd; 245 } 246 else 247 { 248 // wrap-around; the effective vardataPut=0, vardataOffsetEnd=size 249 vardataOffsetEnd = 0 + alignedSize; 250 if ((!info->isKeepNewest) && (pVarInfo->get <= vardataOffsetEnd)) 251 goto skip; 252 253 recordHeader->varData = vardataOffsetEnd | NV_EVENT_VARDATA_START_OFFSET_ZERO; 254 pVardataOffset = 0; 255 } 256 257 if(size) 258 { 259 portMemCopy((void*)((NvUPtr)pVarInfo->vardataBuffAddr + pVardataOffset), size, NvP64_VALUE(data), size); 260 261 if (alignedSize != size) 262 { 263 pVardataOffset += size; 264 portMemSet((void*)((NvUPtr)pVarInfo->vardataBuffAddr + pVardataOffset), 0, (alignedSize - size)); 265 } 266 } 267 268 pVarInfo->put = vardataOffsetEnd; 269 _eventBufferUpdateVarRemaingSize(info); 270 return; 271 272 skip: 273 recordHeader->varData = pVarInfo->put; 274 pHeader->vardataDropcount += 1; 275 } 276 277 void 278 _eventBufferUpdateVarRemaingSize(EVENT_BUFFER_PRODUCER_INFO* info) 279 { 280 VARDATA_BUFFER_INFO *pVarInfo = &info->vardataBuffer; 281 282 if (!info->isKeepNewest) 283 { 284 if (pVarInfo->get <= pVarInfo->put) 285 pVarInfo->remainingSize = pVarInfo->get + (pVarInfo->bufferSize - pVarInfo->put); 286 else 287 pVarInfo->remainingSize = pVarInfo->get - pVarInfo->put; 288 } 289 } 290 291 NvBool 292 eventBufferIsNotifyThresholdMet(EVENT_BUFFER_PRODUCER_INFO* info) 293 { 294 VARDATA_BUFFER_INFO *pVarInfo = &info->vardataBuffer; 295 RECORD_BUFFER_INFO* pRecInfo = &info->recordBuffer; 296 NV_EVENT_BUFFER_HEADER* pHeader = pRecInfo->pHeader; 297 298 if (!info->isKeepNewest) 299 { 300 if (((pRecInfo->totalRecordCount - pHeader->recordCount) <= pRecInfo->notificationThreshold) || 301 (pVarInfo->remainingSize <= pVarInfo->notificationThreshold)) 302 { 303 return NV_TRUE; 304 } 305 } 306 return NV_FALSE; 307 } 308 309