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