PS2SDK
PS2 Homebrew Libraries
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 
16 extern int IntrEventFlag;
17 extern unsigned short int LocalNodeID;
18 extern int NodeCapabilities;
19 extern int nNodes;
20 extern int GenerationNumber;
21 extern struct ILINKMemMap *ILINKRegisterBase;
22 extern struct DMAChannelRegBlock *iLinkDMACRegs;
23 extern void (*CallBackFunction)(int reason, unsigned int offset, unsigned int size);
24 
25 extern unsigned int *ConfigurationROM;
26 extern unsigned int ConfigurationROMSize;
27 
28 unsigned int *TargetBuffer, NodeData[63];
29 unsigned int LocalCachedIntr0Register;
30 
31 unsigned char IsBusRoot = 1; /* Assume that the console is the root, in case this variable is polled before it was set correctly. */
32 
33 static 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 
51 static 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 
102 static 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 
148 static 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 
228 static 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 
307 const 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 
326 int 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 }
dmacman.h
ieee1394_TrBlockRdPacketHdr
Definition: iLink_intr.c:213
DMAChannelRegBlock
Definition: iLink_internal.h:258
ieee1394_TrCommonRdPktHdr
Definition: iLink_intr.c:206
ieee1394_TrQuadRdPacketHdr
Definition: iLink_intr.c:221
stdio.h
ILINKMemMap
Definition: iLink_internal.h:158
sysmem.h
ieee1394_TrPacketHdr
Definition: iLink_internal.h:140
ieee1394_TrResponsePacketHdr
Definition: iLink_internal.h:148
thevent.h