|
1 /* |
|
2 * QEMU AMD PC-Net II (Am79C970A) emulation |
|
3 * |
|
4 * Copyright (c) 2004 Antony T Curtis |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 |
|
25 /* This software was written to be compatible with the specification: |
|
26 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet |
|
27 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 |
|
28 */ |
|
29 |
|
30 /* |
|
31 * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also |
|
32 * produced as NCR89C100. See |
|
33 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt |
|
34 * and |
|
35 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt |
|
36 */ |
|
37 |
|
38 #include "hw.h" |
|
39 #include "pci.h" |
|
40 #include "net.h" |
|
41 #include "qemu-timer.h" |
|
42 #include "qemu_socket.h" |
|
43 |
|
44 //#define PCNET_DEBUG |
|
45 //#define PCNET_DEBUG_IO |
|
46 //#define PCNET_DEBUG_BCR |
|
47 //#define PCNET_DEBUG_CSR |
|
48 //#define PCNET_DEBUG_RMD |
|
49 //#define PCNET_DEBUG_TMD |
|
50 //#define PCNET_DEBUG_MATCH |
|
51 |
|
52 |
|
53 #define PCNET_IOPORT_SIZE 0x20 |
|
54 #define PCNET_PNPMMIO_SIZE 0x20 |
|
55 |
|
56 #define PCNET_LOOPTEST_CRC 1 |
|
57 #define PCNET_LOOPTEST_NOCRC 2 |
|
58 |
|
59 |
|
60 typedef struct PCNetState_st PCNetState; |
|
61 |
|
62 struct PCNetState_st { |
|
63 PCIDevice dev; |
|
64 PCIDevice *pci_dev; |
|
65 VLANClientState *vc; |
|
66 NICInfo *nd; |
|
67 QEMUTimer *poll_timer; |
|
68 int mmio_index, rap, isr, lnkst; |
|
69 uint32_t rdra, tdra; |
|
70 uint8_t prom[16]; |
|
71 uint16_t csr[128]; |
|
72 uint16_t bcr[32]; |
|
73 uint64_t timer; |
|
74 int xmit_pos, recv_pos; |
|
75 uint8_t buffer[4096]; |
|
76 int tx_busy; |
|
77 qemu_irq irq; |
|
78 void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, |
|
79 uint8_t *buf, int len, int do_bswap); |
|
80 void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, |
|
81 uint8_t *buf, int len, int do_bswap); |
|
82 void *dma_opaque; |
|
83 int looptest; |
|
84 }; |
|
85 |
|
86 struct qemu_ether_header { |
|
87 uint8_t ether_dhost[6]; |
|
88 uint8_t ether_shost[6]; |
|
89 uint16_t ether_type; |
|
90 }; |
|
91 |
|
92 /* BUS CONFIGURATION REGISTERS */ |
|
93 #define BCR_MSRDA 0 |
|
94 #define BCR_MSWRA 1 |
|
95 #define BCR_MC 2 |
|
96 #define BCR_LNKST 4 |
|
97 #define BCR_LED1 5 |
|
98 #define BCR_LED2 6 |
|
99 #define BCR_LED3 7 |
|
100 #define BCR_FDC 9 |
|
101 #define BCR_BSBC 18 |
|
102 #define BCR_EECAS 19 |
|
103 #define BCR_SWS 20 |
|
104 #define BCR_PLAT 22 |
|
105 |
|
106 #define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) |
|
107 #define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) |
|
108 #define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) |
|
109 |
|
110 #define CSR_INIT(S) !!(((S)->csr[0])&0x0001) |
|
111 #define CSR_STRT(S) !!(((S)->csr[0])&0x0002) |
|
112 #define CSR_STOP(S) !!(((S)->csr[0])&0x0004) |
|
113 #define CSR_TDMD(S) !!(((S)->csr[0])&0x0008) |
|
114 #define CSR_TXON(S) !!(((S)->csr[0])&0x0010) |
|
115 #define CSR_RXON(S) !!(((S)->csr[0])&0x0020) |
|
116 #define CSR_INEA(S) !!(((S)->csr[0])&0x0040) |
|
117 #define CSR_BSWP(S) !!(((S)->csr[3])&0x0004) |
|
118 #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) |
|
119 #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) |
|
120 #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) |
|
121 #define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000) |
|
122 #define CSR_SPND(S) !!(((S)->csr[5])&0x0001) |
|
123 #define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000) |
|
124 #define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000) |
|
125 #define CSR_DRX(S) !!(((S)->csr[15])&0x0001) |
|
126 #define CSR_DTX(S) !!(((S)->csr[15])&0x0002) |
|
127 #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) |
|
128 #define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008) |
|
129 #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) |
|
130 #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) |
|
131 #define CSR_PROM(S) !!(((S)->csr[15])&0x8000) |
|
132 |
|
133 #define CSR_CRBC(S) ((S)->csr[40]) |
|
134 #define CSR_CRST(S) ((S)->csr[41]) |
|
135 #define CSR_CXBC(S) ((S)->csr[42]) |
|
136 #define CSR_CXST(S) ((S)->csr[43]) |
|
137 #define CSR_NRBC(S) ((S)->csr[44]) |
|
138 #define CSR_NRST(S) ((S)->csr[45]) |
|
139 #define CSR_POLL(S) ((S)->csr[46]) |
|
140 #define CSR_PINT(S) ((S)->csr[47]) |
|
141 #define CSR_RCVRC(S) ((S)->csr[72]) |
|
142 #define CSR_XMTRC(S) ((S)->csr[74]) |
|
143 #define CSR_RCVRL(S) ((S)->csr[76]) |
|
144 #define CSR_XMTRL(S) ((S)->csr[78]) |
|
145 #define CSR_MISSC(S) ((S)->csr[112]) |
|
146 |
|
147 #define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) |
|
148 #define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) |
|
149 #define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) |
|
150 #define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) |
|
151 #define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) |
|
152 #define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) |
|
153 #define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) |
|
154 #define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) |
|
155 #define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) |
|
156 #define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) |
|
157 #define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) |
|
158 #define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) |
|
159 #define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) |
|
160 #define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) |
|
161 |
|
162 #define PHYSADDR(S,A) \ |
|
163 (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) |
|
164 |
|
165 struct pcnet_initblk16 { |
|
166 uint16_t mode; |
|
167 uint16_t padr[3]; |
|
168 uint16_t ladrf[4]; |
|
169 uint32_t rdra; |
|
170 uint32_t tdra; |
|
171 }; |
|
172 |
|
173 struct pcnet_initblk32 { |
|
174 uint16_t mode; |
|
175 uint8_t rlen; |
|
176 uint8_t tlen; |
|
177 uint16_t padr[3]; |
|
178 uint16_t _res; |
|
179 uint16_t ladrf[4]; |
|
180 uint32_t rdra; |
|
181 uint32_t tdra; |
|
182 }; |
|
183 |
|
184 struct pcnet_TMD { |
|
185 uint32_t tbadr; |
|
186 int16_t length; |
|
187 int16_t status; |
|
188 uint32_t misc; |
|
189 uint32_t res; |
|
190 }; |
|
191 |
|
192 #define TMDL_BCNT_MASK 0x0fff |
|
193 #define TMDL_BCNT_SH 0 |
|
194 #define TMDL_ONES_MASK 0xf000 |
|
195 #define TMDL_ONES_SH 12 |
|
196 |
|
197 #define TMDS_BPE_MASK 0x0080 |
|
198 #define TMDS_BPE_SH 7 |
|
199 #define TMDS_ENP_MASK 0x0100 |
|
200 #define TMDS_ENP_SH 8 |
|
201 #define TMDS_STP_MASK 0x0200 |
|
202 #define TMDS_STP_SH 9 |
|
203 #define TMDS_DEF_MASK 0x0400 |
|
204 #define TMDS_DEF_SH 10 |
|
205 #define TMDS_ONE_MASK 0x0800 |
|
206 #define TMDS_ONE_SH 11 |
|
207 #define TMDS_LTINT_MASK 0x1000 |
|
208 #define TMDS_LTINT_SH 12 |
|
209 #define TMDS_NOFCS_MASK 0x2000 |
|
210 #define TMDS_NOFCS_SH 13 |
|
211 #define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK |
|
212 #define TMDS_ADDFCS_SH TMDS_NOFCS_SH |
|
213 #define TMDS_ERR_MASK 0x4000 |
|
214 #define TMDS_ERR_SH 14 |
|
215 #define TMDS_OWN_MASK 0x8000 |
|
216 #define TMDS_OWN_SH 15 |
|
217 |
|
218 #define TMDM_TRC_MASK 0x0000000f |
|
219 #define TMDM_TRC_SH 0 |
|
220 #define TMDM_TDR_MASK 0x03ff0000 |
|
221 #define TMDM_TDR_SH 16 |
|
222 #define TMDM_RTRY_MASK 0x04000000 |
|
223 #define TMDM_RTRY_SH 26 |
|
224 #define TMDM_LCAR_MASK 0x08000000 |
|
225 #define TMDM_LCAR_SH 27 |
|
226 #define TMDM_LCOL_MASK 0x10000000 |
|
227 #define TMDM_LCOL_SH 28 |
|
228 #define TMDM_EXDEF_MASK 0x20000000 |
|
229 #define TMDM_EXDEF_SH 29 |
|
230 #define TMDM_UFLO_MASK 0x40000000 |
|
231 #define TMDM_UFLO_SH 30 |
|
232 #define TMDM_BUFF_MASK 0x80000000 |
|
233 #define TMDM_BUFF_SH 31 |
|
234 |
|
235 struct pcnet_RMD { |
|
236 uint32_t rbadr; |
|
237 int16_t buf_length; |
|
238 int16_t status; |
|
239 uint32_t msg_length; |
|
240 uint32_t res; |
|
241 }; |
|
242 |
|
243 #define RMDL_BCNT_MASK 0x0fff |
|
244 #define RMDL_BCNT_SH 0 |
|
245 #define RMDL_ONES_MASK 0xf000 |
|
246 #define RMDL_ONES_SH 12 |
|
247 |
|
248 #define RMDS_BAM_MASK 0x0010 |
|
249 #define RMDS_BAM_SH 4 |
|
250 #define RMDS_LFAM_MASK 0x0020 |
|
251 #define RMDS_LFAM_SH 5 |
|
252 #define RMDS_PAM_MASK 0x0040 |
|
253 #define RMDS_PAM_SH 6 |
|
254 #define RMDS_BPE_MASK 0x0080 |
|
255 #define RMDS_BPE_SH 7 |
|
256 #define RMDS_ENP_MASK 0x0100 |
|
257 #define RMDS_ENP_SH 8 |
|
258 #define RMDS_STP_MASK 0x0200 |
|
259 #define RMDS_STP_SH 9 |
|
260 #define RMDS_BUFF_MASK 0x0400 |
|
261 #define RMDS_BUFF_SH 10 |
|
262 #define RMDS_CRC_MASK 0x0800 |
|
263 #define RMDS_CRC_SH 11 |
|
264 #define RMDS_OFLO_MASK 0x1000 |
|
265 #define RMDS_OFLO_SH 12 |
|
266 #define RMDS_FRAM_MASK 0x2000 |
|
267 #define RMDS_FRAM_SH 13 |
|
268 #define RMDS_ERR_MASK 0x4000 |
|
269 #define RMDS_ERR_SH 14 |
|
270 #define RMDS_OWN_MASK 0x8000 |
|
271 #define RMDS_OWN_SH 15 |
|
272 |
|
273 #define RMDM_MCNT_MASK 0x00000fff |
|
274 #define RMDM_MCNT_SH 0 |
|
275 #define RMDM_ZEROS_MASK 0x0000f000 |
|
276 #define RMDM_ZEROS_SH 12 |
|
277 #define RMDM_RPC_MASK 0x00ff0000 |
|
278 #define RMDM_RPC_SH 16 |
|
279 #define RMDM_RCC_MASK 0xff000000 |
|
280 #define RMDM_RCC_SH 24 |
|
281 |
|
282 #define SET_FIELD(regp, name, field, value) \ |
|
283 (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \ |
|
284 | ((value) << name ## _ ## field ## _SH)) |
|
285 |
|
286 #define GET_FIELD(reg, name, field) \ |
|
287 (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH) |
|
288 |
|
289 #define PRINT_TMD(T) printf( \ |
|
290 "TMD0 : TBADR=0x%08x\n" \ |
|
291 "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ |
|
292 "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ |
|
293 " BPE=%d, BCNT=%d\n" \ |
|
294 "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ |
|
295 "LCA=%d, RTR=%d,\n" \ |
|
296 " TDR=%d, TRC=%d\n", \ |
|
297 (T)->tbadr, \ |
|
298 GET_FIELD((T)->status, TMDS, OWN), \ |
|
299 GET_FIELD((T)->status, TMDS, ERR), \ |
|
300 GET_FIELD((T)->status, TMDS, NOFCS), \ |
|
301 GET_FIELD((T)->status, TMDS, LTINT), \ |
|
302 GET_FIELD((T)->status, TMDS, ONE), \ |
|
303 GET_FIELD((T)->status, TMDS, DEF), \ |
|
304 GET_FIELD((T)->status, TMDS, STP), \ |
|
305 GET_FIELD((T)->status, TMDS, ENP), \ |
|
306 GET_FIELD((T)->status, TMDS, BPE), \ |
|
307 4096-GET_FIELD((T)->length, TMDL, BCNT), \ |
|
308 GET_FIELD((T)->misc, TMDM, BUFF), \ |
|
309 GET_FIELD((T)->misc, TMDM, UFLO), \ |
|
310 GET_FIELD((T)->misc, TMDM, EXDEF), \ |
|
311 GET_FIELD((T)->misc, TMDM, LCOL), \ |
|
312 GET_FIELD((T)->misc, TMDM, LCAR), \ |
|
313 GET_FIELD((T)->misc, TMDM, RTRY), \ |
|
314 GET_FIELD((T)->misc, TMDM, TDR), \ |
|
315 GET_FIELD((T)->misc, TMDM, TRC)) |
|
316 |
|
317 #define PRINT_RMD(R) printf( \ |
|
318 "RMD0 : RBADR=0x%08x\n" \ |
|
319 "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ |
|
320 "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ |
|
321 "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ |
|
322 "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ |
|
323 (R)->rbadr, \ |
|
324 GET_FIELD((R)->status, RMDS, OWN), \ |
|
325 GET_FIELD((R)->status, RMDS, ERR), \ |
|
326 GET_FIELD((R)->status, RMDS, FRAM), \ |
|
327 GET_FIELD((R)->status, RMDS, OFLO), \ |
|
328 GET_FIELD((R)->status, RMDS, CRC), \ |
|
329 GET_FIELD((R)->status, RMDS, BUFF), \ |
|
330 GET_FIELD((R)->status, RMDS, STP), \ |
|
331 GET_FIELD((R)->status, RMDS, ENP), \ |
|
332 GET_FIELD((R)->status, RMDS, BPE), \ |
|
333 GET_FIELD((R)->status, RMDS, PAM), \ |
|
334 GET_FIELD((R)->status, RMDS, LFAM), \ |
|
335 GET_FIELD((R)->status, RMDS, BAM), \ |
|
336 GET_FIELD((R)->buf_length, RMDL, ONES), \ |
|
337 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \ |
|
338 GET_FIELD((R)->msg_length, RMDM, RCC), \ |
|
339 GET_FIELD((R)->msg_length, RMDM, RPC), \ |
|
340 GET_FIELD((R)->msg_length, RMDM, MCNT), \ |
|
341 GET_FIELD((R)->msg_length, RMDM, ZEROS)) |
|
342 |
|
343 static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, |
|
344 target_phys_addr_t addr) |
|
345 { |
|
346 if (!BCR_SSIZE32(s)) { |
|
347 struct { |
|
348 uint32_t tbadr; |
|
349 int16_t length; |
|
350 int16_t status; |
|
351 } xda; |
|
352 s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); |
|
353 tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff; |
|
354 tmd->length = le16_to_cpu(xda.length); |
|
355 tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00; |
|
356 tmd->misc = le16_to_cpu(xda.status) << 16; |
|
357 tmd->res = 0; |
|
358 } else { |
|
359 s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0); |
|
360 le32_to_cpus(&tmd->tbadr); |
|
361 le16_to_cpus((uint16_t *)&tmd->length); |
|
362 le16_to_cpus((uint16_t *)&tmd->status); |
|
363 le32_to_cpus(&tmd->misc); |
|
364 le32_to_cpus(&tmd->res); |
|
365 if (BCR_SWSTYLE(s) == 3) { |
|
366 uint32_t tmp = tmd->tbadr; |
|
367 tmd->tbadr = tmd->misc; |
|
368 tmd->misc = tmp; |
|
369 } |
|
370 } |
|
371 } |
|
372 |
|
373 static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, |
|
374 target_phys_addr_t addr) |
|
375 { |
|
376 if (!BCR_SSIZE32(s)) { |
|
377 struct { |
|
378 uint32_t tbadr; |
|
379 int16_t length; |
|
380 int16_t status; |
|
381 } xda; |
|
382 xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) | |
|
383 ((tmd->status & 0xff00) << 16)); |
|
384 xda.length = cpu_to_le16(tmd->length); |
|
385 xda.status = cpu_to_le16(tmd->misc >> 16); |
|
386 s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); |
|
387 } else { |
|
388 struct { |
|
389 uint32_t tbadr; |
|
390 int16_t length; |
|
391 int16_t status; |
|
392 uint32_t misc; |
|
393 uint32_t res; |
|
394 } xda; |
|
395 xda.tbadr = cpu_to_le32(tmd->tbadr); |
|
396 xda.length = cpu_to_le16(tmd->length); |
|
397 xda.status = cpu_to_le16(tmd->status); |
|
398 xda.misc = cpu_to_le32(tmd->misc); |
|
399 xda.res = cpu_to_le32(tmd->res); |
|
400 if (BCR_SWSTYLE(s) == 3) { |
|
401 uint32_t tmp = xda.tbadr; |
|
402 xda.tbadr = xda.misc; |
|
403 xda.misc = tmp; |
|
404 } |
|
405 s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); |
|
406 } |
|
407 } |
|
408 |
|
409 static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, |
|
410 target_phys_addr_t addr) |
|
411 { |
|
412 if (!BCR_SSIZE32(s)) { |
|
413 struct { |
|
414 uint32_t rbadr; |
|
415 int16_t buf_length; |
|
416 int16_t msg_length; |
|
417 } rda; |
|
418 s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); |
|
419 rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff; |
|
420 rmd->buf_length = le16_to_cpu(rda.buf_length); |
|
421 rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00; |
|
422 rmd->msg_length = le16_to_cpu(rda.msg_length); |
|
423 rmd->res = 0; |
|
424 } else { |
|
425 s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0); |
|
426 le32_to_cpus(&rmd->rbadr); |
|
427 le16_to_cpus((uint16_t *)&rmd->buf_length); |
|
428 le16_to_cpus((uint16_t *)&rmd->status); |
|
429 le32_to_cpus(&rmd->msg_length); |
|
430 le32_to_cpus(&rmd->res); |
|
431 if (BCR_SWSTYLE(s) == 3) { |
|
432 uint32_t tmp = rmd->rbadr; |
|
433 rmd->rbadr = rmd->msg_length; |
|
434 rmd->msg_length = tmp; |
|
435 } |
|
436 } |
|
437 } |
|
438 |
|
439 static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, |
|
440 target_phys_addr_t addr) |
|
441 { |
|
442 if (!BCR_SSIZE32(s)) { |
|
443 struct { |
|
444 uint32_t rbadr; |
|
445 int16_t buf_length; |
|
446 int16_t msg_length; |
|
447 } rda; |
|
448 rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) | |
|
449 ((rmd->status & 0xff00) << 16)); |
|
450 rda.buf_length = cpu_to_le16(rmd->buf_length); |
|
451 rda.msg_length = cpu_to_le16(rmd->msg_length); |
|
452 s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); |
|
453 } else { |
|
454 struct { |
|
455 uint32_t rbadr; |
|
456 int16_t buf_length; |
|
457 int16_t status; |
|
458 uint32_t msg_length; |
|
459 uint32_t res; |
|
460 } rda; |
|
461 rda.rbadr = cpu_to_le32(rmd->rbadr); |
|
462 rda.buf_length = cpu_to_le16(rmd->buf_length); |
|
463 rda.status = cpu_to_le16(rmd->status); |
|
464 rda.msg_length = cpu_to_le32(rmd->msg_length); |
|
465 rda.res = cpu_to_le32(rmd->res); |
|
466 if (BCR_SWSTYLE(s) == 3) { |
|
467 uint32_t tmp = rda.rbadr; |
|
468 rda.rbadr = rda.msg_length; |
|
469 rda.msg_length = tmp; |
|
470 } |
|
471 s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); |
|
472 } |
|
473 } |
|
474 |
|
475 |
|
476 #define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR) |
|
477 |
|
478 #define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR) |
|
479 |
|
480 #define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR) |
|
481 |
|
482 #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) |
|
483 |
|
484 #if 1 |
|
485 |
|
486 #define CHECK_RMD(ADDR,RES) do { \ |
|
487 struct pcnet_RMD rmd; \ |
|
488 RMDLOAD(&rmd,(ADDR)); \ |
|
489 (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \ |
|
490 || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \ |
|
491 } while (0) |
|
492 |
|
493 #define CHECK_TMD(ADDR,RES) do { \ |
|
494 struct pcnet_TMD tmd; \ |
|
495 TMDLOAD(&tmd,(ADDR)); \ |
|
496 (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \ |
|
497 } while (0) |
|
498 |
|
499 #else |
|
500 |
|
501 #define CHECK_RMD(ADDR,RES) do { \ |
|
502 switch (BCR_SWSTYLE(s)) { \ |
|
503 case 0x00: \ |
|
504 do { \ |
|
505 uint16_t rda[4]; \ |
|
506 s->phys_mem_read(s->dma_opaque, (ADDR), \ |
|
507 (void *)&rda[0], sizeof(rda), 0); \ |
|
508 (RES) |= (rda[2] & 0xf000)!=0xf000; \ |
|
509 (RES) |= (rda[3] & 0xf000)!=0x0000; \ |
|
510 } while (0); \ |
|
511 break; \ |
|
512 case 0x01: \ |
|
513 case 0x02: \ |
|
514 do { \ |
|
515 uint32_t rda[4]; \ |
|
516 s->phys_mem_read(s->dma_opaque, (ADDR), \ |
|
517 (void *)&rda[0], sizeof(rda), 0); \ |
|
518 (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ |
|
519 (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ |
|
520 } while (0); \ |
|
521 break; \ |
|
522 case 0x03: \ |
|
523 do { \ |
|
524 uint32_t rda[4]; \ |
|
525 s->phys_mem_read(s->dma_opaque, (ADDR), \ |
|
526 (void *)&rda[0], sizeof(rda), 0); \ |
|
527 (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ |
|
528 (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ |
|
529 } while (0); \ |
|
530 break; \ |
|
531 } \ |
|
532 } while (0) |
|
533 |
|
534 #define CHECK_TMD(ADDR,RES) do { \ |
|
535 switch (BCR_SWSTYLE(s)) { \ |
|
536 case 0x00: \ |
|
537 do { \ |
|
538 uint16_t xda[4]; \ |
|
539 s->phys_mem_read(s->dma_opaque, (ADDR), \ |
|
540 (void *)&xda[0], sizeof(xda), 0); \ |
|
541 (RES) |= (xda[2] & 0xf000)!=0xf000; \ |
|
542 } while (0); \ |
|
543 break; \ |
|
544 case 0x01: \ |
|
545 case 0x02: \ |
|
546 case 0x03: \ |
|
547 do { \ |
|
548 uint32_t xda[4]; \ |
|
549 s->phys_mem_read(s->dma_opaque, (ADDR), \ |
|
550 (void *)&xda[0], sizeof(xda), 0); \ |
|
551 (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ |
|
552 } while (0); \ |
|
553 break; \ |
|
554 } \ |
|
555 } while (0) |
|
556 |
|
557 #endif |
|
558 |
|
559 #define PRINT_PKTHDR(BUF) do { \ |
|
560 struct qemu_ether_header *hdr = (void *)(BUF); \ |
|
561 printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ |
|
562 "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ |
|
563 "type=0x%04x\n", \ |
|
564 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ |
|
565 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ |
|
566 hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ |
|
567 hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ |
|
568 be16_to_cpu(hdr->ether_type)); \ |
|
569 } while (0) |
|
570 |
|
571 #define MULTICAST_FILTER_LEN 8 |
|
572 |
|
573 static inline uint32_t lnc_mchash(const uint8_t *ether_addr) |
|
574 { |
|
575 #define LNC_POLYNOMIAL 0xEDB88320UL |
|
576 uint32_t crc = 0xFFFFFFFF; |
|
577 int idx, bit; |
|
578 uint8_t data; |
|
579 |
|
580 for (idx = 0; idx < 6; idx++) { |
|
581 for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { |
|
582 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); |
|
583 data >>= 1; |
|
584 } |
|
585 } |
|
586 return crc; |
|
587 #undef LNC_POLYNOMIAL |
|
588 } |
|
589 |
|
590 #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) |
|
591 |
|
592 /* generated using the AUTODIN II polynomial |
|
593 * x^32 + x^26 + x^23 + x^22 + x^16 + |
|
594 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 |
|
595 */ |
|
596 static const uint32_t crctab[256] = { |
|
597 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, |
|
598 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, |
|
599 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, |
|
600 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, |
|
601 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, |
|
602 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, |
|
603 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, |
|
604 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, |
|
605 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, |
|
606 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, |
|
607 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, |
|
608 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, |
|
609 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, |
|
610 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, |
|
611 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
|
612 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, |
|
613 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, |
|
614 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, |
|
615 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, |
|
616 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, |
|
617 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, |
|
618 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, |
|
619 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, |
|
620 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, |
|
621 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, |
|
622 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, |
|
623 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, |
|
624 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, |
|
625 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, |
|
626 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
|
627 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, |
|
628 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, |
|
629 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, |
|
630 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, |
|
631 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, |
|
632 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, |
|
633 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, |
|
634 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, |
|
635 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, |
|
636 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, |
|
637 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, |
|
638 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, |
|
639 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, |
|
640 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, |
|
641 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
|
642 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, |
|
643 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, |
|
644 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, |
|
645 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, |
|
646 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, |
|
647 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, |
|
648 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, |
|
649 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, |
|
650 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, |
|
651 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, |
|
652 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, |
|
653 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, |
|
654 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, |
|
655 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, |
|
656 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
|
657 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, |
|
658 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, |
|
659 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, |
|
660 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, |
|
661 }; |
|
662 |
|
663 static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) |
|
664 { |
|
665 struct qemu_ether_header *hdr = (void *)buf; |
|
666 uint8_t padr[6] = { |
|
667 s->csr[12] & 0xff, s->csr[12] >> 8, |
|
668 s->csr[13] & 0xff, s->csr[13] >> 8, |
|
669 s->csr[14] & 0xff, s->csr[14] >> 8 |
|
670 }; |
|
671 int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); |
|
672 #ifdef PCNET_DEBUG_MATCH |
|
673 printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " |
|
674 "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", |
|
675 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], |
|
676 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], |
|
677 padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]); |
|
678 printf("padr_match result=%d\n", result); |
|
679 #endif |
|
680 return result; |
|
681 } |
|
682 |
|
683 static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) |
|
684 { |
|
685 static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
|
686 struct qemu_ether_header *hdr = (void *)buf; |
|
687 int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); |
|
688 #ifdef PCNET_DEBUG_MATCH |
|
689 printf("padr_bcast result=%d\n", result); |
|
690 #endif |
|
691 return result; |
|
692 } |
|
693 |
|
694 static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) |
|
695 { |
|
696 struct qemu_ether_header *hdr = (void *)buf; |
|
697 if ((*(hdr->ether_dhost)&0x01) && |
|
698 ((uint64_t *)&s->csr[8])[0] != 0LL) { |
|
699 uint8_t ladr[8] = { |
|
700 s->csr[8] & 0xff, s->csr[8] >> 8, |
|
701 s->csr[9] & 0xff, s->csr[9] >> 8, |
|
702 s->csr[10] & 0xff, s->csr[10] >> 8, |
|
703 s->csr[11] & 0xff, s->csr[11] >> 8 |
|
704 }; |
|
705 int index = lnc_mchash(hdr->ether_dhost) >> 26; |
|
706 return !!(ladr[index >> 3] & (1 << (index & 7))); |
|
707 } |
|
708 return 0; |
|
709 } |
|
710 |
|
711 static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) |
|
712 { |
|
713 while (idx < 1) idx += CSR_RCVRL(s); |
|
714 return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); |
|
715 } |
|
716 |
|
717 static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) |
|
718 { |
|
719 int64_t next_time = current_time + |
|
720 muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), |
|
721 ticks_per_sec, 33000000L); |
|
722 if (next_time <= current_time) |
|
723 next_time = current_time + 1; |
|
724 return next_time; |
|
725 } |
|
726 |
|
727 static void pcnet_poll(PCNetState *s); |
|
728 static void pcnet_poll_timer(void *opaque); |
|
729 |
|
730 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); |
|
731 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); |
|
732 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); |
|
733 static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); |
|
734 |
|
735 static void pcnet_s_reset(PCNetState *s) |
|
736 { |
|
737 #ifdef PCNET_DEBUG |
|
738 printf("pcnet_s_reset\n"); |
|
739 #endif |
|
740 |
|
741 s->lnkst = 0x40; |
|
742 s->rdra = 0; |
|
743 s->tdra = 0; |
|
744 s->rap = 0; |
|
745 |
|
746 s->bcr[BCR_BSBC] &= ~0x0080; |
|
747 |
|
748 s->csr[0] = 0x0004; |
|
749 s->csr[3] = 0x0000; |
|
750 s->csr[4] = 0x0115; |
|
751 s->csr[5] = 0x0000; |
|
752 s->csr[6] = 0x0000; |
|
753 s->csr[8] = 0; |
|
754 s->csr[9] = 0; |
|
755 s->csr[10] = 0; |
|
756 s->csr[11] = 0; |
|
757 s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]); |
|
758 s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]); |
|
759 s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]); |
|
760 s->csr[15] &= 0x21c4; |
|
761 s->csr[72] = 1; |
|
762 s->csr[74] = 1; |
|
763 s->csr[76] = 1; |
|
764 s->csr[78] = 1; |
|
765 s->csr[80] = 0x1410; |
|
766 s->csr[88] = 0x1003; |
|
767 s->csr[89] = 0x0262; |
|
768 s->csr[94] = 0x0000; |
|
769 s->csr[100] = 0x0200; |
|
770 s->csr[103] = 0x0105; |
|
771 s->csr[103] = 0x0105; |
|
772 s->csr[112] = 0x0000; |
|
773 s->csr[114] = 0x0000; |
|
774 s->csr[122] = 0x0000; |
|
775 s->csr[124] = 0x0000; |
|
776 |
|
777 s->tx_busy = 0; |
|
778 } |
|
779 |
|
780 static void pcnet_update_irq(PCNetState *s) |
|
781 { |
|
782 int isr = 0; |
|
783 s->csr[0] &= ~0x0080; |
|
784 |
|
785 #if 1 |
|
786 if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || |
|
787 (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || |
|
788 (((s->csr[5]>>1) & s->csr[5]) & 0x0048)) |
|
789 #else |
|
790 if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ || |
|
791 (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ || |
|
792 (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ || |
|
793 (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ || |
|
794 (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ || |
|
795 (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ || |
|
796 (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ || |
|
797 (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ || |
|
798 (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ || |
|
799 (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ || |
|
800 (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ || |
|
801 (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) |
|
802 #endif |
|
803 { |
|
804 |
|
805 isr = CSR_INEA(s); |
|
806 s->csr[0] |= 0x0080; |
|
807 } |
|
808 |
|
809 if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ |
|
810 s->csr[4] &= ~0x0080; |
|
811 s->csr[4] |= 0x0040; |
|
812 s->csr[0] |= 0x0080; |
|
813 isr = 1; |
|
814 #ifdef PCNET_DEBUG |
|
815 printf("pcnet user int\n"); |
|
816 #endif |
|
817 } |
|
818 |
|
819 #if 1 |
|
820 if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) |
|
821 #else |
|
822 if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || |
|
823 (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) |
|
824 #endif |
|
825 { |
|
826 isr = 1; |
|
827 s->csr[0] |= 0x0080; |
|
828 } |
|
829 |
|
830 if (isr != s->isr) { |
|
831 #ifdef PCNET_DEBUG |
|
832 printf("pcnet: INTA=%d\n", isr); |
|
833 #endif |
|
834 } |
|
835 qemu_set_irq(s->irq, isr); |
|
836 s->isr = isr; |
|
837 } |
|
838 |
|
839 static void pcnet_init(PCNetState *s) |
|
840 { |
|
841 int rlen, tlen; |
|
842 uint16_t padr[3], ladrf[4], mode; |
|
843 uint32_t rdra, tdra; |
|
844 |
|
845 #ifdef PCNET_DEBUG |
|
846 printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); |
|
847 #endif |
|
848 |
|
849 if (BCR_SSIZE32(s)) { |
|
850 struct pcnet_initblk32 initblk; |
|
851 s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), |
|
852 (uint8_t *)&initblk, sizeof(initblk), 0); |
|
853 mode = le16_to_cpu(initblk.mode); |
|
854 rlen = initblk.rlen >> 4; |
|
855 tlen = initblk.tlen >> 4; |
|
856 ladrf[0] = le16_to_cpu(initblk.ladrf[0]); |
|
857 ladrf[1] = le16_to_cpu(initblk.ladrf[1]); |
|
858 ladrf[2] = le16_to_cpu(initblk.ladrf[2]); |
|
859 ladrf[3] = le16_to_cpu(initblk.ladrf[3]); |
|
860 padr[0] = le16_to_cpu(initblk.padr[0]); |
|
861 padr[1] = le16_to_cpu(initblk.padr[1]); |
|
862 padr[2] = le16_to_cpu(initblk.padr[2]); |
|
863 rdra = le32_to_cpu(initblk.rdra); |
|
864 tdra = le32_to_cpu(initblk.tdra); |
|
865 } else { |
|
866 struct pcnet_initblk16 initblk; |
|
867 s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), |
|
868 (uint8_t *)&initblk, sizeof(initblk), 0); |
|
869 mode = le16_to_cpu(initblk.mode); |
|
870 ladrf[0] = le16_to_cpu(initblk.ladrf[0]); |
|
871 ladrf[1] = le16_to_cpu(initblk.ladrf[1]); |
|
872 ladrf[2] = le16_to_cpu(initblk.ladrf[2]); |
|
873 ladrf[3] = le16_to_cpu(initblk.ladrf[3]); |
|
874 padr[0] = le16_to_cpu(initblk.padr[0]); |
|
875 padr[1] = le16_to_cpu(initblk.padr[1]); |
|
876 padr[2] = le16_to_cpu(initblk.padr[2]); |
|
877 rdra = le32_to_cpu(initblk.rdra); |
|
878 tdra = le32_to_cpu(initblk.tdra); |
|
879 rlen = rdra >> 29; |
|
880 tlen = tdra >> 29; |
|
881 rdra &= 0x00ffffff; |
|
882 tdra &= 0x00ffffff; |
|
883 } |
|
884 |
|
885 #if defined(PCNET_DEBUG) |
|
886 printf("rlen=%d tlen=%d\n", rlen, tlen); |
|
887 #endif |
|
888 |
|
889 CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; |
|
890 CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; |
|
891 s->csr[ 6] = (tlen << 12) | (rlen << 8); |
|
892 s->csr[15] = mode; |
|
893 s->csr[ 8] = ladrf[0]; |
|
894 s->csr[ 9] = ladrf[1]; |
|
895 s->csr[10] = ladrf[2]; |
|
896 s->csr[11] = ladrf[3]; |
|
897 s->csr[12] = padr[0]; |
|
898 s->csr[13] = padr[1]; |
|
899 s->csr[14] = padr[2]; |
|
900 s->rdra = PHYSADDR(s, rdra); |
|
901 s->tdra = PHYSADDR(s, tdra); |
|
902 |
|
903 CSR_RCVRC(s) = CSR_RCVRL(s); |
|
904 CSR_XMTRC(s) = CSR_XMTRL(s); |
|
905 |
|
906 #ifdef PCNET_DEBUG |
|
907 printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", |
|
908 BCR_SSIZE32(s), |
|
909 s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); |
|
910 #endif |
|
911 |
|
912 s->csr[0] |= 0x0101; |
|
913 s->csr[0] &= ~0x0004; /* clear STOP bit */ |
|
914 } |
|
915 |
|
916 static void pcnet_start(PCNetState *s) |
|
917 { |
|
918 #ifdef PCNET_DEBUG |
|
919 printf("pcnet_start\n"); |
|
920 #endif |
|
921 |
|
922 if (!CSR_DTX(s)) |
|
923 s->csr[0] |= 0x0010; /* set TXON */ |
|
924 |
|
925 if (!CSR_DRX(s)) |
|
926 s->csr[0] |= 0x0020; /* set RXON */ |
|
927 |
|
928 s->csr[0] &= ~0x0004; /* clear STOP bit */ |
|
929 s->csr[0] |= 0x0002; |
|
930 } |
|
931 |
|
932 static void pcnet_stop(PCNetState *s) |
|
933 { |
|
934 #ifdef PCNET_DEBUG |
|
935 printf("pcnet_stop\n"); |
|
936 #endif |
|
937 s->csr[0] &= ~0x7feb; |
|
938 s->csr[0] |= 0x0014; |
|
939 s->csr[4] &= ~0x02c2; |
|
940 s->csr[5] &= ~0x0011; |
|
941 pcnet_poll_timer(s); |
|
942 } |
|
943 |
|
944 static void pcnet_rdte_poll(PCNetState *s) |
|
945 { |
|
946 s->csr[28] = s->csr[29] = 0; |
|
947 if (s->rdra) { |
|
948 int bad = 0; |
|
949 #if 1 |
|
950 target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); |
|
951 target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); |
|
952 target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); |
|
953 #else |
|
954 target_phys_addr_t crda = s->rdra + |
|
955 (CSR_RCVRL(s) - CSR_RCVRC(s)) * |
|
956 (BCR_SWSTYLE(s) ? 16 : 8 ); |
|
957 int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; |
|
958 target_phys_addr_t nrda = s->rdra + |
|
959 (CSR_RCVRL(s) - nrdc) * |
|
960 (BCR_SWSTYLE(s) ? 16 : 8 ); |
|
961 int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; |
|
962 target_phys_addr_t nnrd = s->rdra + |
|
963 (CSR_RCVRL(s) - nnrc) * |
|
964 (BCR_SWSTYLE(s) ? 16 : 8 ); |
|
965 #endif |
|
966 |
|
967 CHECK_RMD(PHYSADDR(s,crda), bad); |
|
968 if (!bad) { |
|
969 CHECK_RMD(PHYSADDR(s,nrda), bad); |
|
970 if (bad || (nrda == crda)) nrda = 0; |
|
971 CHECK_RMD(PHYSADDR(s,nnrd), bad); |
|
972 if (bad || (nnrd == crda)) nnrd = 0; |
|
973 |
|
974 s->csr[28] = crda & 0xffff; |
|
975 s->csr[29] = crda >> 16; |
|
976 s->csr[26] = nrda & 0xffff; |
|
977 s->csr[27] = nrda >> 16; |
|
978 s->csr[36] = nnrd & 0xffff; |
|
979 s->csr[37] = nnrd >> 16; |
|
980 #ifdef PCNET_DEBUG |
|
981 if (bad) { |
|
982 printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n", |
|
983 PHYSADDR(s,crda)); |
|
984 } |
|
985 } else { |
|
986 printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n", |
|
987 PHYSADDR(s,crda)); |
|
988 #endif |
|
989 } |
|
990 } |
|
991 |
|
992 if (CSR_CRDA(s)) { |
|
993 struct pcnet_RMD rmd; |
|
994 RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); |
|
995 CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); |
|
996 CSR_CRST(s) = rmd.status; |
|
997 #ifdef PCNET_DEBUG_RMD_X |
|
998 printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n", |
|
999 PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), |
|
1000 rmd.buf_length, rmd.status, rmd.msg_length); |
|
1001 PRINT_RMD(&rmd); |
|
1002 #endif |
|
1003 } else { |
|
1004 CSR_CRBC(s) = CSR_CRST(s) = 0; |
|
1005 } |
|
1006 |
|
1007 if (CSR_NRDA(s)) { |
|
1008 struct pcnet_RMD rmd; |
|
1009 RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); |
|
1010 CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); |
|
1011 CSR_NRST(s) = rmd.status; |
|
1012 } else { |
|
1013 CSR_NRBC(s) = CSR_NRST(s) = 0; |
|
1014 } |
|
1015 |
|
1016 } |
|
1017 |
|
1018 static int pcnet_tdte_poll(PCNetState *s) |
|
1019 { |
|
1020 s->csr[34] = s->csr[35] = 0; |
|
1021 if (s->tdra) { |
|
1022 target_phys_addr_t cxda = s->tdra + |
|
1023 (CSR_XMTRL(s) - CSR_XMTRC(s)) * |
|
1024 (BCR_SWSTYLE(s) ? 16 : 8); |
|
1025 int bad = 0; |
|
1026 CHECK_TMD(PHYSADDR(s, cxda),bad); |
|
1027 if (!bad) { |
|
1028 if (CSR_CXDA(s) != cxda) { |
|
1029 s->csr[60] = s->csr[34]; |
|
1030 s->csr[61] = s->csr[35]; |
|
1031 s->csr[62] = CSR_CXBC(s); |
|
1032 s->csr[63] = CSR_CXST(s); |
|
1033 } |
|
1034 s->csr[34] = cxda & 0xffff; |
|
1035 s->csr[35] = cxda >> 16; |
|
1036 #ifdef PCNET_DEBUG_X |
|
1037 printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); |
|
1038 #endif |
|
1039 } |
|
1040 } |
|
1041 |
|
1042 if (CSR_CXDA(s)) { |
|
1043 struct pcnet_TMD tmd; |
|
1044 |
|
1045 TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); |
|
1046 |
|
1047 CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT); |
|
1048 CSR_CXST(s) = tmd.status; |
|
1049 } else { |
|
1050 CSR_CXBC(s) = CSR_CXST(s) = 0; |
|
1051 } |
|
1052 |
|
1053 return !!(CSR_CXST(s) & 0x8000); |
|
1054 } |
|
1055 |
|
1056 static int pcnet_can_receive(void *opaque) |
|
1057 { |
|
1058 PCNetState *s = opaque; |
|
1059 if (CSR_STOP(s) || CSR_SPND(s)) |
|
1060 return 0; |
|
1061 |
|
1062 if (s->recv_pos > 0) |
|
1063 return 0; |
|
1064 |
|
1065 return sizeof(s->buffer)-16; |
|
1066 } |
|
1067 |
|
1068 #define MIN_BUF_SIZE 60 |
|
1069 |
|
1070 static void pcnet_receive(void *opaque, const uint8_t *buf, int size) |
|
1071 { |
|
1072 PCNetState *s = opaque; |
|
1073 int is_padr = 0, is_bcast = 0, is_ladr = 0; |
|
1074 uint8_t buf1[60]; |
|
1075 int remaining; |
|
1076 int crc_err = 0; |
|
1077 |
|
1078 if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) |
|
1079 return; |
|
1080 |
|
1081 #ifdef PCNET_DEBUG |
|
1082 printf("pcnet_receive size=%d\n", size); |
|
1083 #endif |
|
1084 |
|
1085 /* if too small buffer, then expand it */ |
|
1086 if (size < MIN_BUF_SIZE) { |
|
1087 memcpy(buf1, buf, size); |
|
1088 memset(buf1 + size, 0, MIN_BUF_SIZE - size); |
|
1089 buf = buf1; |
|
1090 size = MIN_BUF_SIZE; |
|
1091 } |
|
1092 |
|
1093 if (CSR_PROM(s) |
|
1094 || (is_padr=padr_match(s, buf, size)) |
|
1095 || (is_bcast=padr_bcast(s, buf, size)) |
|
1096 || (is_ladr=ladr_match(s, buf, size))) { |
|
1097 |
|
1098 pcnet_rdte_poll(s); |
|
1099 |
|
1100 if (!(CSR_CRST(s) & 0x8000) && s->rdra) { |
|
1101 struct pcnet_RMD rmd; |
|
1102 int rcvrc = CSR_RCVRC(s)-1,i; |
|
1103 target_phys_addr_t nrda; |
|
1104 for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { |
|
1105 if (rcvrc <= 1) |
|
1106 rcvrc = CSR_RCVRL(s); |
|
1107 nrda = s->rdra + |
|
1108 (CSR_RCVRL(s) - rcvrc) * |
|
1109 (BCR_SWSTYLE(s) ? 16 : 8 ); |
|
1110 RMDLOAD(&rmd, PHYSADDR(s,nrda)); |
|
1111 if (GET_FIELD(rmd.status, RMDS, OWN)) { |
|
1112 #ifdef PCNET_DEBUG_RMD |
|
1113 printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", |
|
1114 rcvrc, CSR_RCVRC(s)); |
|
1115 #endif |
|
1116 CSR_RCVRC(s) = rcvrc; |
|
1117 pcnet_rdte_poll(s); |
|
1118 break; |
|
1119 } |
|
1120 } |
|
1121 } |
|
1122 |
|
1123 if (!(CSR_CRST(s) & 0x8000)) { |
|
1124 #ifdef PCNET_DEBUG_RMD |
|
1125 printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); |
|
1126 #endif |
|
1127 s->csr[0] |= 0x1000; /* Set MISS flag */ |
|
1128 CSR_MISSC(s)++; |
|
1129 } else { |
|
1130 uint8_t *src = s->buffer; |
|
1131 target_phys_addr_t crda = CSR_CRDA(s); |
|
1132 struct pcnet_RMD rmd; |
|
1133 int pktcount = 0; |
|
1134 |
|
1135 if (!s->looptest) { |
|
1136 memcpy(src, buf, size); |
|
1137 /* no need to compute the CRC */ |
|
1138 src[size] = 0; |
|
1139 src[size + 1] = 0; |
|
1140 src[size + 2] = 0; |
|
1141 src[size + 3] = 0; |
|
1142 size += 4; |
|
1143 } else if (s->looptest == PCNET_LOOPTEST_CRC || |
|
1144 !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) { |
|
1145 uint32_t fcs = ~0; |
|
1146 uint8_t *p = src; |
|
1147 |
|
1148 while (p != &src[size]) |
|
1149 CRC(fcs, *p++); |
|
1150 *(uint32_t *)p = htonl(fcs); |
|
1151 size += 4; |
|
1152 } else { |
|
1153 uint32_t fcs = ~0; |
|
1154 uint8_t *p = src; |
|
1155 |
|
1156 while (p != &src[size-4]) |
|
1157 CRC(fcs, *p++); |
|
1158 crc_err = (*(uint32_t *)p != htonl(fcs)); |
|
1159 } |
|
1160 |
|
1161 #ifdef PCNET_DEBUG_MATCH |
|
1162 PRINT_PKTHDR(buf); |
|
1163 #endif |
|
1164 |
|
1165 RMDLOAD(&rmd, PHYSADDR(s,crda)); |
|
1166 /*if (!CSR_LAPPEN(s))*/ |
|
1167 SET_FIELD(&rmd.status, RMDS, STP, 1); |
|
1168 |
|
1169 #define PCNET_RECV_STORE() do { \ |
|
1170 int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \ |
|
1171 target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ |
|
1172 s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ |
|
1173 src += count; remaining -= count; \ |
|
1174 SET_FIELD(&rmd.status, RMDS, OWN, 0); \ |
|
1175 RMDSTORE(&rmd, PHYSADDR(s,crda)); \ |
|
1176 pktcount++; \ |
|
1177 } while (0) |
|
1178 |
|
1179 remaining = size; |
|
1180 PCNET_RECV_STORE(); |
|
1181 if ((remaining > 0) && CSR_NRDA(s)) { |
|
1182 target_phys_addr_t nrda = CSR_NRDA(s); |
|
1183 #ifdef PCNET_DEBUG_RMD |
|
1184 PRINT_RMD(&rmd); |
|
1185 #endif |
|
1186 RMDLOAD(&rmd, PHYSADDR(s,nrda)); |
|
1187 if (GET_FIELD(rmd.status, RMDS, OWN)) { |
|
1188 crda = nrda; |
|
1189 PCNET_RECV_STORE(); |
|
1190 #ifdef PCNET_DEBUG_RMD |
|
1191 PRINT_RMD(&rmd); |
|
1192 #endif |
|
1193 if ((remaining > 0) && (nrda=CSR_NNRD(s))) { |
|
1194 RMDLOAD(&rmd, PHYSADDR(s,nrda)); |
|
1195 if (GET_FIELD(rmd.status, RMDS, OWN)) { |
|
1196 crda = nrda; |
|
1197 PCNET_RECV_STORE(); |
|
1198 } |
|
1199 } |
|
1200 } |
|
1201 } |
|
1202 |
|
1203 #undef PCNET_RECV_STORE |
|
1204 |
|
1205 RMDLOAD(&rmd, PHYSADDR(s,crda)); |
|
1206 if (remaining == 0) { |
|
1207 SET_FIELD(&rmd.msg_length, RMDM, MCNT, size); |
|
1208 SET_FIELD(&rmd.status, RMDS, ENP, 1); |
|
1209 SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr); |
|
1210 SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr); |
|
1211 SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast); |
|
1212 if (crc_err) { |
|
1213 SET_FIELD(&rmd.status, RMDS, CRC, 1); |
|
1214 SET_FIELD(&rmd.status, RMDS, ERR, 1); |
|
1215 } |
|
1216 } else { |
|
1217 SET_FIELD(&rmd.status, RMDS, OFLO, 1); |
|
1218 SET_FIELD(&rmd.status, RMDS, BUFF, 1); |
|
1219 SET_FIELD(&rmd.status, RMDS, ERR, 1); |
|
1220 } |
|
1221 RMDSTORE(&rmd, PHYSADDR(s,crda)); |
|
1222 s->csr[0] |= 0x0400; |
|
1223 |
|
1224 #ifdef PCNET_DEBUG |
|
1225 printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", |
|
1226 CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); |
|
1227 #endif |
|
1228 #ifdef PCNET_DEBUG_RMD |
|
1229 PRINT_RMD(&rmd); |
|
1230 #endif |
|
1231 |
|
1232 while (pktcount--) { |
|
1233 if (CSR_RCVRC(s) <= 1) |
|
1234 CSR_RCVRC(s) = CSR_RCVRL(s); |
|
1235 else |
|
1236 CSR_RCVRC(s)--; |
|
1237 } |
|
1238 |
|
1239 pcnet_rdte_poll(s); |
|
1240 |
|
1241 } |
|
1242 } |
|
1243 |
|
1244 pcnet_poll(s); |
|
1245 pcnet_update_irq(s); |
|
1246 } |
|
1247 |
|
1248 static void pcnet_transmit(PCNetState *s) |
|
1249 { |
|
1250 target_phys_addr_t xmit_cxda = 0; |
|
1251 int count = CSR_XMTRL(s)-1; |
|
1252 int add_crc = 0; |
|
1253 |
|
1254 s->xmit_pos = -1; |
|
1255 |
|
1256 if (!CSR_TXON(s)) { |
|
1257 s->csr[0] &= ~0x0008; |
|
1258 return; |
|
1259 } |
|
1260 |
|
1261 s->tx_busy = 1; |
|
1262 |
|
1263 txagain: |
|
1264 if (pcnet_tdte_poll(s)) { |
|
1265 struct pcnet_TMD tmd; |
|
1266 |
|
1267 TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); |
|
1268 |
|
1269 #ifdef PCNET_DEBUG_TMD |
|
1270 printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); |
|
1271 PRINT_TMD(&tmd); |
|
1272 #endif |
|
1273 if (GET_FIELD(tmd.status, TMDS, STP)) { |
|
1274 s->xmit_pos = 0; |
|
1275 xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); |
|
1276 if (BCR_SWSTYLE(s) != 1) |
|
1277 add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS); |
|
1278 } |
|
1279 if (!GET_FIELD(tmd.status, TMDS, ENP)) { |
|
1280 int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); |
|
1281 s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), |
|
1282 s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); |
|
1283 s->xmit_pos += bcnt; |
|
1284 } else if (s->xmit_pos >= 0) { |
|
1285 int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); |
|
1286 s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), |
|
1287 s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); |
|
1288 s->xmit_pos += bcnt; |
|
1289 #ifdef PCNET_DEBUG |
|
1290 printf("pcnet_transmit size=%d\n", s->xmit_pos); |
|
1291 #endif |
|
1292 if (CSR_LOOP(s)) { |
|
1293 if (BCR_SWSTYLE(s) == 1) |
|
1294 add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); |
|
1295 s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; |
|
1296 pcnet_receive(s, s->buffer, s->xmit_pos); |
|
1297 s->looptest = 0; |
|
1298 } else |
|
1299 if (s->vc) |
|
1300 qemu_send_packet(s->vc, s->buffer, s->xmit_pos); |
|
1301 |
|
1302 s->csr[0] &= ~0x0008; /* clear TDMD */ |
|
1303 s->csr[4] |= 0x0004; /* set TXSTRT */ |
|
1304 s->xmit_pos = -1; |
|
1305 } |
|
1306 |
|
1307 SET_FIELD(&tmd.status, TMDS, OWN, 0); |
|
1308 TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); |
|
1309 if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT))) |
|
1310 s->csr[0] |= 0x0200; /* set TINT */ |
|
1311 |
|
1312 if (CSR_XMTRC(s)<=1) |
|
1313 CSR_XMTRC(s) = CSR_XMTRL(s); |
|
1314 else |
|
1315 CSR_XMTRC(s)--; |
|
1316 if (count--) |
|
1317 goto txagain; |
|
1318 |
|
1319 } else |
|
1320 if (s->xmit_pos >= 0) { |
|
1321 struct pcnet_TMD tmd; |
|
1322 TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); |
|
1323 SET_FIELD(&tmd.misc, TMDM, BUFF, 1); |
|
1324 SET_FIELD(&tmd.misc, TMDM, UFLO, 1); |
|
1325 SET_FIELD(&tmd.status, TMDS, ERR, 1); |
|
1326 SET_FIELD(&tmd.status, TMDS, OWN, 0); |
|
1327 TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); |
|
1328 s->csr[0] |= 0x0200; /* set TINT */ |
|
1329 if (!CSR_DXSUFLO(s)) { |
|
1330 s->csr[0] &= ~0x0010; |
|
1331 } else |
|
1332 if (count--) |
|
1333 goto txagain; |
|
1334 } |
|
1335 |
|
1336 s->tx_busy = 0; |
|
1337 } |
|
1338 |
|
1339 static void pcnet_poll(PCNetState *s) |
|
1340 { |
|
1341 if (CSR_RXON(s)) { |
|
1342 pcnet_rdte_poll(s); |
|
1343 } |
|
1344 |
|
1345 if (CSR_TDMD(s) || |
|
1346 (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) |
|
1347 { |
|
1348 /* prevent recursion */ |
|
1349 if (s->tx_busy) |
|
1350 return; |
|
1351 |
|
1352 pcnet_transmit(s); |
|
1353 } |
|
1354 } |
|
1355 |
|
1356 static void pcnet_poll_timer(void *opaque) |
|
1357 { |
|
1358 PCNetState *s = opaque; |
|
1359 |
|
1360 qemu_del_timer(s->poll_timer); |
|
1361 |
|
1362 if (CSR_TDMD(s)) { |
|
1363 pcnet_transmit(s); |
|
1364 } |
|
1365 |
|
1366 pcnet_update_irq(s); |
|
1367 |
|
1368 if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { |
|
1369 uint64_t now = qemu_get_clock(vm_clock) * 33; |
|
1370 if (!s->timer || !now) |
|
1371 s->timer = now; |
|
1372 else { |
|
1373 uint64_t t = now - s->timer + CSR_POLL(s); |
|
1374 if (t > 0xffffLL) { |
|
1375 pcnet_poll(s); |
|
1376 CSR_POLL(s) = CSR_PINT(s); |
|
1377 } else |
|
1378 CSR_POLL(s) = t; |
|
1379 } |
|
1380 qemu_mod_timer(s->poll_timer, |
|
1381 pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); |
|
1382 } |
|
1383 } |
|
1384 |
|
1385 |
|
1386 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) |
|
1387 { |
|
1388 uint16_t val = new_value; |
|
1389 #ifdef PCNET_DEBUG_CSR |
|
1390 printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val); |
|
1391 #endif |
|
1392 switch (rap) { |
|
1393 case 0: |
|
1394 s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ |
|
1395 |
|
1396 s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); |
|
1397 |
|
1398 val = (val & 0x007f) | (s->csr[0] & 0x7f00); |
|
1399 |
|
1400 /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ |
|
1401 if ((val&7) == 7) |
|
1402 val &= ~3; |
|
1403 |
|
1404 if (!CSR_STOP(s) && (val & 4)) |
|
1405 pcnet_stop(s); |
|
1406 |
|
1407 if (!CSR_INIT(s) && (val & 1)) |
|
1408 pcnet_init(s); |
|
1409 |
|
1410 if (!CSR_STRT(s) && (val & 2)) |
|
1411 pcnet_start(s); |
|
1412 |
|
1413 if (CSR_TDMD(s)) |
|
1414 pcnet_transmit(s); |
|
1415 |
|
1416 return; |
|
1417 case 1: |
|
1418 case 2: |
|
1419 case 8: |
|
1420 case 9: |
|
1421 case 10: |
|
1422 case 11: |
|
1423 case 12: |
|
1424 case 13: |
|
1425 case 14: |
|
1426 case 15: |
|
1427 case 18: /* CRBAL */ |
|
1428 case 19: /* CRBAU */ |
|
1429 case 20: /* CXBAL */ |
|
1430 case 21: /* CXBAU */ |
|
1431 case 22: /* NRBAU */ |
|
1432 case 23: /* NRBAU */ |
|
1433 case 24: |
|
1434 case 25: |
|
1435 case 26: |
|
1436 case 27: |
|
1437 case 28: |
|
1438 case 29: |
|
1439 case 30: |
|
1440 case 31: |
|
1441 case 32: |
|
1442 case 33: |
|
1443 case 34: |
|
1444 case 35: |
|
1445 case 36: |
|
1446 case 37: |
|
1447 case 38: |
|
1448 case 39: |
|
1449 case 40: /* CRBC */ |
|
1450 case 41: |
|
1451 case 42: /* CXBC */ |
|
1452 case 43: |
|
1453 case 44: |
|
1454 case 45: |
|
1455 case 46: /* POLL */ |
|
1456 case 47: /* POLLINT */ |
|
1457 case 72: |
|
1458 case 74: |
|
1459 case 76: /* RCVRL */ |
|
1460 case 78: /* XMTRL */ |
|
1461 case 112: |
|
1462 if (CSR_STOP(s) || CSR_SPND(s)) |
|
1463 break; |
|
1464 return; |
|
1465 case 3: |
|
1466 break; |
|
1467 case 4: |
|
1468 s->csr[4] &= ~(val & 0x026a); |
|
1469 val &= ~0x026a; val |= s->csr[4] & 0x026a; |
|
1470 break; |
|
1471 case 5: |
|
1472 s->csr[5] &= ~(val & 0x0a90); |
|
1473 val &= ~0x0a90; val |= s->csr[5] & 0x0a90; |
|
1474 break; |
|
1475 case 16: |
|
1476 pcnet_csr_writew(s,1,val); |
|
1477 return; |
|
1478 case 17: |
|
1479 pcnet_csr_writew(s,2,val); |
|
1480 return; |
|
1481 case 58: |
|
1482 pcnet_bcr_writew(s,BCR_SWS,val); |
|
1483 break; |
|
1484 default: |
|
1485 return; |
|
1486 } |
|
1487 s->csr[rap] = val; |
|
1488 } |
|
1489 |
|
1490 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap) |
|
1491 { |
|
1492 uint32_t val; |
|
1493 switch (rap) { |
|
1494 case 0: |
|
1495 pcnet_update_irq(s); |
|
1496 val = s->csr[0]; |
|
1497 val |= (val & 0x7800) ? 0x8000 : 0; |
|
1498 break; |
|
1499 case 16: |
|
1500 return pcnet_csr_readw(s,1); |
|
1501 case 17: |
|
1502 return pcnet_csr_readw(s,2); |
|
1503 case 58: |
|
1504 return pcnet_bcr_readw(s,BCR_SWS); |
|
1505 case 88: |
|
1506 val = s->csr[89]; |
|
1507 val <<= 16; |
|
1508 val |= s->csr[88]; |
|
1509 break; |
|
1510 default: |
|
1511 val = s->csr[rap]; |
|
1512 } |
|
1513 #ifdef PCNET_DEBUG_CSR |
|
1514 printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val); |
|
1515 #endif |
|
1516 return val; |
|
1517 } |
|
1518 |
|
1519 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) |
|
1520 { |
|
1521 rap &= 127; |
|
1522 #ifdef PCNET_DEBUG_BCR |
|
1523 printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val); |
|
1524 #endif |
|
1525 switch (rap) { |
|
1526 case BCR_SWS: |
|
1527 if (!(CSR_STOP(s) || CSR_SPND(s))) |
|
1528 return; |
|
1529 val &= ~0x0300; |
|
1530 switch (val & 0x00ff) { |
|
1531 case 0: |
|
1532 val |= 0x0200; |
|
1533 break; |
|
1534 case 1: |
|
1535 val |= 0x0100; |
|
1536 break; |
|
1537 case 2: |
|
1538 case 3: |
|
1539 val |= 0x0300; |
|
1540 break; |
|
1541 default: |
|
1542 printf("Bad SWSTYLE=0x%02x\n", val & 0xff); |
|
1543 val = 0x0200; |
|
1544 break; |
|
1545 } |
|
1546 #ifdef PCNET_DEBUG |
|
1547 printf("BCR_SWS=0x%04x\n", val); |
|
1548 #endif |
|
1549 case BCR_LNKST: |
|
1550 case BCR_LED1: |
|
1551 case BCR_LED2: |
|
1552 case BCR_LED3: |
|
1553 case BCR_MC: |
|
1554 case BCR_FDC: |
|
1555 case BCR_BSBC: |
|
1556 case BCR_EECAS: |
|
1557 case BCR_PLAT: |
|
1558 s->bcr[rap] = val; |
|
1559 break; |
|
1560 default: |
|
1561 break; |
|
1562 } |
|
1563 } |
|
1564 |
|
1565 static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) |
|
1566 { |
|
1567 uint32_t val; |
|
1568 rap &= 127; |
|
1569 switch (rap) { |
|
1570 case BCR_LNKST: |
|
1571 case BCR_LED1: |
|
1572 case BCR_LED2: |
|
1573 case BCR_LED3: |
|
1574 val = s->bcr[rap] & ~0x8000; |
|
1575 val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; |
|
1576 break; |
|
1577 default: |
|
1578 val = rap < 32 ? s->bcr[rap] : 0; |
|
1579 break; |
|
1580 } |
|
1581 #ifdef PCNET_DEBUG_BCR |
|
1582 printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); |
|
1583 #endif |
|
1584 return val; |
|
1585 } |
|
1586 |
|
1587 static void pcnet_h_reset(void *opaque) |
|
1588 { |
|
1589 PCNetState *s = opaque; |
|
1590 int i; |
|
1591 uint16_t checksum; |
|
1592 |
|
1593 /* Initialize the PROM */ |
|
1594 |
|
1595 if (s->nd) |
|
1596 memcpy(s->prom, s->nd->macaddr, 6); |
|
1597 s->prom[12] = s->prom[13] = 0x00; |
|
1598 s->prom[14] = s->prom[15] = 0x57; |
|
1599 |
|
1600 for (i = 0,checksum = 0; i < 16; i++) |
|
1601 checksum += s->prom[i]; |
|
1602 *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); |
|
1603 |
|
1604 |
|
1605 s->bcr[BCR_MSRDA] = 0x0005; |
|
1606 s->bcr[BCR_MSWRA] = 0x0005; |
|
1607 s->bcr[BCR_MC ] = 0x0002; |
|
1608 s->bcr[BCR_LNKST] = 0x00c0; |
|
1609 s->bcr[BCR_LED1 ] = 0x0084; |
|
1610 s->bcr[BCR_LED2 ] = 0x0088; |
|
1611 s->bcr[BCR_LED3 ] = 0x0090; |
|
1612 s->bcr[BCR_FDC ] = 0x0000; |
|
1613 s->bcr[BCR_BSBC ] = 0x9001; |
|
1614 s->bcr[BCR_EECAS] = 0x0002; |
|
1615 s->bcr[BCR_SWS ] = 0x0200; |
|
1616 s->bcr[BCR_PLAT ] = 0xff06; |
|
1617 |
|
1618 pcnet_s_reset(s); |
|
1619 } |
|
1620 |
|
1621 static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) |
|
1622 { |
|
1623 PCNetState *s = opaque; |
|
1624 #ifdef PCNET_DEBUG |
|
1625 printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); |
|
1626 #endif |
|
1627 /* Check APROMWE bit to enable write access */ |
|
1628 if (pcnet_bcr_readw(s,2) & 0x80) |
|
1629 s->prom[addr & 15] = val; |
|
1630 } |
|
1631 |
|
1632 static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) |
|
1633 { |
|
1634 PCNetState *s = opaque; |
|
1635 uint32_t val = s->prom[addr &= 15]; |
|
1636 #ifdef PCNET_DEBUG |
|
1637 printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); |
|
1638 #endif |
|
1639 return val; |
|
1640 } |
|
1641 |
|
1642 static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) |
|
1643 { |
|
1644 PCNetState *s = opaque; |
|
1645 pcnet_poll_timer(s); |
|
1646 #ifdef PCNET_DEBUG_IO |
|
1647 printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val); |
|
1648 #endif |
|
1649 if (!BCR_DWIO(s)) { |
|
1650 switch (addr & 0x0f) { |
|
1651 case 0x00: /* RDP */ |
|
1652 pcnet_csr_writew(s, s->rap, val); |
|
1653 break; |
|
1654 case 0x02: |
|
1655 s->rap = val & 0x7f; |
|
1656 break; |
|
1657 case 0x06: |
|
1658 pcnet_bcr_writew(s, s->rap, val); |
|
1659 break; |
|
1660 } |
|
1661 } |
|
1662 pcnet_update_irq(s); |
|
1663 } |
|
1664 |
|
1665 static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) |
|
1666 { |
|
1667 PCNetState *s = opaque; |
|
1668 uint32_t val = -1; |
|
1669 pcnet_poll_timer(s); |
|
1670 if (!BCR_DWIO(s)) { |
|
1671 switch (addr & 0x0f) { |
|
1672 case 0x00: /* RDP */ |
|
1673 val = pcnet_csr_readw(s, s->rap); |
|
1674 break; |
|
1675 case 0x02: |
|
1676 val = s->rap; |
|
1677 break; |
|
1678 case 0x04: |
|
1679 pcnet_s_reset(s); |
|
1680 val = 0; |
|
1681 break; |
|
1682 case 0x06: |
|
1683 val = pcnet_bcr_readw(s, s->rap); |
|
1684 break; |
|
1685 } |
|
1686 } |
|
1687 pcnet_update_irq(s); |
|
1688 #ifdef PCNET_DEBUG_IO |
|
1689 printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff); |
|
1690 #endif |
|
1691 return val; |
|
1692 } |
|
1693 |
|
1694 static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) |
|
1695 { |
|
1696 PCNetState *s = opaque; |
|
1697 pcnet_poll_timer(s); |
|
1698 #ifdef PCNET_DEBUG_IO |
|
1699 printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val); |
|
1700 #endif |
|
1701 if (BCR_DWIO(s)) { |
|
1702 switch (addr & 0x0f) { |
|
1703 case 0x00: /* RDP */ |
|
1704 pcnet_csr_writew(s, s->rap, val & 0xffff); |
|
1705 break; |
|
1706 case 0x04: |
|
1707 s->rap = val & 0x7f; |
|
1708 break; |
|
1709 case 0x0c: |
|
1710 pcnet_bcr_writew(s, s->rap, val & 0xffff); |
|
1711 break; |
|
1712 } |
|
1713 } else |
|
1714 if ((addr & 0x0f) == 0) { |
|
1715 /* switch device to dword i/o mode */ |
|
1716 pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); |
|
1717 #ifdef PCNET_DEBUG_IO |
|
1718 printf("device switched into dword i/o mode\n"); |
|
1719 #endif |
|
1720 } |
|
1721 pcnet_update_irq(s); |
|
1722 } |
|
1723 |
|
1724 static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) |
|
1725 { |
|
1726 PCNetState *s = opaque; |
|
1727 uint32_t val = -1; |
|
1728 pcnet_poll_timer(s); |
|
1729 if (BCR_DWIO(s)) { |
|
1730 switch (addr & 0x0f) { |
|
1731 case 0x00: /* RDP */ |
|
1732 val = pcnet_csr_readw(s, s->rap); |
|
1733 break; |
|
1734 case 0x04: |
|
1735 val = s->rap; |
|
1736 break; |
|
1737 case 0x08: |
|
1738 pcnet_s_reset(s); |
|
1739 val = 0; |
|
1740 break; |
|
1741 case 0x0c: |
|
1742 val = pcnet_bcr_readw(s, s->rap); |
|
1743 break; |
|
1744 } |
|
1745 } |
|
1746 pcnet_update_irq(s); |
|
1747 #ifdef PCNET_DEBUG_IO |
|
1748 printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val); |
|
1749 #endif |
|
1750 return val; |
|
1751 } |
|
1752 |
|
1753 static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, |
|
1754 uint32_t addr, uint32_t size, int type) |
|
1755 { |
|
1756 PCNetState *d = (PCNetState *)pci_dev; |
|
1757 |
|
1758 #ifdef PCNET_DEBUG_IO |
|
1759 printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); |
|
1760 #endif |
|
1761 |
|
1762 register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); |
|
1763 register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); |
|
1764 |
|
1765 register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); |
|
1766 register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); |
|
1767 register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); |
|
1768 register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); |
|
1769 } |
|
1770 |
|
1771 static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1772 { |
|
1773 PCNetState *d = opaque; |
|
1774 #ifdef PCNET_DEBUG_IO |
|
1775 printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, |
|
1776 val); |
|
1777 #endif |
|
1778 if (!(addr & 0x10)) |
|
1779 pcnet_aprom_writeb(d, addr & 0x0f, val); |
|
1780 } |
|
1781 |
|
1782 static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) |
|
1783 { |
|
1784 PCNetState *d = opaque; |
|
1785 uint32_t val = -1; |
|
1786 if (!(addr & 0x10)) |
|
1787 val = pcnet_aprom_readb(d, addr & 0x0f); |
|
1788 #ifdef PCNET_DEBUG_IO |
|
1789 printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, |
|
1790 val & 0xff); |
|
1791 #endif |
|
1792 return val; |
|
1793 } |
|
1794 |
|
1795 static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1796 { |
|
1797 PCNetState *d = opaque; |
|
1798 #ifdef PCNET_DEBUG_IO |
|
1799 printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, |
|
1800 val); |
|
1801 #endif |
|
1802 if (addr & 0x10) |
|
1803 pcnet_ioport_writew(d, addr & 0x0f, val); |
|
1804 else { |
|
1805 addr &= 0x0f; |
|
1806 pcnet_aprom_writeb(d, addr, val & 0xff); |
|
1807 pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); |
|
1808 } |
|
1809 } |
|
1810 |
|
1811 static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) |
|
1812 { |
|
1813 PCNetState *d = opaque; |
|
1814 uint32_t val = -1; |
|
1815 if (addr & 0x10) |
|
1816 val = pcnet_ioport_readw(d, addr & 0x0f); |
|
1817 else { |
|
1818 addr &= 0x0f; |
|
1819 val = pcnet_aprom_readb(d, addr+1); |
|
1820 val <<= 8; |
|
1821 val |= pcnet_aprom_readb(d, addr); |
|
1822 } |
|
1823 #ifdef PCNET_DEBUG_IO |
|
1824 printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, |
|
1825 val & 0xffff); |
|
1826 #endif |
|
1827 return val; |
|
1828 } |
|
1829 |
|
1830 static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1831 { |
|
1832 PCNetState *d = opaque; |
|
1833 #ifdef PCNET_DEBUG_IO |
|
1834 printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, |
|
1835 val); |
|
1836 #endif |
|
1837 if (addr & 0x10) |
|
1838 pcnet_ioport_writel(d, addr & 0x0f, val); |
|
1839 else { |
|
1840 addr &= 0x0f; |
|
1841 pcnet_aprom_writeb(d, addr, val & 0xff); |
|
1842 pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); |
|
1843 pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); |
|
1844 pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); |
|
1845 } |
|
1846 } |
|
1847 |
|
1848 static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) |
|
1849 { |
|
1850 PCNetState *d = opaque; |
|
1851 uint32_t val; |
|
1852 if (addr & 0x10) |
|
1853 val = pcnet_ioport_readl(d, addr & 0x0f); |
|
1854 else { |
|
1855 addr &= 0x0f; |
|
1856 val = pcnet_aprom_readb(d, addr+3); |
|
1857 val <<= 8; |
|
1858 val |= pcnet_aprom_readb(d, addr+2); |
|
1859 val <<= 8; |
|
1860 val |= pcnet_aprom_readb(d, addr+1); |
|
1861 val <<= 8; |
|
1862 val |= pcnet_aprom_readb(d, addr); |
|
1863 } |
|
1864 #ifdef PCNET_DEBUG_IO |
|
1865 printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, |
|
1866 val); |
|
1867 #endif |
|
1868 return val; |
|
1869 } |
|
1870 |
|
1871 |
|
1872 static void pcnet_save(QEMUFile *f, void *opaque) |
|
1873 { |
|
1874 PCNetState *s = opaque; |
|
1875 unsigned int i; |
|
1876 |
|
1877 if (s->pci_dev) |
|
1878 pci_device_save(s->pci_dev, f); |
|
1879 |
|
1880 qemu_put_sbe32(f, s->rap); |
|
1881 qemu_put_sbe32(f, s->isr); |
|
1882 qemu_put_sbe32(f, s->lnkst); |
|
1883 qemu_put_be32s(f, &s->rdra); |
|
1884 qemu_put_be32s(f, &s->tdra); |
|
1885 qemu_put_buffer(f, s->prom, 16); |
|
1886 for (i = 0; i < 128; i++) |
|
1887 qemu_put_be16s(f, &s->csr[i]); |
|
1888 for (i = 0; i < 32; i++) |
|
1889 qemu_put_be16s(f, &s->bcr[i]); |
|
1890 qemu_put_be64s(f, &s->timer); |
|
1891 qemu_put_sbe32(f, s->xmit_pos); |
|
1892 qemu_put_sbe32(f, s->recv_pos); |
|
1893 qemu_put_buffer(f, s->buffer, 4096); |
|
1894 qemu_put_sbe32(f, s->tx_busy); |
|
1895 qemu_put_timer(f, s->poll_timer); |
|
1896 } |
|
1897 |
|
1898 static int pcnet_load(QEMUFile *f, void *opaque, int version_id) |
|
1899 { |
|
1900 PCNetState *s = opaque; |
|
1901 int i, ret; |
|
1902 |
|
1903 if (version_id != 2) |
|
1904 return -EINVAL; |
|
1905 |
|
1906 if (s->pci_dev) { |
|
1907 ret = pci_device_load(s->pci_dev, f); |
|
1908 if (ret < 0) |
|
1909 return ret; |
|
1910 } |
|
1911 |
|
1912 qemu_get_sbe32s(f, &s->rap); |
|
1913 qemu_get_sbe32s(f, &s->isr); |
|
1914 qemu_get_sbe32s(f, &s->lnkst); |
|
1915 qemu_get_be32s(f, &s->rdra); |
|
1916 qemu_get_be32s(f, &s->tdra); |
|
1917 qemu_get_buffer(f, s->prom, 16); |
|
1918 for (i = 0; i < 128; i++) |
|
1919 qemu_get_be16s(f, &s->csr[i]); |
|
1920 for (i = 0; i < 32; i++) |
|
1921 qemu_get_be16s(f, &s->bcr[i]); |
|
1922 qemu_get_be64s(f, &s->timer); |
|
1923 qemu_get_sbe32s(f, &s->xmit_pos); |
|
1924 qemu_get_sbe32s(f, &s->recv_pos); |
|
1925 qemu_get_buffer(f, s->buffer, 4096); |
|
1926 qemu_get_sbe32s(f, &s->tx_busy); |
|
1927 qemu_get_timer(f, s->poll_timer); |
|
1928 |
|
1929 return 0; |
|
1930 } |
|
1931 |
|
1932 static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str) |
|
1933 { |
|
1934 d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); |
|
1935 |
|
1936 d->nd = nd; |
|
1937 |
|
1938 if (nd && nd->vlan) { |
|
1939 d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, |
|
1940 pcnet_can_receive, d); |
|
1941 |
|
1942 snprintf(d->vc->info_str, sizeof(d->vc->info_str), |
|
1943 "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
|
1944 d->nd->macaddr[0], |
|
1945 d->nd->macaddr[1], |
|
1946 d->nd->macaddr[2], |
|
1947 d->nd->macaddr[3], |
|
1948 d->nd->macaddr[4], |
|
1949 d->nd->macaddr[5]); |
|
1950 } else { |
|
1951 d->vc = NULL; |
|
1952 } |
|
1953 pcnet_h_reset(d); |
|
1954 register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, d); |
|
1955 } |
|
1956 |
|
1957 /* PCI interface */ |
|
1958 |
|
1959 static CPUWriteMemoryFunc *pcnet_mmio_write[] = { |
|
1960 (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, |
|
1961 (CPUWriteMemoryFunc *)&pcnet_mmio_writew, |
|
1962 (CPUWriteMemoryFunc *)&pcnet_mmio_writel |
|
1963 }; |
|
1964 |
|
1965 static CPUReadMemoryFunc *pcnet_mmio_read[] = { |
|
1966 (CPUReadMemoryFunc *)&pcnet_mmio_readb, |
|
1967 (CPUReadMemoryFunc *)&pcnet_mmio_readw, |
|
1968 (CPUReadMemoryFunc *)&pcnet_mmio_readl |
|
1969 }; |
|
1970 |
|
1971 static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, |
|
1972 uint32_t addr, uint32_t size, int type) |
|
1973 { |
|
1974 PCNetState *d = (PCNetState *)pci_dev; |
|
1975 |
|
1976 #ifdef PCNET_DEBUG_IO |
|
1977 printf("pcnet_mmio_map addr=0x%08x 0x%08x\n", addr, size); |
|
1978 #endif |
|
1979 |
|
1980 cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index); |
|
1981 } |
|
1982 |
|
1983 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, |
|
1984 uint8_t *buf, int len, int do_bswap) |
|
1985 { |
|
1986 cpu_physical_memory_write(addr, buf, len); |
|
1987 } |
|
1988 |
|
1989 static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, |
|
1990 uint8_t *buf, int len, int do_bswap) |
|
1991 { |
|
1992 cpu_physical_memory_read(addr, buf, len); |
|
1993 } |
|
1994 |
|
1995 void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) |
|
1996 { |
|
1997 PCNetState *d; |
|
1998 uint8_t *pci_conf; |
|
1999 |
|
2000 #if 0 |
|
2001 printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", |
|
2002 sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); |
|
2003 #endif |
|
2004 |
|
2005 d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), |
|
2006 devfn, NULL, NULL); |
|
2007 |
|
2008 pci_conf = d->dev.config; |
|
2009 |
|
2010 *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); |
|
2011 *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); |
|
2012 *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); |
|
2013 *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); |
|
2014 pci_conf[0x08] = 0x10; |
|
2015 pci_conf[0x09] = 0x00; |
|
2016 pci_conf[0x0a] = 0x00; // ethernet network controller |
|
2017 pci_conf[0x0b] = 0x02; |
|
2018 pci_conf[0x0e] = 0x00; // header_type |
|
2019 |
|
2020 *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); |
|
2021 *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); |
|
2022 |
|
2023 pci_conf[0x3d] = 1; // interrupt pin 0 |
|
2024 pci_conf[0x3e] = 0x06; |
|
2025 pci_conf[0x3f] = 0xff; |
|
2026 |
|
2027 /* Handler for memory-mapped I/O */ |
|
2028 d->mmio_index = |
|
2029 cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); |
|
2030 |
|
2031 pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, |
|
2032 PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); |
|
2033 |
|
2034 pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, |
|
2035 PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); |
|
2036 |
|
2037 d->irq = d->dev.irq[0]; |
|
2038 d->phys_mem_read = pci_physical_memory_read; |
|
2039 d->phys_mem_write = pci_physical_memory_write; |
|
2040 d->pci_dev = &d->dev; |
|
2041 |
|
2042 pcnet_common_init(d, nd, "pcnet"); |
|
2043 } |
|
2044 |
|
2045 /* SPARC32 interface */ |
|
2046 |
|
2047 #if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure |
|
2048 #include "sun4m.h" |
|
2049 |
|
2050 static void parent_lance_reset(void *opaque, int irq, int level) |
|
2051 { |
|
2052 if (level) |
|
2053 pcnet_h_reset(opaque); |
|
2054 } |
|
2055 |
|
2056 static void lance_mem_writew(void *opaque, target_phys_addr_t addr, |
|
2057 uint32_t val) |
|
2058 { |
|
2059 #ifdef PCNET_DEBUG_IO |
|
2060 printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr, |
|
2061 val & 0xffff); |
|
2062 #endif |
|
2063 pcnet_ioport_writew(opaque, addr, val & 0xffff); |
|
2064 } |
|
2065 |
|
2066 static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) |
|
2067 { |
|
2068 uint32_t val; |
|
2069 |
|
2070 val = pcnet_ioport_readw(opaque, addr); |
|
2071 #ifdef PCNET_DEBUG_IO |
|
2072 printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, |
|
2073 val & 0xffff); |
|
2074 #endif |
|
2075 |
|
2076 return val & 0xffff; |
|
2077 } |
|
2078 |
|
2079 static CPUReadMemoryFunc *lance_mem_read[3] = { |
|
2080 NULL, |
|
2081 lance_mem_readw, |
|
2082 NULL, |
|
2083 }; |
|
2084 |
|
2085 static CPUWriteMemoryFunc *lance_mem_write[3] = { |
|
2086 NULL, |
|
2087 lance_mem_writew, |
|
2088 NULL, |
|
2089 }; |
|
2090 |
|
2091 void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, |
|
2092 qemu_irq irq, qemu_irq *reset) |
|
2093 { |
|
2094 PCNetState *d; |
|
2095 int lance_io_memory; |
|
2096 |
|
2097 d = qemu_mallocz(sizeof(PCNetState)); |
|
2098 if (!d) |
|
2099 return; |
|
2100 |
|
2101 lance_io_memory = |
|
2102 cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); |
|
2103 |
|
2104 d->dma_opaque = dma_opaque; |
|
2105 |
|
2106 *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1); |
|
2107 |
|
2108 cpu_register_physical_memory(leaddr, 4, lance_io_memory); |
|
2109 |
|
2110 d->irq = irq; |
|
2111 d->phys_mem_read = ledma_memory_read; |
|
2112 d->phys_mem_write = ledma_memory_write; |
|
2113 |
|
2114 pcnet_common_init(d, nd, "lance"); |
|
2115 } |
|
2116 #endif /* TARGET_SPARC */ |