Statistics
| Branch: | Revision:

root / hw / pcnet.c @ 7165448a

History | View | Annotate | Download (54.4 kB)

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