xref: /openbmc/qemu/hw/net/fsl_etsec/etsec.c (revision 63dc36944383f70f1c7a20f6104966d8560300fa)
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