1*1739a20eSAndy Ritger /*
2*1739a20eSAndy Ritger  * SPDX-FileCopyrightText: Copyright (c) 1993-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*1739a20eSAndy Ritger  * SPDX-License-Identifier: MIT
4*1739a20eSAndy Ritger  *
5*1739a20eSAndy Ritger  * Permission is hereby granted, free of charge, to any person obtaining a
6*1739a20eSAndy Ritger  * copy of this software and associated documentation files (the "Software"),
7*1739a20eSAndy Ritger  * to deal in the Software without restriction, including without limitation
8*1739a20eSAndy Ritger  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*1739a20eSAndy Ritger  * and/or sell copies of the Software, and to permit persons to whom the
10*1739a20eSAndy Ritger  * Software is furnished to do so, subject to the following conditions:
11*1739a20eSAndy Ritger  *
12*1739a20eSAndy Ritger  * The above copyright notice and this permission notice shall be included in
13*1739a20eSAndy Ritger  * all copies or substantial portions of the Software.
14*1739a20eSAndy Ritger  *
15*1739a20eSAndy Ritger  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*1739a20eSAndy Ritger  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*1739a20eSAndy Ritger  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*1739a20eSAndy Ritger  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*1739a20eSAndy Ritger  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*1739a20eSAndy Ritger  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*1739a20eSAndy Ritger  * DEALINGS IN THE SOFTWARE.
22*1739a20eSAndy Ritger  */
23*1739a20eSAndy Ritger 
24*1739a20eSAndy Ritger /******************************* DisplayPort********************************\
25*1739a20eSAndy Ritger *                                                                           *
26*1739a20eSAndy Ritger * Module: dp_merger.cpp                                                     *
27*1739a20eSAndy Ritger *    Asynchronous Message merger                                            *
28*1739a20eSAndy Ritger *                                                                           *
29*1739a20eSAndy Ritger \***************************************************************************/
30*1739a20eSAndy Ritger 
31*1739a20eSAndy Ritger #include "dp_internal.h"
32*1739a20eSAndy Ritger #include "dp_bitstream.h"
33*1739a20eSAndy Ritger #include "dp_merger.h"
34*1739a20eSAndy Ritger #include "dp_auxdefs.h"
35*1739a20eSAndy Ritger #include "dp_crc.h"
36*1739a20eSAndy Ritger #include "dp_messageheader.h"
37*1739a20eSAndy Ritger 
38*1739a20eSAndy Ritger using namespace DisplayPort;
39*1739a20eSAndy Ritger 
40*1739a20eSAndy Ritger 
pushTransaction(MessageHeader * header,Buffer * data)41*1739a20eSAndy Ritger EncodedMessage * MessageTransactionMerger::pushTransaction(MessageHeader * header, Buffer * data)
42*1739a20eSAndy Ritger {
43*1739a20eSAndy Ritger     if (freeOnNextCall)
44*1739a20eSAndy Ritger     {
45*1739a20eSAndy Ritger         delete freeOnNextCall;
46*1739a20eSAndy Ritger         freeOnNextCall = 0;
47*1739a20eSAndy Ritger     }
48*1739a20eSAndy Ritger 
49*1739a20eSAndy Ritger     IncompleteMessage * imsg = getTransactionRecord(header->address, header->messageNumber);
50*1739a20eSAndy Ritger 
51*1739a20eSAndy Ritger     if (!imsg)
52*1739a20eSAndy Ritger     {
53*1739a20eSAndy Ritger         DP_LOG(("DP-MM> Ignore message due to OOM"));
54*1739a20eSAndy Ritger         return 0;
55*1739a20eSAndy Ritger     }
56*1739a20eSAndy Ritger 
57*1739a20eSAndy Ritger     if (header->isTransactionStart)
58*1739a20eSAndy Ritger     {
59*1739a20eSAndy Ritger         imsg->message.isPathMessage = header->isPathMessage;
60*1739a20eSAndy Ritger         imsg->message.isBroadcast = header->isBroadcast;
61*1739a20eSAndy Ritger     }
62*1739a20eSAndy Ritger     else
63*1739a20eSAndy Ritger     {
64*1739a20eSAndy Ritger         if (imsg->message.buffer.length == 0)
65*1739a20eSAndy Ritger         {
66*1739a20eSAndy Ritger             DP_LOG(("DP-MM> Expected transaction-start, ignoring message transaction"));
67*1739a20eSAndy Ritger             return 0;
68*1739a20eSAndy Ritger         }
69*1739a20eSAndy Ritger 
70*1739a20eSAndy Ritger         if (imsg->message.isPathMessage != header->isPathMessage ||
71*1739a20eSAndy Ritger             imsg->message.isBroadcast != header->isBroadcast)
72*1739a20eSAndy Ritger         {
73*1739a20eSAndy Ritger             DP_ASSERT(0 && "Message type changed during transmission");
74*1739a20eSAndy Ritger         }
75*1739a20eSAndy Ritger     }
76*1739a20eSAndy Ritger 
77*1739a20eSAndy Ritger     //
78*1739a20eSAndy Ritger     //  Check for redundant start
79*1739a20eSAndy Ritger     //
80*1739a20eSAndy Ritger     if (header->isTransactionStart && imsg->message.buffer.length)
81*1739a20eSAndy Ritger     {
82*1739a20eSAndy Ritger         DP_LOG(("DP-MM> Unexpected repeated transaction-start, resetting message state."));
83*1739a20eSAndy Ritger 
84*1739a20eSAndy Ritger         // We must have seen a previous incomplete transaction from this device
85*1739a20eSAndy Ritger         // they've begun a new packet.  Forget about the old thing
86*1739a20eSAndy Ritger         imsg->message.buffer.reset();
87*1739a20eSAndy Ritger     }
88*1739a20eSAndy Ritger 
89*1739a20eSAndy Ritger     //
90*1739a20eSAndy Ritger     //  Kill the buffer if we've got less payload than we should
91*1739a20eSAndy Ritger     //
92*1739a20eSAndy Ritger     if (header->payloadBytes > data->length)
93*1739a20eSAndy Ritger     {
94*1739a20eSAndy Ritger         freeOnNextCall = imsg;
95*1739a20eSAndy Ritger         imsg->message.buffer.reset();
96*1739a20eSAndy Ritger         DP_LOG(("DP-MM> Received truncated or corrupted message transaction"));
97*1739a20eSAndy Ritger         return 0;
98*1739a20eSAndy Ritger     }
99*1739a20eSAndy Ritger 
100*1739a20eSAndy Ritger     //
101*1739a20eSAndy Ritger     //  Verify transaction CRC
102*1739a20eSAndy Ritger     //
103*1739a20eSAndy Ritger     BitStreamReader bsr(data, header->headerSizeBits, (header->payloadBytes-1)*8);
104*1739a20eSAndy Ritger     NvU8 dataCrc = (NvU8)dpCalculateBodyCRC(&bsr);
105*1739a20eSAndy Ritger 
106*1739a20eSAndy Ritger     DP_ASSERT(header->headerSizeBits  % 8 == 0 && "Header must be byte aligned");
107*1739a20eSAndy Ritger 
108*1739a20eSAndy Ritger     if (dataCrc != data->data[header->headerSizeBits/8 + header->payloadBytes - 1] ||
109*1739a20eSAndy Ritger         header->payloadBytes == 0)
110*1739a20eSAndy Ritger     {
111*1739a20eSAndy Ritger         DP_LOG(("DP-MM> Received corruption message transactions"));
112*1739a20eSAndy Ritger         freeOnNextCall = imsg;
113*1739a20eSAndy Ritger         imsg->message.buffer.reset();
114*1739a20eSAndy Ritger         return 0;
115*1739a20eSAndy Ritger     }
116*1739a20eSAndy Ritger 
117*1739a20eSAndy Ritger     // Discount the processed CRC from the payload count
118*1739a20eSAndy Ritger     header->payloadBytes--;
119*1739a20eSAndy Ritger 
120*1739a20eSAndy Ritger     //
121*1739a20eSAndy Ritger     //  Append active buffer
122*1739a20eSAndy Ritger     //
123*1739a20eSAndy Ritger     unsigned i = imsg->message.buffer.length;
124*1739a20eSAndy Ritger     imsg->message.buffer.resize(i + header->payloadBytes);
125*1739a20eSAndy Ritger     dpMemCopy(&imsg->message.buffer.data[i], &data->data[header->headerSizeBits/8], header->payloadBytes);
126*1739a20eSAndy Ritger 
127*1739a20eSAndy Ritger     //
128*1739a20eSAndy Ritger     //  Check for end of message transaction
129*1739a20eSAndy Ritger     //
130*1739a20eSAndy Ritger     if (header->isTransactionEnd)
131*1739a20eSAndy Ritger     {
132*1739a20eSAndy Ritger         freeOnNextCall = imsg;
133*1739a20eSAndy Ritger 
134*1739a20eSAndy Ritger         return &imsg->message;
135*1739a20eSAndy Ritger     }
136*1739a20eSAndy Ritger 
137*1739a20eSAndy Ritger     return 0;
138*1739a20eSAndy Ritger }
139*1739a20eSAndy Ritger 
getTransactionRecord(const Address & address,unsigned messageNumber)140*1739a20eSAndy Ritger MessageTransactionMerger::IncompleteMessage * MessageTransactionMerger::getTransactionRecord(const Address & address, unsigned messageNumber)
141*1739a20eSAndy Ritger {
142*1739a20eSAndy Ritger     IncompleteMessage * msg;
143*1739a20eSAndy Ritger     NvU64 currentTime = this->timer->getTimeUs();
144*1739a20eSAndy Ritger 
145*1739a20eSAndy Ritger     //
146*1739a20eSAndy Ritger     //  Search for existing record
147*1739a20eSAndy Ritger     //
148*1739a20eSAndy Ritger     for (ListElement * i = incompleteMessages.begin();i != incompleteMessages.end();)
149*1739a20eSAndy Ritger     {
150*1739a20eSAndy Ritger         msg = (IncompleteMessage *)i;
151*1739a20eSAndy Ritger         i = i->next;
152*1739a20eSAndy Ritger         if (msg->message.address == address && msg->message.messageNumber == messageNumber)
153*1739a20eSAndy Ritger         {
154*1739a20eSAndy Ritger             goto found;
155*1739a20eSAndy Ritger         }
156*1739a20eSAndy Ritger 
157*1739a20eSAndy Ritger         //
158*1739a20eSAndy Ritger         //  Found a stale message in the list
159*1739a20eSAndy Ritger         //
160*1739a20eSAndy Ritger         if (msg->lastUpdated + incompleteMessageTimeoutMs < currentTime)
161*1739a20eSAndy Ritger             delete msg;
162*1739a20eSAndy Ritger     }
163*1739a20eSAndy Ritger 
164*1739a20eSAndy Ritger     //
165*1739a20eSAndy Ritger     //  None exists? Add a new one
166*1739a20eSAndy Ritger     //
167*1739a20eSAndy Ritger     msg = new IncompleteMessage();
168*1739a20eSAndy Ritger     msg->message.address = address;
169*1739a20eSAndy Ritger     msg->message.messageNumber = messageNumber;
170*1739a20eSAndy Ritger     this->incompleteMessages.insertFront(msg);
171*1739a20eSAndy Ritger 
172*1739a20eSAndy Ritger found:
173*1739a20eSAndy Ritger     //
174*1739a20eSAndy Ritger     //  Update the timestamp
175*1739a20eSAndy Ritger     //
176*1739a20eSAndy Ritger     msg->lastUpdated = currentTime;
177*1739a20eSAndy Ritger 
178*1739a20eSAndy Ritger     return msg;
179*1739a20eSAndy Ritger }
180*1739a20eSAndy Ritger 
mailboxInterrupt()181*1739a20eSAndy Ritger void IncomingTransactionManager::mailboxInterrupt()
182*1739a20eSAndy Ritger {
183*1739a20eSAndy Ritger     MessageHeader msg;
184*1739a20eSAndy Ritger     unsigned totalSize;
185*1739a20eSAndy Ritger     AuxRetry::status result;
186*1739a20eSAndy Ritger     unsigned txSize = (unsigned)getTransactionSize();
187*1739a20eSAndy Ritger 
188*1739a20eSAndy Ritger     //
189*1739a20eSAndy Ritger     //  Size the static aux window
190*1739a20eSAndy Ritger     //
191*1739a20eSAndy Ritger     this->localWindow.resize(DP_MAX((unsigned)getTransactionSize(), (unsigned)getMessageBoxSize()));
192*1739a20eSAndy Ritger     if (this->localWindow.isError())
193*1739a20eSAndy Ritger         return;
194*1739a20eSAndy Ritger 
195*1739a20eSAndy Ritger     //
196*1739a20eSAndy Ritger     //  Read one aux-transaction worth of data
197*1739a20eSAndy Ritger     //
198*1739a20eSAndy Ritger     result = readMessageBox(0, &this->localWindow.data[0], txSize);
199*1739a20eSAndy Ritger 
200*1739a20eSAndy Ritger     DP_ASSERT( result != AuxRetry::defer && "Unexpected?!" );
201*1739a20eSAndy Ritger 
202*1739a20eSAndy Ritger     if (result != AuxRetry::ack)
203*1739a20eSAndy Ritger         return;
204*1739a20eSAndy Ritger 
205*1739a20eSAndy Ritger     BitStreamReader reader(&this->localWindow, 0, 8*txSize);
206*1739a20eSAndy Ritger 
207*1739a20eSAndy Ritger 
208*1739a20eSAndy Ritger     //
209*1739a20eSAndy Ritger     //  Before decoding the header, start with the downstream
210*1739a20eSAndy Ritger     //    ports address prefix
211*1739a20eSAndy Ritger     //
212*1739a20eSAndy Ritger     if (!decodeHeader(&reader, &msg, addressPrefix))
213*1739a20eSAndy Ritger     {
214*1739a20eSAndy Ritger         //
215*1739a20eSAndy Ritger         // It's possible we should be NACKing here.  Ignoring for now
216*1739a20eSAndy Ritger         // to allow the message originator to time out (can take seconds).
217*1739a20eSAndy Ritger         //
218*1739a20eSAndy Ritger         DP_ASSERT(0 && "Not yet implemented");
219*1739a20eSAndy Ritger 
220*1739a20eSAndy Ritger         return;
221*1739a20eSAndy Ritger     }
222*1739a20eSAndy Ritger 
223*1739a20eSAndy Ritger     //
224*1739a20eSAndy Ritger     //  Let's get the entire sideband message in the localWindow
225*1739a20eSAndy Ritger     //
226*1739a20eSAndy Ritger 
227*1739a20eSAndy Ritger     totalSize = (msg.headerSizeBits / 8) + msg.payloadBytes;
228*1739a20eSAndy Ritger 
229*1739a20eSAndy Ritger     if (totalSize > txSize)
230*1739a20eSAndy Ritger     {
231*1739a20eSAndy Ritger         if (totalSize > DPCD_MESSAGEBOX_SIZE)
232*1739a20eSAndy Ritger         {
233*1739a20eSAndy Ritger             //
234*1739a20eSAndy Ritger             //  Corrupt packet - total packet can't be larger than the window
235*1739a20eSAndy Ritger             //
236*1739a20eSAndy Ritger             return;
237*1739a20eSAndy Ritger         }
238*1739a20eSAndy Ritger         if (AuxRetry::ack!=readMessageBox(txSize, &this->localWindow.data[txSize], totalSize - txSize))
239*1739a20eSAndy Ritger         {
240*1739a20eSAndy Ritger             //
241*1739a20eSAndy Ritger             //  Failed to read second half of message
242*1739a20eSAndy Ritger             //
243*1739a20eSAndy Ritger             return;
244*1739a20eSAndy Ritger         }
245*1739a20eSAndy Ritger     }
246*1739a20eSAndy Ritger 
247*1739a20eSAndy Ritger     clearMessageBoxInterrupt();
248*1739a20eSAndy Ritger 
249*1739a20eSAndy Ritger     EncodedMessage * em = incompleteMessages.pushTransaction(&msg, &this->localWindow);
250*1739a20eSAndy Ritger 
251*1739a20eSAndy Ritger     if (em)
252*1739a20eSAndy Ritger     {
253*1739a20eSAndy Ritger         this->sink->messagedReceived(this, em);
254*1739a20eSAndy Ritger     }
255*1739a20eSAndy Ritger }
256*1739a20eSAndy Ritger 
~IncomingTransactionManager()257*1739a20eSAndy Ritger IncomingTransactionManager::~IncomingTransactionManager()
258*1739a20eSAndy Ritger {
259*1739a20eSAndy Ritger }
260*1739a20eSAndy Ritger 
261*1739a20eSAndy Ritger 
IncomingTransactionManager(Timer * timer,const Address & addressPrefix,IncomingTransactionManagerEventSink * sink)262*1739a20eSAndy Ritger IncomingTransactionManager::IncomingTransactionManager(Timer * timer, const Address & addressPrefix, IncomingTransactionManagerEventSink * sink)
263*1739a20eSAndy Ritger     : incompleteMessages(timer, DP_INCOMPLETE_MESSAGE_TIMEOUT_USEC), addressPrefix(addressPrefix)
264*1739a20eSAndy Ritger {
265*1739a20eSAndy Ritger     this->sink = sink;
266*1739a20eSAndy Ritger     this->timer = timer;
267*1739a20eSAndy Ritger }
268*1739a20eSAndy Ritger 
269*1739a20eSAndy Ritger 
270*1739a20eSAndy Ritger 
readMessageBox(NvU32 offset,NvU8 * data,size_t length)271*1739a20eSAndy Ritger AuxRetry::status DownReplyManager::readMessageBox(NvU32 offset, NvU8 * data, size_t length)
272*1739a20eSAndy Ritger {
273*1739a20eSAndy Ritger     return hal->readDownReplyMessageBox(offset, data, length);
274*1739a20eSAndy Ritger }
275*1739a20eSAndy Ritger 
getMessageBoxSize()276*1739a20eSAndy Ritger size_t           DownReplyManager::getMessageBoxSize()
277*1739a20eSAndy Ritger {
278*1739a20eSAndy Ritger     return hal->getDownReplyMessageBoxSize();
279*1739a20eSAndy Ritger }
280*1739a20eSAndy Ritger 
getTransactionSize()281*1739a20eSAndy Ritger size_t           DownReplyManager::getTransactionSize()
282*1739a20eSAndy Ritger {
283*1739a20eSAndy Ritger     return hal->getTransactionSize();
284*1739a20eSAndy Ritger }
285*1739a20eSAndy Ritger 
clearMessageBoxInterrupt()286*1739a20eSAndy Ritger void     DownReplyManager::clearMessageBoxInterrupt()
287*1739a20eSAndy Ritger {
288*1739a20eSAndy Ritger     hal->clearInterruptDownReplyReady();
289*1739a20eSAndy Ritger }
290*1739a20eSAndy Ritger 
readMessageBox(NvU32 offset,NvU8 * data,size_t length)291*1739a20eSAndy Ritger AuxRetry::status UpRequestManager::readMessageBox(NvU32 offset, NvU8 * data, size_t length)
292*1739a20eSAndy Ritger {
293*1739a20eSAndy Ritger     return hal->readUpRequestMessageBox(offset, data, length);
294*1739a20eSAndy Ritger }
295*1739a20eSAndy Ritger 
getMessageBoxSize()296*1739a20eSAndy Ritger size_t           UpRequestManager::getMessageBoxSize()
297*1739a20eSAndy Ritger {
298*1739a20eSAndy Ritger     return hal->getUpRequestMessageBoxSize();
299*1739a20eSAndy Ritger }
300*1739a20eSAndy Ritger 
getTransactionSize()301*1739a20eSAndy Ritger size_t           UpRequestManager::getTransactionSize()
302*1739a20eSAndy Ritger {
303*1739a20eSAndy Ritger     return hal->getTransactionSize();
304*1739a20eSAndy Ritger }
305*1739a20eSAndy Ritger 
clearMessageBoxInterrupt()306*1739a20eSAndy Ritger void     UpRequestManager::clearMessageBoxInterrupt()
307*1739a20eSAndy Ritger {
308*1739a20eSAndy Ritger     hal->clearInterruptUpRequestReady();
309*1739a20eSAndy Ritger }
310*1739a20eSAndy Ritger 
311