1eb1e7c3eSFabien Chouteau /*
2eb1e7c3eSFabien Chouteau * QEMU Freescale eTSEC Emulator
3eb1e7c3eSFabien Chouteau *
4eb1e7c3eSFabien Chouteau * Copyright (c) 2011-2013 AdaCore
5eb1e7c3eSFabien Chouteau *
6eb1e7c3eSFabien Chouteau * Permission is hereby granted, free of charge, to any person obtaining a copy
7eb1e7c3eSFabien Chouteau * of this software and associated documentation files (the "Software"), to deal
8eb1e7c3eSFabien Chouteau * in the Software without restriction, including without limitation the rights
9eb1e7c3eSFabien Chouteau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10eb1e7c3eSFabien Chouteau * copies of the Software, and to permit persons to whom the Software is
11eb1e7c3eSFabien Chouteau * furnished to do so, subject to the following conditions:
12eb1e7c3eSFabien Chouteau *
13eb1e7c3eSFabien Chouteau * The above copyright notice and this permission notice shall be included in
14eb1e7c3eSFabien Chouteau * all copies or substantial portions of the Software.
15eb1e7c3eSFabien Chouteau *
16eb1e7c3eSFabien Chouteau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17eb1e7c3eSFabien Chouteau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18eb1e7c3eSFabien Chouteau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19eb1e7c3eSFabien Chouteau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20eb1e7c3eSFabien Chouteau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21eb1e7c3eSFabien Chouteau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22eb1e7c3eSFabien Chouteau * THE SOFTWARE.
23eb1e7c3eSFabien Chouteau */
24eb1e7c3eSFabien Chouteau
25eb1e7c3eSFabien Chouteau /*
26eb1e7c3eSFabien Chouteau * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
27eb1e7c3eSFabien Chouteau */
28eb1e7c3eSFabien Chouteau
29e8d40465SPeter Maydell #include "qemu/osdep.h"
30eb1e7c3eSFabien Chouteau #include "hw/sysbus.h"
3164552b6bSMarkus Armbruster #include "hw/irq.h"
326684bef1SAkihiko Odaki #include "hw/net/mii.h"
33eb1e7c3eSFabien Chouteau #include "hw/ptimer.h"
34a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
35eb1e7c3eSFabien Chouteau #include "etsec.h"
36eb1e7c3eSFabien Chouteau #include "registers.h"
373e80f690SMarkus Armbruster #include "qapi/error.h"
3803dd024fSPaolo Bonzini #include "qemu/log.h"
39eb1e7c3eSFabien Chouteau
40eb1e7c3eSFabien Chouteau /* #define HEX_DUMP */
41eb1e7c3eSFabien Chouteau /* #define DEBUG_REGISTER */
42eb1e7c3eSFabien Chouteau
43eb1e7c3eSFabien Chouteau #ifdef DEBUG_REGISTER
44eb1e7c3eSFabien Chouteau static const int debug_etsec = 1;
45eb1e7c3eSFabien Chouteau #else
46eb1e7c3eSFabien Chouteau static const int debug_etsec;
47eb1e7c3eSFabien Chouteau #endif
48eb1e7c3eSFabien Chouteau
49eb1e7c3eSFabien Chouteau #define DPRINTF(fmt, ...) do { \
50eb1e7c3eSFabien Chouteau if (debug_etsec) { \
51eb1e7c3eSFabien Chouteau qemu_log(fmt , ## __VA_ARGS__); \
52eb1e7c3eSFabien Chouteau } \
53eb1e7c3eSFabien Chouteau } while (0)
54eb1e7c3eSFabien Chouteau
55fd8e3381SMichael Davidsaver /* call after any change to IEVENT or IMASK */
etsec_update_irq(eTSEC * etsec)56fd8e3381SMichael Davidsaver void etsec_update_irq(eTSEC *etsec)
57fd8e3381SMichael Davidsaver {
58fd8e3381SMichael Davidsaver uint32_t ievent = etsec->regs[IEVENT].value;
59fd8e3381SMichael Davidsaver uint32_t imask = etsec->regs[IMASK].value;
60fd8e3381SMichael Davidsaver uint32_t active = ievent & imask;
61fd8e3381SMichael Davidsaver
62fd8e3381SMichael Davidsaver int tx = !!(active & IEVENT_TX_MASK);
63fd8e3381SMichael Davidsaver int rx = !!(active & IEVENT_RX_MASK);
64fd8e3381SMichael Davidsaver int err = !!(active & IEVENT_ERR_MASK);
65fd8e3381SMichael Davidsaver
66fd8e3381SMichael Davidsaver DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c",
67fd8e3381SMichael Davidsaver __func__, ievent, imask,
68fd8e3381SMichael Davidsaver tx ? 'T' : '_',
69fd8e3381SMichael Davidsaver rx ? 'R' : '_',
70fd8e3381SMichael Davidsaver err ? 'E' : '_');
71fd8e3381SMichael Davidsaver
72fd8e3381SMichael Davidsaver qemu_set_irq(etsec->tx_irq, tx);
73fd8e3381SMichael Davidsaver qemu_set_irq(etsec->rx_irq, rx);
74fd8e3381SMichael Davidsaver qemu_set_irq(etsec->err_irq, err);
75fd8e3381SMichael Davidsaver }
76fd8e3381SMichael Davidsaver
etsec_read(void * opaque,hwaddr addr,unsigned size)77eb1e7c3eSFabien Chouteau static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
78eb1e7c3eSFabien Chouteau {
79eb1e7c3eSFabien Chouteau eTSEC *etsec = opaque;
80eb1e7c3eSFabien Chouteau uint32_t reg_index = addr / 4;
81eb1e7c3eSFabien Chouteau eTSEC_Register *reg = NULL;
82eb1e7c3eSFabien Chouteau uint32_t ret = 0x0;
83eb1e7c3eSFabien Chouteau
84eb1e7c3eSFabien Chouteau assert(reg_index < ETSEC_REG_NUMBER);
85eb1e7c3eSFabien Chouteau
86eb1e7c3eSFabien Chouteau reg = &etsec->regs[reg_index];
87eb1e7c3eSFabien Chouteau
88eb1e7c3eSFabien Chouteau
89eb1e7c3eSFabien Chouteau switch (reg->access) {
90eb1e7c3eSFabien Chouteau case ACC_WO:
91eb1e7c3eSFabien Chouteau ret = 0x00000000;
92eb1e7c3eSFabien Chouteau break;
93eb1e7c3eSFabien Chouteau
94eb1e7c3eSFabien Chouteau case ACC_RW:
95eb1e7c3eSFabien Chouteau case ACC_W1C:
96eb1e7c3eSFabien Chouteau case ACC_RO:
97eb1e7c3eSFabien Chouteau default:
98eb1e7c3eSFabien Chouteau ret = reg->value;
99eb1e7c3eSFabien Chouteau break;
100eb1e7c3eSFabien Chouteau }
101eb1e7c3eSFabien Chouteau
102883f2c59SPhilippe Mathieu-Daudé DPRINTF("Read 0x%08x @ 0x" HWADDR_FMT_plx
103eb1e7c3eSFabien Chouteau " : %s (%s)\n",
104eb1e7c3eSFabien Chouteau ret, addr, reg->name, reg->desc);
105eb1e7c3eSFabien Chouteau
106eb1e7c3eSFabien Chouteau return ret;
107eb1e7c3eSFabien Chouteau }
108eb1e7c3eSFabien Chouteau
write_tstat(eTSEC * etsec,eTSEC_Register * reg,uint32_t reg_index,uint32_t value)109eb1e7c3eSFabien Chouteau static void write_tstat(eTSEC *etsec,
110eb1e7c3eSFabien Chouteau eTSEC_Register *reg,
111eb1e7c3eSFabien Chouteau uint32_t reg_index,
112eb1e7c3eSFabien Chouteau uint32_t value)
113eb1e7c3eSFabien Chouteau {
114eb1e7c3eSFabien Chouteau int i = 0;
115eb1e7c3eSFabien Chouteau
116eb1e7c3eSFabien Chouteau for (i = 0; i < 8; i++) {
117eb1e7c3eSFabien Chouteau /* Check THLTi flag in TSTAT */
118eb1e7c3eSFabien Chouteau if (value & (1 << (31 - i))) {
119eb1e7c3eSFabien Chouteau etsec_walk_tx_ring(etsec, i);
120eb1e7c3eSFabien Chouteau }
121eb1e7c3eSFabien Chouteau }
122eb1e7c3eSFabien Chouteau
123eb1e7c3eSFabien Chouteau /* Write 1 to clear */
124eb1e7c3eSFabien Chouteau reg->value &= ~value;
125eb1e7c3eSFabien Chouteau }
126eb1e7c3eSFabien Chouteau
write_rstat(eTSEC * etsec,eTSEC_Register * reg,uint32_t reg_index,uint32_t value)127eb1e7c3eSFabien Chouteau static void write_rstat(eTSEC *etsec,
128eb1e7c3eSFabien Chouteau eTSEC_Register *reg,
129eb1e7c3eSFabien Chouteau uint32_t reg_index,
130eb1e7c3eSFabien Chouteau uint32_t value)
131eb1e7c3eSFabien Chouteau {
132eb1e7c3eSFabien Chouteau int i = 0;
133eb1e7c3eSFabien Chouteau
134eb1e7c3eSFabien Chouteau for (i = 0; i < 8; i++) {
135eb1e7c3eSFabien Chouteau /* Check QHLTi flag in RSTAT */
136eb1e7c3eSFabien Chouteau if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
137eb1e7c3eSFabien Chouteau etsec_walk_rx_ring(etsec, i);
138eb1e7c3eSFabien Chouteau }
139eb1e7c3eSFabien Chouteau }
140eb1e7c3eSFabien Chouteau
141eb1e7c3eSFabien Chouteau /* Write 1 to clear */
142eb1e7c3eSFabien Chouteau reg->value &= ~value;
143eb1e7c3eSFabien Chouteau }
144eb1e7c3eSFabien Chouteau
write_tbasex(eTSEC * etsec,eTSEC_Register * reg,uint32_t reg_index,uint32_t value)145eb1e7c3eSFabien Chouteau static void write_tbasex(eTSEC *etsec,
146eb1e7c3eSFabien Chouteau eTSEC_Register *reg,
147eb1e7c3eSFabien Chouteau uint32_t reg_index,
148eb1e7c3eSFabien Chouteau uint32_t value)
149eb1e7c3eSFabien Chouteau {
150eb1e7c3eSFabien Chouteau reg->value = value & ~0x7;
151eb1e7c3eSFabien Chouteau
152eb1e7c3eSFabien Chouteau /* Copy this value in the ring's TxBD pointer */
153eb1e7c3eSFabien Chouteau etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
154eb1e7c3eSFabien Chouteau }
155eb1e7c3eSFabien Chouteau
write_rbasex(eTSEC * etsec,eTSEC_Register * reg,uint32_t reg_index,uint32_t value)156eb1e7c3eSFabien Chouteau static void write_rbasex(eTSEC *etsec,
157eb1e7c3eSFabien Chouteau eTSEC_Register *reg,
158eb1e7c3eSFabien Chouteau uint32_t reg_index,
159eb1e7c3eSFabien Chouteau uint32_t value)
160eb1e7c3eSFabien Chouteau {
161eb1e7c3eSFabien Chouteau reg->value = value & ~0x7;
162eb1e7c3eSFabien Chouteau
163eb1e7c3eSFabien Chouteau /* Copy this value in the ring's RxBD pointer */
164eb1e7c3eSFabien Chouteau etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
165eb1e7c3eSFabien Chouteau }
166eb1e7c3eSFabien Chouteau
write_dmactrl(eTSEC * etsec,eTSEC_Register * reg,uint32_t reg_index,uint32_t value)167eb1e7c3eSFabien Chouteau static void write_dmactrl(eTSEC *etsec,
168eb1e7c3eSFabien Chouteau eTSEC_Register *reg,
169eb1e7c3eSFabien Chouteau uint32_t reg_index,
170eb1e7c3eSFabien Chouteau uint32_t value)
171eb1e7c3eSFabien Chouteau {
172eb1e7c3eSFabien Chouteau reg->value = value;
173eb1e7c3eSFabien Chouteau
174eb1e7c3eSFabien Chouteau if (value & DMACTRL_GRS) {
175eb1e7c3eSFabien Chouteau
176eb1e7c3eSFabien Chouteau if (etsec->rx_buffer_len != 0) {
177eb1e7c3eSFabien Chouteau /* Graceful receive stop delayed until end of frame */
178eb1e7c3eSFabien Chouteau } else {
179eb1e7c3eSFabien Chouteau /* Graceful receive stop now */
180eb1e7c3eSFabien Chouteau etsec->regs[IEVENT].value |= IEVENT_GRSC;
181fd8e3381SMichael Davidsaver etsec_update_irq(etsec);
182eb1e7c3eSFabien Chouteau }
183eb1e7c3eSFabien Chouteau }
184eb1e7c3eSFabien Chouteau
185eb1e7c3eSFabien Chouteau if (value & DMACTRL_GTS) {
186eb1e7c3eSFabien Chouteau
187eb1e7c3eSFabien Chouteau if (etsec->tx_buffer_len != 0) {
188eb1e7c3eSFabien Chouteau /* Graceful transmit stop delayed until end of frame */
189eb1e7c3eSFabien Chouteau } else {
190eb1e7c3eSFabien Chouteau /* Graceful transmit stop now */
191eb1e7c3eSFabien Chouteau etsec->regs[IEVENT].value |= IEVENT_GTSC;
192fd8e3381SMichael Davidsaver etsec_update_irq(etsec);
193eb1e7c3eSFabien Chouteau }
194eb1e7c3eSFabien Chouteau }
195eb1e7c3eSFabien Chouteau
196eb1e7c3eSFabien Chouteau if (!(value & DMACTRL_WOP)) {
197eb1e7c3eSFabien Chouteau /* Start polling */
198383a6753SPeter Maydell ptimer_transaction_begin(etsec->ptimer);
199eb1e7c3eSFabien Chouteau ptimer_stop(etsec->ptimer);
200eb1e7c3eSFabien Chouteau ptimer_set_count(etsec->ptimer, 1);
201eb1e7c3eSFabien Chouteau ptimer_run(etsec->ptimer, 1);
202383a6753SPeter Maydell ptimer_transaction_commit(etsec->ptimer);
203eb1e7c3eSFabien Chouteau }
204eb1e7c3eSFabien Chouteau }
205eb1e7c3eSFabien Chouteau
etsec_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)206eb1e7c3eSFabien Chouteau static void etsec_write(void *opaque,
207eb1e7c3eSFabien Chouteau hwaddr addr,
208eb1e7c3eSFabien Chouteau uint64_t value,
209eb1e7c3eSFabien Chouteau unsigned size)
210eb1e7c3eSFabien Chouteau {
211eb1e7c3eSFabien Chouteau eTSEC *etsec = opaque;
212eb1e7c3eSFabien Chouteau uint32_t reg_index = addr / 4;
213eb1e7c3eSFabien Chouteau eTSEC_Register *reg = NULL;
214eb1e7c3eSFabien Chouteau uint32_t before = 0x0;
215eb1e7c3eSFabien Chouteau
216eb1e7c3eSFabien Chouteau assert(reg_index < ETSEC_REG_NUMBER);
217eb1e7c3eSFabien Chouteau
218eb1e7c3eSFabien Chouteau reg = &etsec->regs[reg_index];
219eb1e7c3eSFabien Chouteau before = reg->value;
220eb1e7c3eSFabien Chouteau
221eb1e7c3eSFabien Chouteau switch (reg_index) {
222eb1e7c3eSFabien Chouteau case IEVENT:
223fd8e3381SMichael Davidsaver /* Write 1 to clear */
224fd8e3381SMichael Davidsaver reg->value &= ~value;
225fd8e3381SMichael Davidsaver
226fd8e3381SMichael Davidsaver etsec_update_irq(etsec);
227fd8e3381SMichael Davidsaver break;
228fd8e3381SMichael Davidsaver
229fd8e3381SMichael Davidsaver case IMASK:
230fd8e3381SMichael Davidsaver reg->value = value;
231fd8e3381SMichael Davidsaver
232fd8e3381SMichael Davidsaver etsec_update_irq(etsec);
233eb1e7c3eSFabien Chouteau break;
234eb1e7c3eSFabien Chouteau
235eb1e7c3eSFabien Chouteau case DMACTRL:
236eb1e7c3eSFabien Chouteau write_dmactrl(etsec, reg, reg_index, value);
237eb1e7c3eSFabien Chouteau break;
238eb1e7c3eSFabien Chouteau
239eb1e7c3eSFabien Chouteau case TSTAT:
240eb1e7c3eSFabien Chouteau write_tstat(etsec, reg, reg_index, value);
241eb1e7c3eSFabien Chouteau break;
242eb1e7c3eSFabien Chouteau
243eb1e7c3eSFabien Chouteau case RSTAT:
244eb1e7c3eSFabien Chouteau write_rstat(etsec, reg, reg_index, value);
245eb1e7c3eSFabien Chouteau break;
246eb1e7c3eSFabien Chouteau
247eb1e7c3eSFabien Chouteau case TBASE0 ... TBASE7:
248eb1e7c3eSFabien Chouteau write_tbasex(etsec, reg, reg_index, value);
249eb1e7c3eSFabien Chouteau break;
250eb1e7c3eSFabien Chouteau
251eb1e7c3eSFabien Chouteau case RBASE0 ... RBASE7:
252eb1e7c3eSFabien Chouteau write_rbasex(etsec, reg, reg_index, value);
253eb1e7c3eSFabien Chouteau break;
254eb1e7c3eSFabien Chouteau
255eb1e7c3eSFabien Chouteau case MIIMCFG ... MIIMIND:
256eb1e7c3eSFabien Chouteau etsec_write_miim(etsec, reg, reg_index, value);
257eb1e7c3eSFabien Chouteau break;
258eb1e7c3eSFabien Chouteau
259eb1e7c3eSFabien Chouteau default:
260eb1e7c3eSFabien Chouteau /* Default handling */
261eb1e7c3eSFabien Chouteau switch (reg->access) {
262eb1e7c3eSFabien Chouteau
263eb1e7c3eSFabien Chouteau case ACC_RW:
264eb1e7c3eSFabien Chouteau case ACC_WO:
265eb1e7c3eSFabien Chouteau reg->value = value;
266eb1e7c3eSFabien Chouteau break;
267eb1e7c3eSFabien Chouteau
268eb1e7c3eSFabien Chouteau case ACC_W1C:
269eb1e7c3eSFabien Chouteau reg->value &= ~value;
270eb1e7c3eSFabien Chouteau break;
271eb1e7c3eSFabien Chouteau
272eb1e7c3eSFabien Chouteau case ACC_RO:
273eb1e7c3eSFabien Chouteau default:
274eb1e7c3eSFabien Chouteau /* Read Only or Unknown register */
275eb1e7c3eSFabien Chouteau break;
276eb1e7c3eSFabien Chouteau }
277eb1e7c3eSFabien Chouteau }
278eb1e7c3eSFabien Chouteau
279883f2c59SPhilippe Mathieu-Daudé DPRINTF("Write 0x%08x @ 0x" HWADDR_FMT_plx
280eb1e7c3eSFabien Chouteau " val:0x%08x->0x%08x : %s (%s)\n",
281eb1e7c3eSFabien Chouteau (unsigned int)value, addr, before, reg->value,
282eb1e7c3eSFabien Chouteau reg->name, reg->desc);
283eb1e7c3eSFabien Chouteau }
284eb1e7c3eSFabien Chouteau
285eb1e7c3eSFabien Chouteau static const MemoryRegionOps etsec_ops = {
286eb1e7c3eSFabien Chouteau .read = etsec_read,
287eb1e7c3eSFabien Chouteau .write = etsec_write,
288eb1e7c3eSFabien Chouteau .endianness = DEVICE_NATIVE_ENDIAN,
289eb1e7c3eSFabien Chouteau .impl = {
290eb1e7c3eSFabien Chouteau .min_access_size = 4,
291eb1e7c3eSFabien Chouteau .max_access_size = 4,
292eb1e7c3eSFabien Chouteau },
293eb1e7c3eSFabien Chouteau };
294eb1e7c3eSFabien Chouteau
etsec_timer_hit(void * opaque)295eb1e7c3eSFabien Chouteau static void etsec_timer_hit(void *opaque)
296eb1e7c3eSFabien Chouteau {
297eb1e7c3eSFabien Chouteau eTSEC *etsec = opaque;
298eb1e7c3eSFabien Chouteau
299eb1e7c3eSFabien Chouteau ptimer_stop(etsec->ptimer);
300eb1e7c3eSFabien Chouteau
301eb1e7c3eSFabien Chouteau if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
302eb1e7c3eSFabien Chouteau
303eb1e7c3eSFabien Chouteau if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
304eb1e7c3eSFabien Chouteau etsec_walk_tx_ring(etsec, 0);
305eb1e7c3eSFabien Chouteau }
306eb1e7c3eSFabien Chouteau ptimer_set_count(etsec->ptimer, 1);
307eb1e7c3eSFabien Chouteau ptimer_run(etsec->ptimer, 1);
308eb1e7c3eSFabien Chouteau }
309eb1e7c3eSFabien Chouteau }
310eb1e7c3eSFabien Chouteau
etsec_reset(DeviceState * d)311eb1e7c3eSFabien Chouteau static void etsec_reset(DeviceState *d)
312eb1e7c3eSFabien Chouteau {
313eb1e7c3eSFabien Chouteau eTSEC *etsec = ETSEC_COMMON(d);
314eb1e7c3eSFabien Chouteau int i = 0;
315eb1e7c3eSFabien Chouteau int reg_index = 0;
316eb1e7c3eSFabien Chouteau
317eb1e7c3eSFabien Chouteau /* Default value for all registers */
318eb1e7c3eSFabien Chouteau for (i = 0; i < ETSEC_REG_NUMBER; i++) {
319eb1e7c3eSFabien Chouteau etsec->regs[i].name = "Reserved";
320eb1e7c3eSFabien Chouteau etsec->regs[i].desc = "";
321eb1e7c3eSFabien Chouteau etsec->regs[i].access = ACC_UNKNOWN;
322eb1e7c3eSFabien Chouteau etsec->regs[i].value = 0x00000000;
323eb1e7c3eSFabien Chouteau }
324eb1e7c3eSFabien Chouteau
325eb1e7c3eSFabien Chouteau /* Set-up known registers */
326eb1e7c3eSFabien Chouteau for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
327eb1e7c3eSFabien Chouteau
328eb1e7c3eSFabien Chouteau reg_index = eTSEC_registers_def[i].offset / 4;
329eb1e7c3eSFabien Chouteau
330eb1e7c3eSFabien Chouteau etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
331eb1e7c3eSFabien Chouteau etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
332eb1e7c3eSFabien Chouteau etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
333eb1e7c3eSFabien Chouteau etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
334eb1e7c3eSFabien Chouteau }
335eb1e7c3eSFabien Chouteau
336eb1e7c3eSFabien Chouteau etsec->tx_buffer = NULL;
337eb1e7c3eSFabien Chouteau etsec->tx_buffer_len = 0;
338eb1e7c3eSFabien Chouteau etsec->rx_buffer = NULL;
339eb1e7c3eSFabien Chouteau etsec->rx_buffer_len = 0;
340eb1e7c3eSFabien Chouteau
341eb1e7c3eSFabien Chouteau etsec->phy_status =
3426684bef1SAkihiko Odaki MII_BMSR_EXTCAP | MII_BMSR_LINK_ST | MII_BMSR_AUTONEG |
3436684bef1SAkihiko Odaki MII_BMSR_AN_COMP | MII_BMSR_MFPS | MII_BMSR_EXTSTAT |
3446684bef1SAkihiko Odaki MII_BMSR_100T2_HD | MII_BMSR_100T2_FD |
3456684bef1SAkihiko Odaki MII_BMSR_10T_HD | MII_BMSR_10T_FD |
3466684bef1SAkihiko Odaki MII_BMSR_100TX_HD | MII_BMSR_100TX_FD | MII_BMSR_100T4;
347fd8e3381SMichael Davidsaver
348fd8e3381SMichael Davidsaver etsec_update_irq(etsec);
349eb1e7c3eSFabien Chouteau }
350eb1e7c3eSFabien Chouteau
etsec_receive(NetClientState * nc,const uint8_t * buf,size_t size)351eb1e7c3eSFabien Chouteau static ssize_t etsec_receive(NetClientState *nc,
352eb1e7c3eSFabien Chouteau const uint8_t *buf,
353eb1e7c3eSFabien Chouteau size_t size)
354eb1e7c3eSFabien Chouteau {
355575bafd1SFam Zheng ssize_t ret;
356eb1e7c3eSFabien Chouteau eTSEC *etsec = qemu_get_nic_opaque(nc);
357eb1e7c3eSFabien Chouteau
358eb1e7c3eSFabien Chouteau #if defined(HEX_DUMP)
3599f5832d3SAndrey Smirnov fprintf(stderr, "%s receive size:%zd\n", nc->name, size);
360b42581f5SPhilippe Mathieu-Daudé qemu_hexdump(stderr, "", buf, size);
361eb1e7c3eSFabien Chouteau #endif
362575bafd1SFam Zheng /* Flush is unnecessary as are already in receiving path */
363575bafd1SFam Zheng etsec->need_flush = false;
364575bafd1SFam Zheng ret = etsec_rx_ring_write(etsec, buf, size);
365575bafd1SFam Zheng if (ret == 0) {
36667cc32ebSVeres Lajos /* The packet will be queued, let's flush it when buffer is available
367575bafd1SFam Zheng * again. */
368575bafd1SFam Zheng etsec->need_flush = true;
369575bafd1SFam Zheng }
370575bafd1SFam Zheng return ret;
371eb1e7c3eSFabien Chouteau }
372eb1e7c3eSFabien Chouteau
373eb1e7c3eSFabien Chouteau
etsec_set_link_status(NetClientState * nc)374eb1e7c3eSFabien Chouteau static void etsec_set_link_status(NetClientState *nc)
375eb1e7c3eSFabien Chouteau {
376eb1e7c3eSFabien Chouteau eTSEC *etsec = qemu_get_nic_opaque(nc);
377eb1e7c3eSFabien Chouteau
378eb1e7c3eSFabien Chouteau etsec_miim_link_status(etsec, nc);
379eb1e7c3eSFabien Chouteau }
380eb1e7c3eSFabien Chouteau
381eb1e7c3eSFabien Chouteau static NetClientInfo net_etsec_info = {
382f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC,
383eb1e7c3eSFabien Chouteau .size = sizeof(NICState),
384eb1e7c3eSFabien Chouteau .receive = etsec_receive,
385eb1e7c3eSFabien Chouteau .link_status_changed = etsec_set_link_status,
386eb1e7c3eSFabien Chouteau };
387eb1e7c3eSFabien Chouteau
etsec_realize(DeviceState * dev,Error ** errp)388eb1e7c3eSFabien Chouteau static void etsec_realize(DeviceState *dev, Error **errp)
389eb1e7c3eSFabien Chouteau {
390eb1e7c3eSFabien Chouteau eTSEC *etsec = ETSEC_COMMON(dev);
391eb1e7c3eSFabien Chouteau
392eb1e7c3eSFabien Chouteau etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
3937d0fefdfSAkihiko Odaki object_get_typename(OBJECT(dev)), dev->id,
3947d0fefdfSAkihiko Odaki &dev->mem_reentrancy_guard, etsec);
395eb1e7c3eSFabien Chouteau qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
396eb1e7c3eSFabien Chouteau
3979598c1bbSPeter Maydell etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_LEGACY);
398383a6753SPeter Maydell ptimer_transaction_begin(etsec->ptimer);
399eb1e7c3eSFabien Chouteau ptimer_set_freq(etsec->ptimer, 100);
400383a6753SPeter Maydell ptimer_transaction_commit(etsec->ptimer);
401eb1e7c3eSFabien Chouteau }
402eb1e7c3eSFabien Chouteau
etsec_instance_init(Object * obj)403eb1e7c3eSFabien Chouteau static void etsec_instance_init(Object *obj)
404eb1e7c3eSFabien Chouteau {
405eb1e7c3eSFabien Chouteau eTSEC *etsec = ETSEC_COMMON(obj);
406eb1e7c3eSFabien Chouteau SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
407eb1e7c3eSFabien Chouteau
408eb1e7c3eSFabien Chouteau memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
409eb1e7c3eSFabien Chouteau "eTSEC", 0x1000);
410eb1e7c3eSFabien Chouteau sysbus_init_mmio(sbd, &etsec->io_area);
411eb1e7c3eSFabien Chouteau
412eb1e7c3eSFabien Chouteau sysbus_init_irq(sbd, &etsec->tx_irq);
413eb1e7c3eSFabien Chouteau sysbus_init_irq(sbd, &etsec->rx_irq);
414eb1e7c3eSFabien Chouteau sysbus_init_irq(sbd, &etsec->err_irq);
415eb1e7c3eSFabien Chouteau }
416eb1e7c3eSFabien Chouteau
417eb1e7c3eSFabien Chouteau static Property etsec_properties[] = {
418eb1e7c3eSFabien Chouteau DEFINE_NIC_PROPERTIES(eTSEC, conf),
419eb1e7c3eSFabien Chouteau DEFINE_PROP_END_OF_LIST(),
420eb1e7c3eSFabien Chouteau };
421eb1e7c3eSFabien Chouteau
etsec_class_init(ObjectClass * klass,void * data)422eb1e7c3eSFabien Chouteau static void etsec_class_init(ObjectClass *klass, void *data)
423eb1e7c3eSFabien Chouteau {
424eb1e7c3eSFabien Chouteau DeviceClass *dc = DEVICE_CLASS(klass);
425eb1e7c3eSFabien Chouteau
426eb1e7c3eSFabien Chouteau dc->realize = etsec_realize;
427e3d08143SPeter Maydell device_class_set_legacy_reset(dc, etsec_reset);
4284f67d30bSMarc-André Lureau device_class_set_props(dc, etsec_properties);
429e4f4fb1eSEduardo Habkost /* Supported by ppce500 machine */
430e4f4fb1eSEduardo Habkost dc->user_creatable = true;
431eb1e7c3eSFabien Chouteau }
432eb1e7c3eSFabien Chouteau
433*59e0f990SBernhard Beschow static const TypeInfo etsec_types[] = {
434*59e0f990SBernhard Beschow {
435f7d82e9bSEduardo Habkost .name = TYPE_ETSEC_COMMON,
436eb1e7c3eSFabien Chouteau .parent = TYPE_SYS_BUS_DEVICE,
437eb1e7c3eSFabien Chouteau .instance_size = sizeof(eTSEC),
438eb1e7c3eSFabien Chouteau .class_init = etsec_class_init,
439eb1e7c3eSFabien Chouteau .instance_init = etsec_instance_init,
440*59e0f990SBernhard Beschow },
441eb1e7c3eSFabien Chouteau };
442eb1e7c3eSFabien Chouteau
443*59e0f990SBernhard Beschow DEFINE_TYPES(etsec_types)
444