PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
iLink_intr.c
1/* iLink_intr.c
2 * Purpose: Contains the functions related to interrupt event management/response, and functions that manage IEEE1394 read/write requests and responses.
3 *
4 * Last Updated: 2012/02/24
5 * Programmer: SP193
6 */
7
8#include <dmacman.h>
9#include <sysmem.h>
10#include <stdio.h>
11#include <thevent.h>
12
13#include "iLinkman.h"
14#include "iLink_internal.h"
15
16extern int IntrEventFlag;
17extern unsigned short int LocalNodeID;
18extern int NodeCapabilities;
19extern int nNodes;
20extern int GenerationNumber;
21extern struct ILINKMemMap *ILINKRegisterBase;
22extern struct DMAChannelRegBlock *iLinkDMACRegs;
23extern void (*CallBackFunction)(int reason, unsigned int offset, unsigned int size);
24
25extern unsigned int *ConfigurationROM;
26extern unsigned int ConfigurationROMSize;
27
28unsigned int *TargetBuffer, NodeData[63];
29unsigned int LocalCachedIntr0Register;
30
31unsigned char IsBusRoot = 1; /* Assume that the console is the root, in case this variable is polled before it was set correctly. */
32
33static void NoResponseHandler(unsigned int header, volatile unsigned int *buffer, unsigned int nQuads)
34{
35 unsigned int i;
36
37 (void)header;
38 (void)buffer;
39
40 DEBUG_PRINTF("NULL response handler called.\n");
41
42 for (i = 0; i < nQuads; i++) { /* Flush the buffer. */
43#ifdef DEBUG_TTY_FEEDBACK
44 unsigned int data;
45 data = *buffer;
46 DEBUG_PRINTF("Unhandled data: 0x%08x.\n", data);
47#endif
48 }
49}
50
51static void PHYPacketHandler(unsigned int header, volatile unsigned int *buffer, unsigned int nQuads)
52{
53 unsigned int data;
54
55 DEBUG_PRINTF("Received PHY packet.\n");
56
57 if (header == PHY_SELF_ID_PACKET) {
58 data = header;
59 nQuads++;
60 while (nQuads-- > 0) {
61 if (data == PHY_SELF_ID_PACKET) {
62 DEBUG_PRINTF("Receiving SELFID packets...\n");
63 nNodes = 0;
64 } else if ((data != 1) && (data != 0xE)) {
65 if ((data >> 30) == 2) { /* SELFID entry. */
66 DEBUG_PRINTF("SELFID received from Node 0x%04x. Speed: 0x%02x. Power: 0x%02x.\n", SELF_ID_NODEID(data), SELF_ID_SPEED(data), SELF_ID_POWER(data));
67 NodeData[nNodes] = data;
68 nNodes++;
69 } else {
70 DEBUG_PRINTF("Unknown quad received in SELF-ID phase: 0x%08x.\n", data);
71 }
72 } else { /* End of SELF ID packet receival. */
73 /* The local node ID should be already valid at this point in execution. */
74 LocalNodeID = ILINKRegisterBase->NodeID >> 16;
75
76 IsBusRoot = (ILINKRegisterBase->ctrl0 & iLink_CTRL0_Root) ? 1 : 0;
77
78 DEBUG_PRINTF("Local Node ID: 0x%04x.\n", LocalNodeID);
79 SetEventFlag(IntrEventFlag, iLinkEventGotSELFIDs);
80 if (CallBackFunction != NULL)
81 CallBackFunction(iLink_CB_BUS_RESET, 0, 0);
82 }
83
84 data = *buffer;
85 }
86 } else if (header == PHY_CONFIG_PACKET) {
87 data = *buffer;
88 /* For monitoring only. It seems like the PHY will automatically configure itself with the data from the PHY packet. */
89 /* if (PHY_CONFIG_R(data))
90 iLinkPHY_SetRootBit(PHY_CONFIG_ROOT_ID(data) == (LocalNodeID & 0x3F));
91 if (PHY_CONFIG_T(data))
92 iLinkPHY_SetGapCount(PHY_CONFIG_GAP_CNT(data)); */
93 if (PHY_CONFIG_T(data)) {
94 DEBUG_PRINTF("gap count: %d.\n", PHY_CONFIG_GAP_CNT(data));
95 }
96 } else {
97 DEBUG_PRINTF("DEBUG: Unknown PHY packet type: 0x%8x.\n", header);
98 NoResponseHandler(header, buffer, nQuads);
99 }
100}
101
102static void ResponseHandler(unsigned int header, volatile unsigned int *buffer, unsigned int nQuads)
103{
104 unsigned int i, HeaderLength;
105 struct ieee1394_TrResponsePacketHdr ResponseData;
106 unsigned char tCode;
107
108 (void)nQuads;
109
110 tCode = (header >> 4) & 0xF;
111
112 HeaderLength = (tCode != IEEE1394_TCODE_WRITE_RESPONSE) ? 4 : 3; /* Write response packets are shorter by other responses by one quadlet! */
113
114 ResponseData.header = header;
115 for (i = 1; i < HeaderLength; i++) {
116 ((unsigned int *)&ResponseData)[i] = *buffer;
117 }
118
119 switch (tCode) {
120 case IEEE1394_TCODE_WRITE_RESPONSE:
121 DEBUG_PRINTF("Data write result: ");
122 break;
123 case IEEE1394_TCODE_READQ_RESPONSE:
124 DEBUG_PRINTF("Writing to buffer %p.\n", TargetBuffer);
125 DEBUG_PRINTF("Quadlet read result: ");
126 *TargetBuffer = BSWAP32(ResponseData.LastField);
127 break;
128 case IEEE1394_TCODE_READB_RESPONSE:
129 DEBUG_PRINTF("Block read result: ");
130 break;
131 default:
132 DEBUG_PRINTF("Unknown IEE1394 transaction type 0x%02x result: ", (ResponseData.header >> 10) & 0x3F);
133 }
134
135 DEBUG_PRINTF("%u.\n", (ResponseData.header2 >> 12) & 0xF);
136 if (tCode == IEEE1394_TCODE_READB_RESPONSE) {
137 DEBUG_PRINTF("data length: 0x%08x.\n", ResponseData.LastField >> 16); /* This refers to the data_legnth field of a block read response packet. */
138 for (i = 0; i < (ResponseData.LastField >> 16); i += 4) {
139 *TargetBuffer = *buffer;
140 TargetBuffer++;
141 }
142 }
143
144 (void)(*buffer); /* Read the last quadlet of the read response that contains only the speed. */
145 SetEventFlag(IntrEventFlag, iLinkEventDataReceived);
146}
147
148static void WriteRequestHandler(unsigned int header, volatile unsigned int *buffer, unsigned int nQuads)
149{
150 struct ieee1394_TrPacketHdr WriteReqHeader;
151 unsigned int QuadsToRead, data;
152 unsigned int i;
153 unsigned char rCode, tLabel;
154
155 (void)nQuads;
156
157 DEBUG_PRINTF("Incoming write request. Header: 0x%08x; Buffer: 0x%p; nQuads: 0x%08x.\n", header, buffer, nQuads);
158 rCode = 0;
159
160 /* Read in the header. */
161 WriteReqHeader.header = header;
162 QuadsToRead = sizeof(struct ieee1394_TrPacketHdr) >> 2;
163 if (((header >> 4) & 0xF) == IEEE1394_TCODE_WRITEQ) {
164 QuadsToRead--; /* Quadlet write requests do not have the data length field. */
165 WriteReqHeader.misc = 4; /* nBytes=4 */
166 DEBUG_PRINTF("Quadlet");
167 } else {
168 DEBUG_PRINTF("Block");
169 }
170
171 for (i = 1; i < QuadsToRead; i++) {
172 data = *buffer;
173 ((unsigned int *)(&WriteReqHeader))[i] = data;
174 }
175
176 WriteReqHeader.misc >>= 16;
177
178 DEBUG_PRINTF(" write request to 0x%08x %08x with length %u.\n", WriteReqHeader.offset_high, WriteReqHeader.offset_low, WriteReqHeader.misc);
179
180 /* Using the information in the header, write the data to the destination. */
181#ifdef REQ_CHECK_MEM_BOUNDARIES
182 if (WriteReqHeader.offset_low < 0x00200000) { /* Make sure that the write request falls within IOP memory. */
183#endif
184 for (i = 0; i < (WriteReqHeader.misc >> 2); i++) {
185 data = *buffer;
186 ((unsigned int *)WriteReqHeader.offset_low)[i] = data;
187 }
188#ifdef REQ_CHECK_MEM_BOUNDARIES
189 } else {
190 DEBUG_PRINTF("Invalid write request.");
191 rCode = 6;
192 }
193#endif
194
195 data = *buffer; /* Read in the last field that contains the speed. */
196
197 tLabel = (header >> 10) & 0x3F;
198 SendResponse(WriteReqHeader.offset_high >> 16, (header >> 16) >> 6, rCode, tLabel, IEEE1394_TCODE_WRITE_RESPONSE, (data >> 16) & 0x7, NULL, 0);
199
200 DEBUG_PRINTF("Response sent.\n");
201
202 if (CallBackFunction != NULL)
203 CallBackFunction(iLink_CB_WRITE_REQUEST, WriteReqHeader.offset_low, WriteReqHeader.misc);
204}
205
207{
208 unsigned int header;
209 unsigned int offset_high;
210 unsigned int offset_low;
211};
212
214{
215 struct ieee1394_TrCommonRdPktHdr header;
216
217 unsigned int nBytes;
218 unsigned int trailer;
219};
220
222{
223 struct ieee1394_TrCommonRdPktHdr header;
224
225 unsigned int trailer;
226};
227
228static void ReadRequestHandler(unsigned int header, volatile unsigned int *buffer, unsigned int nQuads)
229{
230 unsigned int QuadsToRead, offset_low, offset_high, nBytes;
231 unsigned int ReadReqHeader[5];
232 unsigned int i;
233 unsigned short int DestinationNodeID;
234 unsigned char tCode, speed, rCode, tLabel;
235
236 (void)nQuads;
237
238 rCode = 0;
239 DEBUG_PRINTF("Incoming read request. Header: 0x%08x; Buffer: 0x%p; nQuads: 0x%08x.\n", header, buffer, nQuads);
240
241 /* Read in the header. */
242 ReadReqHeader[0] = header;
243 tCode = (header >> 4) & 0xF;
244 if (tCode == IEEE1394_TCODE_READQ) {
245 QuadsToRead = sizeof(struct ieee1394_TrQuadRdPacketHdr) >> 2;
246 DEBUG_PRINTF("Quadlet");
247 } else {
248 QuadsToRead = sizeof(struct ieee1394_TrBlockRdPacketHdr) >> 2;
249 DEBUG_PRINTF("Block");
250 }
251
252 for (i = 1; i < QuadsToRead; i++) {
253 ReadReqHeader[i] = *buffer;
254 }
255
256 if (tCode == IEEE1394_TCODE_READB) {
257 offset_low = BSWAP32(((struct ieee1394_TrCommonRdPktHdr *)ReadReqHeader)->offset_low);
258 offset_high = BSWAP32(((struct ieee1394_TrCommonRdPktHdr *)ReadReqHeader)->offset_high);
259 DestinationNodeID = BSWAP16((unsigned short int)offset_high);
260 } else {
261 offset_low = ((struct ieee1394_TrCommonRdPktHdr *)ReadReqHeader)->offset_low;
262 offset_high = ((struct ieee1394_TrCommonRdPktHdr *)ReadReqHeader)->offset_high;
263 DestinationNodeID = (unsigned short int)(offset_high >> 16);
264 }
265
266 if (tCode == IEEE1394_TCODE_READQ) {
267 nBytes = 4;
268 speed = (((struct ieee1394_TrQuadRdPacketHdr *)ReadReqHeader)->trailer >> 16) & 0x7;
269 } else {
270 nBytes = ((struct ieee1394_TrBlockRdPacketHdr *)ReadReqHeader)->nBytes >> 16;
271 speed = (((struct ieee1394_TrBlockRdPacketHdr *)ReadReqHeader)->trailer >> 16) & 0x7;
272 }
273
274 DEBUG_PRINTF(" read request to 0x%08x %08x with length %u.\n", offset_high, offset_low, nBytes);
275
276#ifdef REQ_CHECK_MEM_BOUNDARIES
277 if (((offset_high & 0x0000FFFF) == 0x0000FFFF) && ((offset_low & 0xF0000000) == 0xF0000000)) {
278#endif
279 offset_low &= 0x0FFFFFFF;
280 if ((offset_low - 0x400) < ConfigurationROMSize) {
281 offset_high = 0;
282 offset_low = (unsigned int)ConfigurationROM + (offset_low - 0x400);
283 }
284#ifdef REQ_CHECK_MEM_BOUNDARIES
285 else {
286 DEBUG_PRINTF("Read request is beyond the range of the configuration ROM.\n");
287 rCode = 6;
288 nBytes = 0;
289 }
290 } else if ((offset_low >= 0x00200000) || (offset_low == 0)) {
291 DEBUG_PRINTF("Invalid read request.");
292 rCode = 6;
293 nBytes = 0;
294 }
295#endif
296
297 tCode = (tCode == IEEE1394_TCODE_READQ) ? IEEE1394_TCODE_READQ_RESPONSE : IEEE1394_TCODE_READB_RESPONSE;
298 tLabel = (header >> 10) & 0x3F;
299 SendResponse(DestinationNodeID, DestinationNodeID >> 6, rCode, tLabel, tCode, speed, (unsigned int *)offset_low, nBytes >> 2);
300
301 DEBUG_PRINTF("Response sent!2.\n");
302
303 if (CallBackFunction != NULL)
304 CallBackFunction(iLink_CB_READ_REQUEST, offset_low, nBytes);
305}
306
307const void *RequestHandlers[] = {
308 &WriteRequestHandler, /* 0: write quadlet */
309 &WriteRequestHandler, /* 1: write block */
310 &ResponseHandler, /* 2: write response */
311 &NoResponseHandler, /* 3: reserved */
312 &ReadRequestHandler, /* 4: read quadlet */
313 &ReadRequestHandler, /* 5: read block */
314 &ResponseHandler, /* 6: read quadlet response */
315 &ResponseHandler, /* 7: read block response */
316 &NoResponseHandler, /* 8: cycle start */
317 &NoResponseHandler, /* 9: lock request */
318 &NoResponseHandler, /* 10: ISO/stream data */
319 &NoResponseHandler, /* 11: lock response */
320 &NoResponseHandler, /* 12: reserved */
321 &NoResponseHandler, /* 13: reserved */
322 &PHYPacketHandler, /* 14: PHY packet */
323 &NoResponseHandler /* 15: reserved */
324};
325
326int iLinkIntrHandler(void *arg)
327{
328 unsigned int LocalCachedIntr1Register, EventFlagBitsToSet;
329#ifdef REQ_CHECK_DMAC_STAT
330 unsigned int i;
331#endif
332
333 (void)arg;
334
335 while (1) {
336 /* Acknowledge interrupts while determining which interrupt events have occurred. Some events need to be acknowledged as early as possible or they will prevent the hardware from working properly. */
337 ILINKRegisterBase->intr0 = LocalCachedIntr0Register = ILINKRegisterBase->intr0 & ILINKRegisterBase->intr0Mask;
338 ILINKRegisterBase->intr1 = LocalCachedIntr1Register = ILINKRegisterBase->intr1 & ILINKRegisterBase->intr1Mask;
339
340 if (!LocalCachedIntr0Register && !LocalCachedIntr1Register)
341 break;
342
343 EventFlagBitsToSet = 0;
344
345 DEBUG_PRINTF("iLink interrupt: 0x%08x 0x%08x\n", LocalCachedIntr0Register, LocalCachedIntr1Register);
346
347 if (LocalCachedIntr1Register & iLink_INTR1_UTD)
348 EventFlagBitsToSet |= iLinkEventDataSent;
349
350#ifdef REQ_CHECK_DMAC_STAT
351 if (LocalCachedIntr0Register & iLink_INTR0_DRFR) {
352 iDEBUG_PRINTF("Handling DBUF FIFO data...\n");
353
354 for (i = 0; i < 3; i++) {
355 iDEBUG_PRINTF("DMA Channel %d CHCR: 0x%08x MADR: 0x%08x DLEN: 0x%05x SLICE: 0x%03x\n", 13 + i, iLinkDMACRegs[i].chcr, iLinkDMACRegs[i].madr, iLinkDMACRegs[i].dlen, iLinkDMACRegs[i].slice);
356
357 if ((i > 0) && !(iLinkDMACRegs[i].chcr & DMAC_CHCR_AR)) {
358 iLinkDMACRegs[i].chcr = 0;
359 switch (i) {
360 case 1:
361 ILINKRegisterBase->dmaCtrlSR0 = 0;
362 break;
363 case 2:
364 ILINKRegisterBase->dmaCtrlSR1 = 0;
365 break;
366 }
367
368 iDEBUG_PRINTF("DMAC Channel %d stalled. Flushing FIFOs and reseting PHTs.\n", 13 + i);
369
370 iLinkInitPHT();
371 }
372 }
373 }
374#endif
375
376 if (LocalCachedIntr0Register & iLink_INTR0_PhyRst) {
377 iDEBUG_PRINTF("-=Bus reset start detected=-\n");
378
379 GenerationNumber++;
380
381 iLinkInitPHT();
382 EventFlagBitsToSet |= (iLinkEventBusReady | iLinkEventBusReset);
383
384 iDEBUG_PRINTF("-=PHTs initialized=-\n");
385 }
386
387 if (LocalCachedIntr0Register & iLink_INTR0_URx) {
388 EventFlagBitsToSet |= iLinkEventURx;
389 }
390
391 if (LocalCachedIntr0Register & (iLink_INTR0_InvAck | iLink_INTR0_RetEx | iLink_INTR0_UResp)) {
392 EventFlagBitsToSet |= iLinkEventError;
393 iDEBUG_PRINTF("-=Missing/invalid response detected=-\n");
394 }
395
396 /* For debugging purposes */
397#ifdef REQ_CHECK_ERRORS
398 if (LocalCachedIntr0Register & iLink_INTR0_HdrErr) {
399 iDEBUG_PRINTF("-=HdrErr=-\n");
400 }
401
402 if (LocalCachedIntr0Register & iLink_INTR0_SntBsyAck) {
403 iDEBUG_PRINTF("-=iLink_INTR0_SntBsyAck=-\n");
404 }
405#endif
406
407 if (LocalCachedIntr0Register & iLink_INTR0_PBCntR) {
408 EventFlagBitsToSet |= iLinkEventDMATransEnd;
409 iDEBUG_PRINTF("-=End of DMA transfer=-\n");
410 }
411
412 if (LocalCachedIntr0Register & iLink_INTR0_CmdRst) {
413 iDEBUG_PRINTF("-=CmdRst=-\n");
414 iLinkPHYBusReset();
415 }
416
417 iSetEventFlag(IntrEventFlag, EventFlagBitsToSet);
418 }
419
420 return 1;
421}