Statistics
| Branch: | Revision:

root / hw / pcnet.c @ 93148aa5

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