sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
xfer.c
1
2#include <errno.h>
3#include <stdio.h>
4#include <dmacman.h>
5#include <dev9.h>
6#include <intrman.h>
7#include <loadcore.h>
8#include <modload.h>
9#include <stdio.h>
10#include <sysclib.h>
11#include <thbase.h>
12#include <thevent.h>
13#include <thsemap.h>
14#include <irx.h>
15
16#include <smapregs.h>
17#include <speedregs.h>
18
19#include "main.h"
20
21#include "xfer.h"
22#include "ipstack.h"
23
24static int SmapDmaTransfer(volatile u8 *smap_regbase, void *buffer, unsigned int size, int direction)
25{
26 unsigned int NumBlocks;
27 int result;
28
29 (void)smap_regbase;
30
31 /* Non-Sony: the original block size was (32*4 = 128) bytes.
32 However, that resulted in slightly lower performance due to the IOP needing to copy more data. */
33 if ((NumBlocks = size >> 6) > 0) {
34 if (SpdDmaTransfer(1, buffer, NumBlocks << 16 | 0x10, direction) >= 0) {
35 result = NumBlocks << 6;
36 } else
37 result = 0;
38 } else
39 result = 0;
40
41 return result;
42}
43
44static inline void CopyFromFIFO(volatile u8 *smap_regbase, void *buffer, unsigned int length, u16 RxBdPtr)
45{
46 int i, result;
47
48 if (buffer == NULL) {
49 return;
50 }
51
52 SMAP_REG16(SMAP_R_RXFIFO_RD_PTR) = RxBdPtr;
53
54 /* SPD DMA requires a 4-byte aligned destination; fall back to PIO for unaligned buffers. */
55 if (((uiptr)buffer & 3) == 0) {
56 result = SmapDmaTransfer(smap_regbase, buffer, length, DMAC_TO_MEM);
57
58 for (i = result; (unsigned int)i < length; i += 4) {
59 ((u32 *)buffer)[i / 4] = SMAP_REG32(SMAP_R_RXFIFO_DATA);
60 }
61 } else {
62 u8 *p = (u8 *)buffer;
63 for (i = 0; (unsigned int)i < length; i += 4) {
64 u32 v = SMAP_REG32(SMAP_R_RXFIFO_DATA);
65 p[0] = (u8)v;
66 p[1] = (u8)(v >> 8);
67 p[2] = (u8)(v >> 16);
68 p[3] = (u8)(v >> 24);
69 p += 4;
70 }
71 }
72}
73
74static inline void CopyToFIFO(volatile u8 *smap_regbase, const void *buffer, unsigned int length)
75{
76 int i, result;
77
78 if (buffer == NULL) {
79 return;
80 }
81
82 /* SPD DMA requires a 4-byte aligned source, and the PIO loop below does
83 word-sized loads from the buffer. If the pbuf payload is only halfword-
84 aligned (which lwIP 2.2.1 can produce for some TX paths), a plain lw
85 raises an IOP Address Error. Detect that and take an unaligned path. */
86 if (((uiptr)buffer & 3) == 0) {
87 result = SmapDmaTransfer(smap_regbase, (void *)buffer, length, DMAC_FROM_MEM);
88
89 for (i = result; (unsigned int)i < length; i += 4) {
90 SMAP_REG32(SMAP_R_TXFIFO_DATA) = ((u32 *)buffer)[i / 4];
91 }
92 } else {
93 const u8 *p = (const u8 *)buffer;
94 for (i = 0; (unsigned int)i < length; i += 4) {
95 u32 v = (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
96 SMAP_REG32(SMAP_R_TXFIFO_DATA) = v;
97 p += 4;
98 }
99 }
100}
101
102int HandleRxIntr(struct SmapDriverData *SmapDrivPrivData)
103{
104 USE_SMAP_RX_BD;
105 int NumPacketsReceived, i;
106 volatile smap_bd_t *PktBdPtr;
107 // cppcheck-suppress constVariablePointer
108 volatile u8 *smap_regbase;
109 u16 ctrl_stat, length, pointer, LengthRounded;
110
111 smap_regbase = SmapDrivPrivData->smap_regbase;
112
113 NumPacketsReceived = 0;
114
115 /* Non-Sony: Workaround for the hardware BUG whereby the Rx FIFO of the MAL becomes unresponsive or loses frames when under load.
116 Check that there are frames to process, before accessing the BD registers. */
117 while (SMAP_REG8(SMAP_R_RXFIFO_FRAME_CNT) > 0) {
118 PktBdPtr = &rx_bd[SmapDrivPrivData->RxBDIndex % SMAP_BD_MAX_ENTRY];
119 ctrl_stat = PktBdPtr->ctrl_stat;
120 if (!(ctrl_stat & SMAP_BD_RX_EMPTY)) {
121 length = PktBdPtr->length;
122 LengthRounded = (length + 3) & ~3;
123 pointer = PktBdPtr->pointer;
124
126 for (i = 0; i < 16; i++)
127 if ((ctrl_stat >> i) & 1) {
128 SmapDrivPrivData->RuntimeStats.RxErrorCount++;
129#ifdef BUILDING_SMAP_NETDEV
130 SmapDrivPrivData->RuntimeStats_NetDev.m_RxErrorVarious[i] += 1;
131#endif
132 }
133
134 SmapDrivPrivData->RuntimeStats.RxDroppedFrameCount++;
135#ifdef BUILDING_SMAP_NETDEV
136 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Errors += 1;
137#endif
138
139 if (ctrl_stat & SMAP_BD_RX_OVERRUN) {
140 SmapDrivPrivData->RuntimeStats.RxFrameOverrunCount++;
141#ifdef BUILDING_SMAP_NETDEV
142 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Over_Er += 1;
143#endif
144 }
146 SmapDrivPrivData->RuntimeStats.RxFrameBadLengthCount++;
147#ifdef BUILDING_SMAP_NETDEV
148 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Length_Er += 1;
149#endif
150 }
151 if (ctrl_stat & SMAP_BD_RX_BADFCS) {
152 SmapDrivPrivData->RuntimeStats.RxFrameBadFCSCount++;
153#ifdef BUILDING_SMAP_NETDEV
154 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Crc_Er += 1;
155#endif
156 }
157 if (ctrl_stat & SMAP_BD_RX_ALIGNERR) {
158 SmapDrivPrivData->RuntimeStats.RxFrameBadAlignmentCount++;
159#ifdef BUILDING_SMAP_NETDEV
160 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Frame_Er += 1;
161#endif
162 }
163
164 // Original did this whenever a frame is dropped.
165 SMAP_REG16(SMAP_R_RXFIFO_RD_PTR) = pointer + LengthRounded;
166 } else {
167 void *pbuf, *payload;
168
169 if ((pbuf = SMapCommonStackAllocRxPacket(SmapDrivPrivData, LengthRounded, &payload)) != NULL) {
170 CopyFromFIFO(SmapDrivPrivData->smap_regbase, payload, length, pointer);
171#ifdef BUILDING_SMAP_NETDEV
172 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Packets += 1;
173 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Bytes += length;
174 if ((*((u8 *)payload) & 1) != 0) {
175 SmapDrivPrivData->RuntimeStats_NetDev.m_Multicast += 1;
176 if (*(u32 *)payload == (u32)-1 && *((u16 *)payload + 2) == 0xFFFF) {
177 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Broadcast_Packets += 1;
178 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Broadcast_Bytes += length;
179 } else {
180 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Multicast_Packets += 1;
181 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Multicast_Bytes += length;
182 }
183 }
184#endif
185 SMapStackEnQRxPacket(SmapDrivPrivData, pbuf, length);
186 NumPacketsReceived++;
187 } else {
188 SmapDrivPrivData->RuntimeStats.RxAllocFail++;
189#ifdef BUILDING_SMAP_NETDEV
190 SmapDrivPrivData->RuntimeStats_NetDev.m_Rx_Dropped += 1;
191#endif
192 // Original did this whenever a frame is dropped.
193 SMAP_REG16(SMAP_R_RXFIFO_RD_PTR) = pointer + LengthRounded;
194 }
195 }
196
197 SMAP_REG8(SMAP_R_RXFIFO_FRAME_DEC) = 0;
198 PktBdPtr->ctrl_stat = SMAP_BD_RX_EMPTY;
199 SmapDrivPrivData->RxBDIndex++;
200 } else
201 break;
202 }
203
204#ifdef BUILDING_SMAP_NETDEV
205 if (NumPacketsReceived) {
206 SetEventFlag(SmapDrivPrivData->m_devops.evfid, sceInetDevEFP_Recv);
207 }
208#endif
209
210 return NumPacketsReceived;
211}
212
213int HandleTxReqs(struct SmapDriverData *SmapDrivPrivData)
214{
215 int result;
216 void *data;
217 void *pbuf;
218 USE_SMAP_TX_BD;
219 volatile smap_bd_t *BD_ptr;
220 u16 BD_data_ptr;
221 unsigned int SizeRounded;
222 volatile u8 *smap_regbase;
223
224 result = 0;
225 smap_regbase = SmapDrivPrivData->smap_regbase;
226 while (1) {
227 int length;
228
229 data = NULL;
230 if ((length = SMAPCommonTxPacketNext(SmapDrivPrivData, &data, &pbuf)) < 1) {
231 return result;
232 }
233 SmapDrivPrivData->packetToSend = pbuf;
234
235 if (SmapDrivPrivData->NumPacketsInTx >= SMAP_BD_MAX_ENTRY) {
236 return result; // Queue full
237 }
238 SizeRounded = (length + 3) & ~3;
239
240 if (SmapDrivPrivData->TxBufferSpaceAvailable < SizeRounded) {
241 return result; // Out of FIFO space
242 }
243
244#ifdef BUILDING_SMAP_NETDEV
245 if ((*((u8 *)data) & 1) != 0) {
246 if (*(u32 *)data == (u32)-1 && *((u16 *)data + 2) == 0xFFFF) {
247 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Broadcast_Packets += 1;
248 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Broadcast_Bytes += length;
249 } else {
250 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Multicast_Packets += 1;
251 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Multicast_Bytes += length;
252 }
253 }
254#endif
255
256 BD_data_ptr = SMAP_REG16(SMAP_R_TXFIFO_WR_PTR) + SMAP_TX_BASE;
257 BD_ptr = &tx_bd[SmapDrivPrivData->TxBDIndex % SMAP_BD_MAX_ENTRY];
258
259 CopyToFIFO(smap_regbase, data, length);
260
261 result++;
262 BD_ptr->length = length;
263 BD_ptr->pointer = BD_data_ptr;
264 SMAP_REG8(SMAP_R_TXFIFO_FRAME_INC) = 0;
266 SmapDrivPrivData->TxBDIndex++;
267 SmapDrivPrivData->NumPacketsInTx++;
268 SmapDrivPrivData->TxBufferSpaceAvailable -= SizeRounded;
269
270#ifdef BUILDING_SMAP_NETDEV
271 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Bytes += length;
272 SmapDrivPrivData->RuntimeStats_NetDev.m_Tx_Packets += 1;
273#endif
274
275 SmapDrivPrivData->packetToSend = NULL;
276 SMAPCommonTxPacketDeQ(SmapDrivPrivData, &data, &pbuf);
277 }
278}
#define SMAP_BD_RX_OVERRUN
Definition smapregs.h:363
#define SMAP_BD_TX_GENFCS
Definition smapregs.h:316
#define SMAP_BD_RX_BADFCS
Definition smapregs.h:375
#define SMAP_BD_RX_SHORTEVNT
Definition smapregs.h:371
#define SMAP_BD_TX_READY
Definition smapregs.h:314
#define SMAP_BD_RX_EMPTY
Definition smapregs.h:357
#define SMAP_BD_RX_FRMTOOLONG
Definition smapregs.h:377
struct _smap_bd smap_bd_t
#define SMAP_BD_RX_INRANGE
Definition smapregs.h:381
#define SMAP_BD_RX_ALIGNERR
Definition smapregs.h:373
#define SMAP_BD_RX_RUNTFRM
Definition smapregs.h:369
#define SMAP_BD_TX_GENPAD
Definition smapregs.h:318
#define SMAP_BD_RX_OUTRANGE
Definition smapregs.h:379
vu16 length
Definition smapregs.h:291
Definition tcpip.h:234