Revision 89b190a2 hw/pcnet.c
b/hw/pcnet.c | ||
---|---|---|
35 | 35 |
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt |
36 | 36 |
*/ |
37 | 37 |
|
38 |
#include <netinet/in.h> |
|
39 |
|
|
38 | 40 |
#include "hw.h" |
39 | 41 |
#include "pci.h" |
40 | 42 |
#include "net.h" |
... | ... | |
52 | 54 |
#define PCNET_IOPORT_SIZE 0x20 |
53 | 55 |
#define PCNET_PNPMMIO_SIZE 0x20 |
54 | 56 |
|
57 |
#define PCNET_LOOPTEST_CRC 1 |
|
58 |
#define PCNET_LOOPTEST_NOCRC 2 |
|
59 |
|
|
55 | 60 |
|
56 | 61 |
typedef struct PCNetState_st PCNetState; |
57 | 62 |
|
... | ... | |
76 | 81 |
void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, |
77 | 82 |
uint8_t *buf, int len, int do_bswap); |
78 | 83 |
void *dma_opaque; |
84 |
int looptest; |
|
79 | 85 |
}; |
80 | 86 |
|
81 | 87 |
struct qemu_ether_header { |
... | ... | |
120 | 126 |
#define CSR_DRX(S) !!(((S)->csr[15])&0x0001) |
121 | 127 |
#define CSR_DTX(S) !!(((S)->csr[15])&0x0002) |
122 | 128 |
#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) |
129 |
#define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008) |
|
123 | 130 |
#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) |
124 | 131 |
#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) |
125 | 132 |
#define CSR_PROM(S) !!(((S)->csr[15])&0x8000) |
... | ... | |
202 | 209 |
#define TMDS_LTINT_SH 12 |
203 | 210 |
#define TMDS_NOFCS_MASK 0x2000 |
204 | 211 |
#define TMDS_NOFCS_SH 13 |
212 |
#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK |
|
213 |
#define TMDS_ADDFCS_SH TMDS_NOFCS_SH |
|
205 | 214 |
#define TMDS_ERR_MASK 0x4000 |
206 | 215 |
#define TMDS_ERR_SH 14 |
207 | 216 |
#define TMDS_OWN_MASK 0x8000 |
... | ... | |
1064 | 1073 |
PCNetState *s = opaque; |
1065 | 1074 |
int is_padr = 0, is_bcast = 0, is_ladr = 0; |
1066 | 1075 |
uint8_t buf1[60]; |
1076 |
int remaining; |
|
1077 |
int crc_err = 0; |
|
1067 | 1078 |
|
1068 | 1079 |
if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) |
1069 | 1080 |
return; |
... | ... | |
1117 | 1128 |
s->csr[0] |= 0x1000; /* Set MISS flag */ |
1118 | 1129 |
CSR_MISSC(s)++; |
1119 | 1130 |
} else { |
1120 |
uint8_t *src = &s->buffer[8];
|
|
1131 |
uint8_t *src = s->buffer;
|
|
1121 | 1132 |
target_phys_addr_t crda = CSR_CRDA(s); |
1122 | 1133 |
struct pcnet_RMD rmd; |
1123 | 1134 |
int pktcount = 0; |
1124 | 1135 |
|
1125 |
memcpy(src, buf, size); |
|
1126 |
|
|
1127 |
#if 1 |
|
1128 |
/* no need to compute the CRC */ |
|
1129 |
src[size] = 0; |
|
1130 |
src[size + 1] = 0; |
|
1131 |
src[size + 2] = 0; |
|
1132 |
src[size + 3] = 0; |
|
1133 |
size += 4; |
|
1134 |
#else |
|
1135 |
/* XXX: avoid CRC generation */ |
|
1136 |
if (!CSR_ASTRP_RCV(s)) { |
|
1136 |
if (!s->looptest) { |
|
1137 |
memcpy(src, buf, size); |
|
1138 |
/* no need to compute the CRC */ |
|
1139 |
src[size] = 0; |
|
1140 |
src[size + 1] = 0; |
|
1141 |
src[size + 2] = 0; |
|
1142 |
src[size + 3] = 0; |
|
1143 |
size += 4; |
|
1144 |
} else if (s->looptest == PCNET_LOOPTEST_CRC || |
|
1145 |
!CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) { |
|
1137 | 1146 |
uint32_t fcs = ~0; |
1138 | 1147 |
uint8_t *p = src; |
1139 | 1148 |
|
1140 |
while (size < 46) { |
|
1141 |
src[size++] = 0; |
|
1142 |
} |
|
1149 |
while (p != &src[size]) |
|
1150 |
CRC(fcs, *p++); |
|
1151 |
*(uint32_t *)p = htonl(fcs); |
|
1152 |
size += 4; |
|
1153 |
} else { |
|
1154 |
uint32_t fcs = ~0; |
|
1155 |
uint8_t *p = src; |
|
1143 | 1156 |
|
1144 |
while (p != &src[size]) {
|
|
1157 |
while (p != &src[size-4])
|
|
1145 | 1158 |
CRC(fcs, *p++); |
1146 |
} |
|
1147 |
((uint32_t *)&src[size])[0] = htonl(fcs); |
|
1148 |
size += 4; /* FCS at end of packet */ |
|
1149 |
} else size += 4; |
|
1150 |
#endif |
|
1159 |
crc_err = (*(uint32_t *)p != htonl(fcs)); |
|
1160 |
} |
|
1151 | 1161 |
|
1152 | 1162 |
#ifdef PCNET_DEBUG_MATCH |
1153 | 1163 |
PRINT_PKTHDR(buf); |
... | ... | |
1158 | 1168 |
SET_FIELD(&rmd.status, RMDS, STP, 1); |
1159 | 1169 |
|
1160 | 1170 |
#define PCNET_RECV_STORE() do { \ |
1161 |
int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \
|
|
1171 |
int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
|
|
1162 | 1172 |
target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ |
1163 | 1173 |
s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ |
1164 |
src += count; size -= count; \ |
|
1165 |
SET_FIELD(&rmd.msg_length, RMDM, MCNT, count); \ |
|
1174 |
src += count; remaining -= count; \ |
|
1166 | 1175 |
SET_FIELD(&rmd.status, RMDS, OWN, 0); \ |
1167 | 1176 |
RMDSTORE(&rmd, PHYSADDR(s,crda)); \ |
1168 | 1177 |
pktcount++; \ |
1169 | 1178 |
} while (0) |
1170 | 1179 |
|
1180 |
remaining = size; |
|
1171 | 1181 |
PCNET_RECV_STORE(); |
1172 |
if ((size > 0) && CSR_NRDA(s)) {
|
|
1182 |
if ((remaining > 0) && CSR_NRDA(s)) {
|
|
1173 | 1183 |
target_phys_addr_t nrda = CSR_NRDA(s); |
1184 |
#ifdef PCNET_DEBUG_RMD |
|
1185 |
PRINT_RMD(&rmd); |
|
1186 |
#endif |
|
1174 | 1187 |
RMDLOAD(&rmd, PHYSADDR(s,nrda)); |
1175 | 1188 |
if (GET_FIELD(rmd.status, RMDS, OWN)) { |
1176 | 1189 |
crda = nrda; |
1177 | 1190 |
PCNET_RECV_STORE(); |
1178 |
if ((size > 0) && (nrda=CSR_NNRD(s))) { |
|
1191 |
#ifdef PCNET_DEBUG_RMD |
|
1192 |
PRINT_RMD(&rmd); |
|
1193 |
#endif |
|
1194 |
if ((remaining > 0) && (nrda=CSR_NNRD(s))) { |
|
1179 | 1195 |
RMDLOAD(&rmd, PHYSADDR(s,nrda)); |
1180 | 1196 |
if (GET_FIELD(rmd.status, RMDS, OWN)) { |
1181 | 1197 |
crda = nrda; |
... | ... | |
1188 | 1204 |
#undef PCNET_RECV_STORE |
1189 | 1205 |
|
1190 | 1206 |
RMDLOAD(&rmd, PHYSADDR(s,crda)); |
1191 |
if (size == 0) { |
|
1207 |
if (remaining == 0) { |
|
1208 |
SET_FIELD(&rmd.msg_length, RMDM, MCNT, size); |
|
1192 | 1209 |
SET_FIELD(&rmd.status, RMDS, ENP, 1); |
1193 | 1210 |
SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr); |
1194 | 1211 |
SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr); |
1195 | 1212 |
SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast); |
1213 |
if (crc_err) { |
|
1214 |
SET_FIELD(&rmd.status, RMDS, CRC, 1); |
|
1215 |
SET_FIELD(&rmd.status, RMDS, ERR, 1); |
|
1216 |
} |
|
1196 | 1217 |
} else { |
1197 | 1218 |
SET_FIELD(&rmd.status, RMDS, OFLO, 1); |
1198 | 1219 |
SET_FIELD(&rmd.status, RMDS, BUFF, 1); |
... | ... | |
1229 | 1250 |
{ |
1230 | 1251 |
target_phys_addr_t xmit_cxda = 0; |
1231 | 1252 |
int count = CSR_XMTRL(s)-1; |
1253 |
int add_crc = 0; |
|
1254 |
|
|
1232 | 1255 |
s->xmit_pos = -1; |
1233 | 1256 |
|
1234 | 1257 |
if (!CSR_TXON(s)) { |
... | ... | |
1251 | 1274 |
if (GET_FIELD(tmd.status, TMDS, STP)) { |
1252 | 1275 |
s->xmit_pos = 0; |
1253 | 1276 |
xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); |
1277 |
if (BCR_SWSTYLE(s) != 1) |
|
1278 |
add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS); |
|
1254 | 1279 |
} |
1255 | 1280 |
if (!GET_FIELD(tmd.status, TMDS, ENP)) { |
1256 | 1281 |
int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); |
... | ... | |
1265 | 1290 |
#ifdef PCNET_DEBUG |
1266 | 1291 |
printf("pcnet_transmit size=%d\n", s->xmit_pos); |
1267 | 1292 |
#endif |
1268 |
if (CSR_LOOP(s)) |
|
1293 |
if (CSR_LOOP(s)) { |
|
1294 |
if (BCR_SWSTYLE(s) == 1) |
|
1295 |
add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); |
|
1296 |
s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; |
|
1269 | 1297 |
pcnet_receive(s, s->buffer, s->xmit_pos); |
1270 |
else |
|
1298 |
s->looptest = 0; |
|
1299 |
} else |
|
1271 | 1300 |
if (s->vc) |
1272 | 1301 |
qemu_send_packet(s->vc, s->buffer, s->xmit_pos); |
1273 | 1302 |
|
Also available in: Unified diff