Statistics
| Branch: | Revision:

root / hw / net / xilinx_axienet.c @ f0e7a81c

History | View | Annotate | Download (22.9 kB)

1 93f1e401 Edgar E. Iglesias
/*
2 93f1e401 Edgar E. Iglesias
 * QEMU model of Xilinx AXI-Ethernet.
3 93f1e401 Edgar E. Iglesias
 *
4 93f1e401 Edgar E. Iglesias
 * Copyright (c) 2011 Edgar E. Iglesias.
5 93f1e401 Edgar E. Iglesias
 *
6 93f1e401 Edgar E. Iglesias
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 93f1e401 Edgar E. Iglesias
 * of this software and associated documentation files (the "Software"), to deal
8 93f1e401 Edgar E. Iglesias
 * in the Software without restriction, including without limitation the rights
9 93f1e401 Edgar E. Iglesias
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 93f1e401 Edgar E. Iglesias
 * copies of the Software, and to permit persons to whom the Software is
11 93f1e401 Edgar E. Iglesias
 * furnished to do so, subject to the following conditions:
12 93f1e401 Edgar E. Iglesias
 *
13 93f1e401 Edgar E. Iglesias
 * The above copyright notice and this permission notice shall be included in
14 93f1e401 Edgar E. Iglesias
 * all copies or substantial portions of the Software.
15 93f1e401 Edgar E. Iglesias
 *
16 93f1e401 Edgar E. Iglesias
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 93f1e401 Edgar E. Iglesias
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 93f1e401 Edgar E. Iglesias
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 93f1e401 Edgar E. Iglesias
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 93f1e401 Edgar E. Iglesias
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 93f1e401 Edgar E. Iglesias
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 93f1e401 Edgar E. Iglesias
 * THE SOFTWARE.
23 93f1e401 Edgar E. Iglesias
 */
24 93f1e401 Edgar E. Iglesias
25 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
26 1de7afc9 Paolo Bonzini
#include "qemu/log.h"
27 1422e32d Paolo Bonzini
#include "net/net.h"
28 93f1e401 Edgar E. Iglesias
#include "net/checksum.h"
29 b4a42f81 Paolo Bonzini
#include "qapi/qmp/qerror.h"
30 93f1e401 Edgar E. Iglesias
31 83c9f4ca Paolo Bonzini
#include "hw/stream.h"
32 93f1e401 Edgar E. Iglesias
33 93f1e401 Edgar E. Iglesias
#define DPHY(x)
34 93f1e401 Edgar E. Iglesias
35 f0e7a81c Peter Crosthwaite
#define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet"
36 f0e7a81c Peter Crosthwaite
37 f0e7a81c Peter Crosthwaite
#define XILINX_AXI_ENET(obj) \
38 f0e7a81c Peter Crosthwaite
     OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET)
39 f0e7a81c Peter Crosthwaite
40 93f1e401 Edgar E. Iglesias
/* Advertisement control register. */
41 93f1e401 Edgar E. Iglesias
#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
42 93f1e401 Edgar E. Iglesias
#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
43 93f1e401 Edgar E. Iglesias
#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
44 93f1e401 Edgar E. Iglesias
#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
45 93f1e401 Edgar E. Iglesias
46 93f1e401 Edgar E. Iglesias
struct PHY {
47 93f1e401 Edgar E. Iglesias
    uint32_t regs[32];
48 93f1e401 Edgar E. Iglesias
49 93f1e401 Edgar E. Iglesias
    int link;
50 93f1e401 Edgar E. Iglesias
51 93f1e401 Edgar E. Iglesias
    unsigned int (*read)(struct PHY *phy, unsigned int req);
52 93f1e401 Edgar E. Iglesias
    void (*write)(struct PHY *phy, unsigned int req,
53 93f1e401 Edgar E. Iglesias
                  unsigned int data);
54 93f1e401 Edgar E. Iglesias
};
55 93f1e401 Edgar E. Iglesias
56 93f1e401 Edgar E. Iglesias
static unsigned int tdk_read(struct PHY *phy, unsigned int req)
57 93f1e401 Edgar E. Iglesias
{
58 93f1e401 Edgar E. Iglesias
    int regnum;
59 93f1e401 Edgar E. Iglesias
    unsigned r = 0;
60 93f1e401 Edgar E. Iglesias
61 93f1e401 Edgar E. Iglesias
    regnum = req & 0x1f;
62 93f1e401 Edgar E. Iglesias
63 93f1e401 Edgar E. Iglesias
    switch (regnum) {
64 93f1e401 Edgar E. Iglesias
        case 1:
65 93f1e401 Edgar E. Iglesias
            if (!phy->link) {
66 93f1e401 Edgar E. Iglesias
                break;
67 93f1e401 Edgar E. Iglesias
            }
68 93f1e401 Edgar E. Iglesias
            /* MR1.  */
69 93f1e401 Edgar E. Iglesias
            /* Speeds and modes.  */
70 93f1e401 Edgar E. Iglesias
            r |= (1 << 13) | (1 << 14);
71 93f1e401 Edgar E. Iglesias
            r |= (1 << 11) | (1 << 12);
72 93f1e401 Edgar E. Iglesias
            r |= (1 << 5); /* Autoneg complete.  */
73 93f1e401 Edgar E. Iglesias
            r |= (1 << 3); /* Autoneg able.  */
74 93f1e401 Edgar E. Iglesias
            r |= (1 << 2); /* link.  */
75 93f1e401 Edgar E. Iglesias
            r |= (1 << 1); /* link.  */
76 93f1e401 Edgar E. Iglesias
            break;
77 93f1e401 Edgar E. Iglesias
        case 5:
78 93f1e401 Edgar E. Iglesias
            /* Link partner ability.
79 93f1e401 Edgar E. Iglesias
               We are kind; always agree with whatever best mode
80 93f1e401 Edgar E. Iglesias
               the guest advertises.  */
81 93f1e401 Edgar E. Iglesias
            r = 1 << 14; /* Success.  */
82 93f1e401 Edgar E. Iglesias
            /* Copy advertised modes.  */
83 93f1e401 Edgar E. Iglesias
            r |= phy->regs[4] & (15 << 5);
84 93f1e401 Edgar E. Iglesias
            /* Autoneg support.  */
85 93f1e401 Edgar E. Iglesias
            r |= 1;
86 93f1e401 Edgar E. Iglesias
            break;
87 93f1e401 Edgar E. Iglesias
        case 17:
88 93f1e401 Edgar E. Iglesias
            /* Marvel PHY on many xilinx boards.  */
89 93f1e401 Edgar E. Iglesias
            r = 0x8000; /* 1000Mb  */
90 93f1e401 Edgar E. Iglesias
            break;
91 93f1e401 Edgar E. Iglesias
        case 18:
92 93f1e401 Edgar E. Iglesias
            {
93 93f1e401 Edgar E. Iglesias
                /* Diagnostics reg.  */
94 93f1e401 Edgar E. Iglesias
                int duplex = 0;
95 93f1e401 Edgar E. Iglesias
                int speed_100 = 0;
96 93f1e401 Edgar E. Iglesias
97 93f1e401 Edgar E. Iglesias
                if (!phy->link) {
98 93f1e401 Edgar E. Iglesias
                    break;
99 93f1e401 Edgar E. Iglesias
                }
100 93f1e401 Edgar E. Iglesias
101 93f1e401 Edgar E. Iglesias
                /* Are we advertising 100 half or 100 duplex ? */
102 93f1e401 Edgar E. Iglesias
                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
103 93f1e401 Edgar E. Iglesias
                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
104 93f1e401 Edgar E. Iglesias
105 93f1e401 Edgar E. Iglesias
                /* Are we advertising 10 duplex or 100 duplex ? */
106 93f1e401 Edgar E. Iglesias
                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
107 93f1e401 Edgar E. Iglesias
                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
108 93f1e401 Edgar E. Iglesias
                r = (speed_100 << 10) | (duplex << 11);
109 93f1e401 Edgar E. Iglesias
            }
110 93f1e401 Edgar E. Iglesias
            break;
111 93f1e401 Edgar E. Iglesias
112 93f1e401 Edgar E. Iglesias
        default:
113 93f1e401 Edgar E. Iglesias
            r = phy->regs[regnum];
114 93f1e401 Edgar E. Iglesias
            break;
115 93f1e401 Edgar E. Iglesias
    }
116 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
117 93f1e401 Edgar E. Iglesias
    return r;
118 93f1e401 Edgar E. Iglesias
}
119 93f1e401 Edgar E. Iglesias
120 93f1e401 Edgar E. Iglesias
static void
121 93f1e401 Edgar E. Iglesias
tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
122 93f1e401 Edgar E. Iglesias
{
123 93f1e401 Edgar E. Iglesias
    int regnum;
124 93f1e401 Edgar E. Iglesias
125 93f1e401 Edgar E. Iglesias
    regnum = req & 0x1f;
126 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
127 93f1e401 Edgar E. Iglesias
    switch (regnum) {
128 93f1e401 Edgar E. Iglesias
        default:
129 93f1e401 Edgar E. Iglesias
            phy->regs[regnum] = data;
130 93f1e401 Edgar E. Iglesias
            break;
131 93f1e401 Edgar E. Iglesias
    }
132 93f1e401 Edgar E. Iglesias
}
133 93f1e401 Edgar E. Iglesias
134 93f1e401 Edgar E. Iglesias
static void
135 93f1e401 Edgar E. Iglesias
tdk_init(struct PHY *phy)
136 93f1e401 Edgar E. Iglesias
{
137 93f1e401 Edgar E. Iglesias
    phy->regs[0] = 0x3100;
138 93f1e401 Edgar E. Iglesias
    /* PHY Id.  */
139 93f1e401 Edgar E. Iglesias
    phy->regs[2] = 0x0300;
140 93f1e401 Edgar E. Iglesias
    phy->regs[3] = 0xe400;
141 93f1e401 Edgar E. Iglesias
    /* Autonegotiation advertisement reg.  */
142 93f1e401 Edgar E. Iglesias
    phy->regs[4] = 0x01E1;
143 93f1e401 Edgar E. Iglesias
    phy->link = 1;
144 93f1e401 Edgar E. Iglesias
145 93f1e401 Edgar E. Iglesias
    phy->read = tdk_read;
146 93f1e401 Edgar E. Iglesias
    phy->write = tdk_write;
147 93f1e401 Edgar E. Iglesias
}
148 93f1e401 Edgar E. Iglesias
149 93f1e401 Edgar E. Iglesias
struct MDIOBus {
150 93f1e401 Edgar E. Iglesias
    /* bus.  */
151 93f1e401 Edgar E. Iglesias
    int mdc;
152 93f1e401 Edgar E. Iglesias
    int mdio;
153 93f1e401 Edgar E. Iglesias
154 93f1e401 Edgar E. Iglesias
    /* decoder.  */
155 93f1e401 Edgar E. Iglesias
    enum {
156 93f1e401 Edgar E. Iglesias
        PREAMBLE,
157 93f1e401 Edgar E. Iglesias
        SOF,
158 93f1e401 Edgar E. Iglesias
        OPC,
159 93f1e401 Edgar E. Iglesias
        ADDR,
160 93f1e401 Edgar E. Iglesias
        REQ,
161 93f1e401 Edgar E. Iglesias
        TURNAROUND,
162 93f1e401 Edgar E. Iglesias
        DATA
163 93f1e401 Edgar E. Iglesias
    } state;
164 93f1e401 Edgar E. Iglesias
    unsigned int drive;
165 93f1e401 Edgar E. Iglesias
166 93f1e401 Edgar E. Iglesias
    unsigned int cnt;
167 93f1e401 Edgar E. Iglesias
    unsigned int addr;
168 93f1e401 Edgar E. Iglesias
    unsigned int opc;
169 93f1e401 Edgar E. Iglesias
    unsigned int req;
170 93f1e401 Edgar E. Iglesias
    unsigned int data;
171 93f1e401 Edgar E. Iglesias
172 93f1e401 Edgar E. Iglesias
    struct PHY *devs[32];
173 93f1e401 Edgar E. Iglesias
};
174 93f1e401 Edgar E. Iglesias
175 93f1e401 Edgar E. Iglesias
static void
176 93f1e401 Edgar E. Iglesias
mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
177 93f1e401 Edgar E. Iglesias
{
178 93f1e401 Edgar E. Iglesias
    bus->devs[addr & 0x1f] = phy;
179 93f1e401 Edgar E. Iglesias
}
180 93f1e401 Edgar E. Iglesias
181 93f1e401 Edgar E. Iglesias
#ifdef USE_THIS_DEAD_CODE
182 93f1e401 Edgar E. Iglesias
static void
183 93f1e401 Edgar E. Iglesias
mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
184 93f1e401 Edgar E. Iglesias
{
185 93f1e401 Edgar E. Iglesias
    bus->devs[addr & 0x1f] = NULL;
186 93f1e401 Edgar E. Iglesias
}
187 93f1e401 Edgar E. Iglesias
#endif
188 93f1e401 Edgar E. Iglesias
189 93f1e401 Edgar E. Iglesias
static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
190 93f1e401 Edgar E. Iglesias
                  unsigned int reg)
191 93f1e401 Edgar E. Iglesias
{
192 93f1e401 Edgar E. Iglesias
    struct PHY *phy;
193 93f1e401 Edgar E. Iglesias
    uint16_t data;
194 93f1e401 Edgar E. Iglesias
195 93f1e401 Edgar E. Iglesias
    phy = bus->devs[addr];
196 93f1e401 Edgar E. Iglesias
    if (phy && phy->read) {
197 93f1e401 Edgar E. Iglesias
        data = phy->read(phy, reg);
198 93f1e401 Edgar E. Iglesias
    } else {
199 93f1e401 Edgar E. Iglesias
        data = 0xffff;
200 93f1e401 Edgar E. Iglesias
    }
201 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
202 93f1e401 Edgar E. Iglesias
    return data;
203 93f1e401 Edgar E. Iglesias
}
204 93f1e401 Edgar E. Iglesias
205 93f1e401 Edgar E. Iglesias
static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
206 93f1e401 Edgar E. Iglesias
               unsigned int reg, uint16_t data)
207 93f1e401 Edgar E. Iglesias
{
208 93f1e401 Edgar E. Iglesias
    struct PHY *phy;
209 93f1e401 Edgar E. Iglesias
210 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
211 93f1e401 Edgar E. Iglesias
    phy = bus->devs[addr];
212 93f1e401 Edgar E. Iglesias
    if (phy && phy->write) {
213 93f1e401 Edgar E. Iglesias
        phy->write(phy, reg, data);
214 93f1e401 Edgar E. Iglesias
    }
215 93f1e401 Edgar E. Iglesias
}
216 93f1e401 Edgar E. Iglesias
217 93f1e401 Edgar E. Iglesias
#define DENET(x)
218 93f1e401 Edgar E. Iglesias
219 93f1e401 Edgar E. Iglesias
#define R_RAF      (0x000 / 4)
220 93f1e401 Edgar E. Iglesias
enum {
221 93f1e401 Edgar E. Iglesias
    RAF_MCAST_REJ = (1 << 1),
222 93f1e401 Edgar E. Iglesias
    RAF_BCAST_REJ = (1 << 2),
223 93f1e401 Edgar E. Iglesias
    RAF_EMCF_EN = (1 << 12),
224 93f1e401 Edgar E. Iglesias
    RAF_NEWFUNC_EN = (1 << 11)
225 93f1e401 Edgar E. Iglesias
};
226 93f1e401 Edgar E. Iglesias
227 93f1e401 Edgar E. Iglesias
#define R_IS       (0x00C / 4)
228 93f1e401 Edgar E. Iglesias
enum {
229 93f1e401 Edgar E. Iglesias
    IS_HARD_ACCESS_COMPLETE = 1,
230 93f1e401 Edgar E. Iglesias
    IS_AUTONEG = (1 << 1),
231 93f1e401 Edgar E. Iglesias
    IS_RX_COMPLETE = (1 << 2),
232 93f1e401 Edgar E. Iglesias
    IS_RX_REJECT = (1 << 3),
233 93f1e401 Edgar E. Iglesias
    IS_TX_COMPLETE = (1 << 5),
234 93f1e401 Edgar E. Iglesias
    IS_RX_DCM_LOCK = (1 << 6),
235 93f1e401 Edgar E. Iglesias
    IS_MGM_RDY = (1 << 7),
236 93f1e401 Edgar E. Iglesias
    IS_PHY_RST_DONE = (1 << 8),
237 93f1e401 Edgar E. Iglesias
};
238 93f1e401 Edgar E. Iglesias
239 93f1e401 Edgar E. Iglesias
#define R_IP       (0x010 / 4)
240 93f1e401 Edgar E. Iglesias
#define R_IE       (0x014 / 4)
241 93f1e401 Edgar E. Iglesias
#define R_UAWL     (0x020 / 4)
242 93f1e401 Edgar E. Iglesias
#define R_UAWU     (0x024 / 4)
243 93f1e401 Edgar E. Iglesias
#define R_PPST     (0x030 / 4)
244 93f1e401 Edgar E. Iglesias
enum {
245 93f1e401 Edgar E. Iglesias
    PPST_LINKSTATUS = (1 << 0),
246 93f1e401 Edgar E. Iglesias
    PPST_PHY_LINKSTATUS = (1 << 7),
247 93f1e401 Edgar E. Iglesias
};
248 93f1e401 Edgar E. Iglesias
249 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BYTESL (0x200 / 4)
250 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BYTESH (0x204 / 4)
251 93f1e401 Edgar E. Iglesias
#define R_STATS_TX_BYTESL (0x208 / 4)
252 93f1e401 Edgar E. Iglesias
#define R_STATS_TX_BYTESH (0x20C / 4)
253 93f1e401 Edgar E. Iglesias
#define R_STATS_RXL       (0x290 / 4)
254 93f1e401 Edgar E. Iglesias
#define R_STATS_RXH       (0x294 / 4)
255 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BCASTL (0x2a0 / 4)
256 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BCASTH (0x2a4 / 4)
257 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_MCASTL (0x2a8 / 4)
258 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_MCASTH (0x2ac / 4)
259 93f1e401 Edgar E. Iglesias
260 93f1e401 Edgar E. Iglesias
#define R_RCW0     (0x400 / 4)
261 93f1e401 Edgar E. Iglesias
#define R_RCW1     (0x404 / 4)
262 93f1e401 Edgar E. Iglesias
enum {
263 93f1e401 Edgar E. Iglesias
    RCW1_VLAN = (1 << 27),
264 93f1e401 Edgar E. Iglesias
    RCW1_RX   = (1 << 28),
265 93f1e401 Edgar E. Iglesias
    RCW1_FCS  = (1 << 29),
266 93f1e401 Edgar E. Iglesias
    RCW1_JUM  = (1 << 30),
267 93f1e401 Edgar E. Iglesias
    RCW1_RST  = (1 << 31),
268 93f1e401 Edgar E. Iglesias
};
269 93f1e401 Edgar E. Iglesias
270 93f1e401 Edgar E. Iglesias
#define R_TC       (0x408 / 4)
271 93f1e401 Edgar E. Iglesias
enum {
272 93f1e401 Edgar E. Iglesias
    TC_VLAN = (1 << 27),
273 93f1e401 Edgar E. Iglesias
    TC_TX   = (1 << 28),
274 93f1e401 Edgar E. Iglesias
    TC_FCS  = (1 << 29),
275 93f1e401 Edgar E. Iglesias
    TC_JUM  = (1 << 30),
276 93f1e401 Edgar E. Iglesias
    TC_RST  = (1 << 31),
277 93f1e401 Edgar E. Iglesias
};
278 93f1e401 Edgar E. Iglesias
279 93f1e401 Edgar E. Iglesias
#define R_EMMC     (0x410 / 4)
280 93f1e401 Edgar E. Iglesias
enum {
281 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_10MB = (0 << 30),
282 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_100MB = (1 << 30),
283 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_1000MB = (2 << 30),
284 93f1e401 Edgar E. Iglesias
};
285 93f1e401 Edgar E. Iglesias
286 93f1e401 Edgar E. Iglesias
#define R_PHYC     (0x414 / 4)
287 93f1e401 Edgar E. Iglesias
288 93f1e401 Edgar E. Iglesias
#define R_MC       (0x500 / 4)
289 93f1e401 Edgar E. Iglesias
#define MC_EN      (1 << 6)
290 93f1e401 Edgar E. Iglesias
291 93f1e401 Edgar E. Iglesias
#define R_MCR      (0x504 / 4)
292 93f1e401 Edgar E. Iglesias
#define R_MWD      (0x508 / 4)
293 93f1e401 Edgar E. Iglesias
#define R_MRD      (0x50c / 4)
294 93f1e401 Edgar E. Iglesias
#define R_MIS      (0x600 / 4)
295 93f1e401 Edgar E. Iglesias
#define R_MIP      (0x620 / 4)
296 93f1e401 Edgar E. Iglesias
#define R_MIE      (0x640 / 4)
297 93f1e401 Edgar E. Iglesias
#define R_MIC      (0x640 / 4)
298 93f1e401 Edgar E. Iglesias
299 93f1e401 Edgar E. Iglesias
#define R_UAW0     (0x700 / 4)
300 93f1e401 Edgar E. Iglesias
#define R_UAW1     (0x704 / 4)
301 93f1e401 Edgar E. Iglesias
#define R_FMI      (0x708 / 4)
302 93f1e401 Edgar E. Iglesias
#define R_AF0      (0x710 / 4)
303 93f1e401 Edgar E. Iglesias
#define R_AF1      (0x714 / 4)
304 93f1e401 Edgar E. Iglesias
#define R_MAX      (0x34 / 4)
305 93f1e401 Edgar E. Iglesias
306 93f1e401 Edgar E. Iglesias
/* Indirect registers.  */
307 93f1e401 Edgar E. Iglesias
struct TEMAC  {
308 93f1e401 Edgar E. Iglesias
    struct MDIOBus mdio_bus;
309 93f1e401 Edgar E. Iglesias
    struct PHY phy;
310 93f1e401 Edgar E. Iglesias
311 93f1e401 Edgar E. Iglesias
    void *parent;
312 93f1e401 Edgar E. Iglesias
};
313 93f1e401 Edgar E. Iglesias
314 545129e5 Peter Crosthwaite
typedef struct XilinxAXIEnet XilinxAXIEnet;
315 545129e5 Peter Crosthwaite
316 93f1e401 Edgar E. Iglesias
struct XilinxAXIEnet {
317 93f1e401 Edgar E. Iglesias
    SysBusDevice busdev;
318 0dc31f3b Avi Kivity
    MemoryRegion iomem;
319 93f1e401 Edgar E. Iglesias
    qemu_irq irq;
320 669b4983 Peter A. G. Crosthwaite
    StreamSlave *tx_dev;
321 93f1e401 Edgar E. Iglesias
    NICState *nic;
322 93f1e401 Edgar E. Iglesias
    NICConf conf;
323 93f1e401 Edgar E. Iglesias
324 93f1e401 Edgar E. Iglesias
325 93f1e401 Edgar E. Iglesias
    uint32_t c_rxmem;
326 93f1e401 Edgar E. Iglesias
    uint32_t c_txmem;
327 93f1e401 Edgar E. Iglesias
    uint32_t c_phyaddr;
328 93f1e401 Edgar E. Iglesias
329 93f1e401 Edgar E. Iglesias
    struct TEMAC TEMAC;
330 93f1e401 Edgar E. Iglesias
331 93f1e401 Edgar E. Iglesias
    /* MII regs.  */
332 93f1e401 Edgar E. Iglesias
    union {
333 93f1e401 Edgar E. Iglesias
        uint32_t regs[4];
334 93f1e401 Edgar E. Iglesias
        struct {
335 93f1e401 Edgar E. Iglesias
            uint32_t mc;
336 93f1e401 Edgar E. Iglesias
            uint32_t mcr;
337 93f1e401 Edgar E. Iglesias
            uint32_t mwd;
338 93f1e401 Edgar E. Iglesias
            uint32_t mrd;
339 93f1e401 Edgar E. Iglesias
        };
340 93f1e401 Edgar E. Iglesias
    } mii;
341 93f1e401 Edgar E. Iglesias
342 93f1e401 Edgar E. Iglesias
    struct {
343 93f1e401 Edgar E. Iglesias
        uint64_t rx_bytes;
344 93f1e401 Edgar E. Iglesias
        uint64_t tx_bytes;
345 93f1e401 Edgar E. Iglesias
346 93f1e401 Edgar E. Iglesias
        uint64_t rx;
347 93f1e401 Edgar E. Iglesias
        uint64_t rx_bcast;
348 93f1e401 Edgar E. Iglesias
        uint64_t rx_mcast;
349 93f1e401 Edgar E. Iglesias
    } stats;
350 93f1e401 Edgar E. Iglesias
351 93f1e401 Edgar E. Iglesias
    /* Receive configuration words.  */
352 93f1e401 Edgar E. Iglesias
    uint32_t rcw[2];
353 93f1e401 Edgar E. Iglesias
    /* Transmit config.  */
354 93f1e401 Edgar E. Iglesias
    uint32_t tc;
355 93f1e401 Edgar E. Iglesias
    uint32_t emmc;
356 93f1e401 Edgar E. Iglesias
    uint32_t phyc;
357 93f1e401 Edgar E. Iglesias
358 93f1e401 Edgar E. Iglesias
    /* Unicast Address Word.  */
359 93f1e401 Edgar E. Iglesias
    uint32_t uaw[2];
360 93f1e401 Edgar E. Iglesias
    /* Unicast address filter used with extended mcast.  */
361 93f1e401 Edgar E. Iglesias
    uint32_t ext_uaw[2];
362 93f1e401 Edgar E. Iglesias
    uint32_t fmi;
363 93f1e401 Edgar E. Iglesias
364 93f1e401 Edgar E. Iglesias
    uint32_t regs[R_MAX];
365 93f1e401 Edgar E. Iglesias
366 93f1e401 Edgar E. Iglesias
    /* Multicast filter addrs.  */
367 93f1e401 Edgar E. Iglesias
    uint32_t maddr[4][2];
368 93f1e401 Edgar E. Iglesias
    /* 32K x 1 lookup filter.  */
369 93f1e401 Edgar E. Iglesias
    uint32_t ext_mtable[1024];
370 93f1e401 Edgar E. Iglesias
371 93f1e401 Edgar E. Iglesias
372 93f1e401 Edgar E. Iglesias
    uint8_t *rxmem;
373 93f1e401 Edgar E. Iglesias
};
374 93f1e401 Edgar E. Iglesias
375 545129e5 Peter Crosthwaite
static void axienet_rx_reset(XilinxAXIEnet *s)
376 93f1e401 Edgar E. Iglesias
{
377 93f1e401 Edgar E. Iglesias
    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
378 93f1e401 Edgar E. Iglesias
}
379 93f1e401 Edgar E. Iglesias
380 545129e5 Peter Crosthwaite
static void axienet_tx_reset(XilinxAXIEnet *s)
381 93f1e401 Edgar E. Iglesias
{
382 93f1e401 Edgar E. Iglesias
    s->tc = TC_JUM | TC_TX | TC_VLAN;
383 93f1e401 Edgar E. Iglesias
}
384 93f1e401 Edgar E. Iglesias
385 545129e5 Peter Crosthwaite
static inline int axienet_rx_resetting(XilinxAXIEnet *s)
386 93f1e401 Edgar E. Iglesias
{
387 93f1e401 Edgar E. Iglesias
    return s->rcw[1] & RCW1_RST;
388 93f1e401 Edgar E. Iglesias
}
389 93f1e401 Edgar E. Iglesias
390 545129e5 Peter Crosthwaite
static inline int axienet_rx_enabled(XilinxAXIEnet *s)
391 93f1e401 Edgar E. Iglesias
{
392 93f1e401 Edgar E. Iglesias
    return s->rcw[1] & RCW1_RX;
393 93f1e401 Edgar E. Iglesias
}
394 93f1e401 Edgar E. Iglesias
395 545129e5 Peter Crosthwaite
static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
396 93f1e401 Edgar E. Iglesias
{
397 93f1e401 Edgar E. Iglesias
    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
398 93f1e401 Edgar E. Iglesias
}
399 93f1e401 Edgar E. Iglesias
400 545129e5 Peter Crosthwaite
static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
401 93f1e401 Edgar E. Iglesias
{
402 93f1e401 Edgar E. Iglesias
    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
403 93f1e401 Edgar E. Iglesias
}
404 93f1e401 Edgar E. Iglesias
405 545129e5 Peter Crosthwaite
static void axienet_reset(XilinxAXIEnet *s)
406 93f1e401 Edgar E. Iglesias
{
407 93f1e401 Edgar E. Iglesias
    axienet_rx_reset(s);
408 93f1e401 Edgar E. Iglesias
    axienet_tx_reset(s);
409 93f1e401 Edgar E. Iglesias
410 93f1e401 Edgar E. Iglesias
    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
411 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
412 93f1e401 Edgar E. Iglesias
413 93f1e401 Edgar E. Iglesias
    s->emmc = EMMC_LINKSPEED_100MB;
414 93f1e401 Edgar E. Iglesias
}
415 93f1e401 Edgar E. Iglesias
416 545129e5 Peter Crosthwaite
static void enet_update_irq(XilinxAXIEnet *s)
417 93f1e401 Edgar E. Iglesias
{
418 93f1e401 Edgar E. Iglesias
    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
419 93f1e401 Edgar E. Iglesias
    qemu_set_irq(s->irq, !!s->regs[R_IP]);
420 93f1e401 Edgar E. Iglesias
}
421 93f1e401 Edgar E. Iglesias
422 a8170e5e Avi Kivity
static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
423 93f1e401 Edgar E. Iglesias
{
424 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = opaque;
425 93f1e401 Edgar E. Iglesias
    uint32_t r = 0;
426 93f1e401 Edgar E. Iglesias
    addr >>= 2;
427 93f1e401 Edgar E. Iglesias
428 93f1e401 Edgar E. Iglesias
    switch (addr) {
429 93f1e401 Edgar E. Iglesias
        case R_RCW0:
430 93f1e401 Edgar E. Iglesias
        case R_RCW1:
431 93f1e401 Edgar E. Iglesias
            r = s->rcw[addr & 1];
432 93f1e401 Edgar E. Iglesias
            break;
433 93f1e401 Edgar E. Iglesias
434 93f1e401 Edgar E. Iglesias
        case R_TC:
435 93f1e401 Edgar E. Iglesias
            r = s->tc;
436 93f1e401 Edgar E. Iglesias
            break;
437 93f1e401 Edgar E. Iglesias
438 93f1e401 Edgar E. Iglesias
        case R_EMMC:
439 93f1e401 Edgar E. Iglesias
            r = s->emmc;
440 93f1e401 Edgar E. Iglesias
            break;
441 93f1e401 Edgar E. Iglesias
442 93f1e401 Edgar E. Iglesias
        case R_PHYC:
443 93f1e401 Edgar E. Iglesias
            r = s->phyc;
444 93f1e401 Edgar E. Iglesias
            break;
445 93f1e401 Edgar E. Iglesias
446 93f1e401 Edgar E. Iglesias
        case R_MCR:
447 93f1e401 Edgar E. Iglesias
            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
448 93f1e401 Edgar E. Iglesias
            break;
449 93f1e401 Edgar E. Iglesias
450 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BYTESL:
451 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BYTESH:
452 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_bytes >> (32 * (addr & 1));
453 93f1e401 Edgar E. Iglesias
            break;
454 93f1e401 Edgar E. Iglesias
455 93f1e401 Edgar E. Iglesias
        case R_STATS_TX_BYTESL:
456 93f1e401 Edgar E. Iglesias
        case R_STATS_TX_BYTESH:
457 93f1e401 Edgar E. Iglesias
            r = s->stats.tx_bytes >> (32 * (addr & 1));
458 93f1e401 Edgar E. Iglesias
            break;
459 93f1e401 Edgar E. Iglesias
460 93f1e401 Edgar E. Iglesias
        case R_STATS_RXL:
461 93f1e401 Edgar E. Iglesias
        case R_STATS_RXH:
462 93f1e401 Edgar E. Iglesias
            r = s->stats.rx >> (32 * (addr & 1));
463 93f1e401 Edgar E. Iglesias
            break;
464 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BCASTL:
465 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BCASTH:
466 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_bcast >> (32 * (addr & 1));
467 93f1e401 Edgar E. Iglesias
            break;
468 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_MCASTL:
469 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_MCASTH:
470 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_mcast >> (32 * (addr & 1));
471 93f1e401 Edgar E. Iglesias
            break;
472 93f1e401 Edgar E. Iglesias
473 93f1e401 Edgar E. Iglesias
        case R_MC:
474 93f1e401 Edgar E. Iglesias
        case R_MWD:
475 93f1e401 Edgar E. Iglesias
        case R_MRD:
476 93f1e401 Edgar E. Iglesias
            r = s->mii.regs[addr & 3];
477 93f1e401 Edgar E. Iglesias
            break;
478 93f1e401 Edgar E. Iglesias
479 93f1e401 Edgar E. Iglesias
        case R_UAW0:
480 93f1e401 Edgar E. Iglesias
        case R_UAW1:
481 93f1e401 Edgar E. Iglesias
            r = s->uaw[addr & 1];
482 93f1e401 Edgar E. Iglesias
            break;
483 93f1e401 Edgar E. Iglesias
484 93f1e401 Edgar E. Iglesias
        case R_UAWU:
485 93f1e401 Edgar E. Iglesias
        case R_UAWL:
486 93f1e401 Edgar E. Iglesias
            r = s->ext_uaw[addr & 1];
487 93f1e401 Edgar E. Iglesias
            break;
488 93f1e401 Edgar E. Iglesias
489 93f1e401 Edgar E. Iglesias
        case R_FMI:
490 93f1e401 Edgar E. Iglesias
            r = s->fmi;
491 93f1e401 Edgar E. Iglesias
            break;
492 93f1e401 Edgar E. Iglesias
493 93f1e401 Edgar E. Iglesias
        case R_AF0:
494 93f1e401 Edgar E. Iglesias
        case R_AF1:
495 93f1e401 Edgar E. Iglesias
            r = s->maddr[s->fmi & 3][addr & 1];
496 93f1e401 Edgar E. Iglesias
            break;
497 93f1e401 Edgar E. Iglesias
498 93f1e401 Edgar E. Iglesias
        case 0x8000 ... 0x83ff:
499 93f1e401 Edgar E. Iglesias
            r = s->ext_mtable[addr - 0x8000];
500 93f1e401 Edgar E. Iglesias
            break;
501 93f1e401 Edgar E. Iglesias
502 93f1e401 Edgar E. Iglesias
        default:
503 93f1e401 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(s->regs)) {
504 93f1e401 Edgar E. Iglesias
                r = s->regs[addr];
505 93f1e401 Edgar E. Iglesias
            }
506 93f1e401 Edgar E. Iglesias
            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
507 93f1e401 Edgar E. Iglesias
                            __func__, addr * 4, r));
508 93f1e401 Edgar E. Iglesias
            break;
509 93f1e401 Edgar E. Iglesias
    }
510 93f1e401 Edgar E. Iglesias
    return r;
511 93f1e401 Edgar E. Iglesias
}
512 93f1e401 Edgar E. Iglesias
513 a8170e5e Avi Kivity
static void enet_write(void *opaque, hwaddr addr,
514 0dc31f3b Avi Kivity
                       uint64_t value, unsigned size)
515 93f1e401 Edgar E. Iglesias
{
516 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = opaque;
517 93f1e401 Edgar E. Iglesias
    struct TEMAC *t = &s->TEMAC;
518 93f1e401 Edgar E. Iglesias
519 93f1e401 Edgar E. Iglesias
    addr >>= 2;
520 93f1e401 Edgar E. Iglesias
    switch (addr) {
521 93f1e401 Edgar E. Iglesias
        case R_RCW0:
522 93f1e401 Edgar E. Iglesias
        case R_RCW1:
523 93f1e401 Edgar E. Iglesias
            s->rcw[addr & 1] = value;
524 93f1e401 Edgar E. Iglesias
            if ((addr & 1) && value & RCW1_RST) {
525 93f1e401 Edgar E. Iglesias
                axienet_rx_reset(s);
526 4dbb9ed3 Peter Crosthwaite
            } else {
527 4dbb9ed3 Peter Crosthwaite
                qemu_flush_queued_packets(qemu_get_queue(s->nic));
528 93f1e401 Edgar E. Iglesias
            }
529 93f1e401 Edgar E. Iglesias
            break;
530 93f1e401 Edgar E. Iglesias
531 93f1e401 Edgar E. Iglesias
        case R_TC:
532 93f1e401 Edgar E. Iglesias
            s->tc = value;
533 93f1e401 Edgar E. Iglesias
            if (value & TC_RST) {
534 93f1e401 Edgar E. Iglesias
                axienet_tx_reset(s);
535 93f1e401 Edgar E. Iglesias
            }
536 93f1e401 Edgar E. Iglesias
            break;
537 93f1e401 Edgar E. Iglesias
538 93f1e401 Edgar E. Iglesias
        case R_EMMC:
539 93f1e401 Edgar E. Iglesias
            s->emmc = value;
540 93f1e401 Edgar E. Iglesias
            break;
541 93f1e401 Edgar E. Iglesias
542 93f1e401 Edgar E. Iglesias
        case R_PHYC:
543 93f1e401 Edgar E. Iglesias
            s->phyc = value;
544 93f1e401 Edgar E. Iglesias
            break;
545 93f1e401 Edgar E. Iglesias
546 93f1e401 Edgar E. Iglesias
        case R_MC:
547 93f1e401 Edgar E. Iglesias
             value &= ((1 < 7) - 1);
548 93f1e401 Edgar E. Iglesias
549 93f1e401 Edgar E. Iglesias
             /* Enable the MII.  */
550 93f1e401 Edgar E. Iglesias
             if (value & MC_EN) {
551 93f1e401 Edgar E. Iglesias
                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
552 93f1e401 Edgar E. Iglesias
                 if (!miiclkdiv) {
553 93f1e401 Edgar E. Iglesias
                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
554 93f1e401 Edgar E. Iglesias
                 }
555 93f1e401 Edgar E. Iglesias
             }
556 93f1e401 Edgar E. Iglesias
             s->mii.mc = value;
557 93f1e401 Edgar E. Iglesias
             break;
558 93f1e401 Edgar E. Iglesias
559 93f1e401 Edgar E. Iglesias
        case R_MCR: {
560 93f1e401 Edgar E. Iglesias
             unsigned int phyaddr = (value >> 24) & 0x1f;
561 93f1e401 Edgar E. Iglesias
             unsigned int regaddr = (value >> 16) & 0x1f;
562 93f1e401 Edgar E. Iglesias
             unsigned int op = (value >> 14) & 3;
563 93f1e401 Edgar E. Iglesias
             unsigned int initiate = (value >> 11) & 1;
564 93f1e401 Edgar E. Iglesias
565 93f1e401 Edgar E. Iglesias
             if (initiate) {
566 93f1e401 Edgar E. Iglesias
                 if (op == 1) {
567 93f1e401 Edgar E. Iglesias
                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
568 93f1e401 Edgar E. Iglesias
                 } else if (op == 2) {
569 93f1e401 Edgar E. Iglesias
                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
570 93f1e401 Edgar E. Iglesias
                 } else {
571 93f1e401 Edgar E. Iglesias
                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
572 93f1e401 Edgar E. Iglesias
                 }
573 93f1e401 Edgar E. Iglesias
             }
574 93f1e401 Edgar E. Iglesias
             s->mii.mcr = value;
575 93f1e401 Edgar E. Iglesias
             break;
576 93f1e401 Edgar E. Iglesias
        }
577 93f1e401 Edgar E. Iglesias
578 93f1e401 Edgar E. Iglesias
        case R_MWD:
579 93f1e401 Edgar E. Iglesias
        case R_MRD:
580 93f1e401 Edgar E. Iglesias
             s->mii.regs[addr & 3] = value;
581 93f1e401 Edgar E. Iglesias
             break;
582 93f1e401 Edgar E. Iglesias
583 93f1e401 Edgar E. Iglesias
584 93f1e401 Edgar E. Iglesias
        case R_UAW0:
585 93f1e401 Edgar E. Iglesias
        case R_UAW1:
586 93f1e401 Edgar E. Iglesias
            s->uaw[addr & 1] = value;
587 93f1e401 Edgar E. Iglesias
            break;
588 93f1e401 Edgar E. Iglesias
589 93f1e401 Edgar E. Iglesias
        case R_UAWL:
590 93f1e401 Edgar E. Iglesias
        case R_UAWU:
591 93f1e401 Edgar E. Iglesias
            s->ext_uaw[addr & 1] = value;
592 93f1e401 Edgar E. Iglesias
            break;
593 93f1e401 Edgar E. Iglesias
594 93f1e401 Edgar E. Iglesias
        case R_FMI:
595 93f1e401 Edgar E. Iglesias
            s->fmi = value;
596 93f1e401 Edgar E. Iglesias
            break;
597 93f1e401 Edgar E. Iglesias
598 93f1e401 Edgar E. Iglesias
        case R_AF0:
599 93f1e401 Edgar E. Iglesias
        case R_AF1:
600 93f1e401 Edgar E. Iglesias
            s->maddr[s->fmi & 3][addr & 1] = value;
601 93f1e401 Edgar E. Iglesias
            break;
602 93f1e401 Edgar E. Iglesias
603 d4d230da Peter Crosthwaite
        case R_IS:
604 d4d230da Peter Crosthwaite
            s->regs[addr] &= ~value;
605 d4d230da Peter Crosthwaite
            break;
606 d4d230da Peter Crosthwaite
607 93f1e401 Edgar E. Iglesias
        case 0x8000 ... 0x83ff:
608 93f1e401 Edgar E. Iglesias
            s->ext_mtable[addr - 0x8000] = value;
609 93f1e401 Edgar E. Iglesias
            break;
610 93f1e401 Edgar E. Iglesias
611 93f1e401 Edgar E. Iglesias
        default:
612 93f1e401 Edgar E. Iglesias
            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
613 0dc31f3b Avi Kivity
                           __func__, addr * 4, (unsigned)value));
614 93f1e401 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(s->regs)) {
615 93f1e401 Edgar E. Iglesias
                s->regs[addr] = value;
616 93f1e401 Edgar E. Iglesias
            }
617 93f1e401 Edgar E. Iglesias
            break;
618 93f1e401 Edgar E. Iglesias
    }
619 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
620 93f1e401 Edgar E. Iglesias
}
621 93f1e401 Edgar E. Iglesias
622 0dc31f3b Avi Kivity
static const MemoryRegionOps enet_ops = {
623 0dc31f3b Avi Kivity
    .read = enet_read,
624 0dc31f3b Avi Kivity
    .write = enet_write,
625 0dc31f3b Avi Kivity
    .endianness = DEVICE_LITTLE_ENDIAN,
626 93f1e401 Edgar E. Iglesias
};
627 93f1e401 Edgar E. Iglesias
628 4e68f7a0 Stefan Hajnoczi
static int eth_can_rx(NetClientState *nc)
629 93f1e401 Edgar E. Iglesias
{
630 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
631 93f1e401 Edgar E. Iglesias
632 93f1e401 Edgar E. Iglesias
    /* RX enabled?  */
633 93f1e401 Edgar E. Iglesias
    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
634 93f1e401 Edgar E. Iglesias
}
635 93f1e401 Edgar E. Iglesias
636 93f1e401 Edgar E. Iglesias
static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
637 93f1e401 Edgar E. Iglesias
{
638 93f1e401 Edgar E. Iglesias
    int match = 1;
639 93f1e401 Edgar E. Iglesias
640 93f1e401 Edgar E. Iglesias
    if (memcmp(buf, &f0, 4)) {
641 93f1e401 Edgar E. Iglesias
        match = 0;
642 93f1e401 Edgar E. Iglesias
    }
643 93f1e401 Edgar E. Iglesias
644 93f1e401 Edgar E. Iglesias
    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
645 93f1e401 Edgar E. Iglesias
        match = 0;
646 93f1e401 Edgar E. Iglesias
    }
647 93f1e401 Edgar E. Iglesias
648 93f1e401 Edgar E. Iglesias
    return match;
649 93f1e401 Edgar E. Iglesias
}
650 93f1e401 Edgar E. Iglesias
651 4e68f7a0 Stefan Hajnoczi
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
652 93f1e401 Edgar E. Iglesias
{
653 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
654 93f1e401 Edgar E. Iglesias
    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
655 93f1e401 Edgar E. Iglesias
                                              0xff, 0xff, 0xff};
656 93f1e401 Edgar E. Iglesias
    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
657 93f1e401 Edgar E. Iglesias
    uint32_t app[6] = {0};
658 93f1e401 Edgar E. Iglesias
    int promisc = s->fmi & (1 << 31);
659 93f1e401 Edgar E. Iglesias
    int unicast, broadcast, multicast, ip_multicast = 0;
660 93f1e401 Edgar E. Iglesias
    uint32_t csum32;
661 93f1e401 Edgar E. Iglesias
    uint16_t csum16;
662 93f1e401 Edgar E. Iglesias
    int i;
663 93f1e401 Edgar E. Iglesias
664 93f1e401 Edgar E. Iglesias
    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
665 93f1e401 Edgar E. Iglesias
666 93f1e401 Edgar E. Iglesias
    unicast = ~buf[0] & 0x1;
667 93f1e401 Edgar E. Iglesias
    broadcast = memcmp(buf, sa_bcast, 6) == 0;
668 93f1e401 Edgar E. Iglesias
    multicast = !unicast && !broadcast;
669 93f1e401 Edgar E. Iglesias
    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
670 93f1e401 Edgar E. Iglesias
        ip_multicast = 1;
671 93f1e401 Edgar E. Iglesias
    }
672 93f1e401 Edgar E. Iglesias
673 93f1e401 Edgar E. Iglesias
    /* Jumbo or vlan sizes ?  */
674 93f1e401 Edgar E. Iglesias
    if (!(s->rcw[1] & RCW1_JUM)) {
675 93f1e401 Edgar E. Iglesias
        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
676 93f1e401 Edgar E. Iglesias
            return size;
677 93f1e401 Edgar E. Iglesias
        }
678 93f1e401 Edgar E. Iglesias
    }
679 93f1e401 Edgar E. Iglesias
680 93f1e401 Edgar E. Iglesias
    /* Basic Address filters.  If you want to use the extended filters
681 93f1e401 Edgar E. Iglesias
       you'll generally have to place the ethernet mac into promiscuous mode
682 93f1e401 Edgar E. Iglesias
       to avoid the basic filtering from dropping most frames.  */
683 93f1e401 Edgar E. Iglesias
    if (!promisc) {
684 93f1e401 Edgar E. Iglesias
        if (unicast) {
685 93f1e401 Edgar E. Iglesias
            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
686 93f1e401 Edgar E. Iglesias
                return size;
687 93f1e401 Edgar E. Iglesias
            }
688 93f1e401 Edgar E. Iglesias
        } else {
689 93f1e401 Edgar E. Iglesias
            if (broadcast) {
690 93f1e401 Edgar E. Iglesias
                /* Broadcast.  */
691 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
692 93f1e401 Edgar E. Iglesias
                    return size;
693 93f1e401 Edgar E. Iglesias
                }
694 93f1e401 Edgar E. Iglesias
            } else {
695 93f1e401 Edgar E. Iglesias
                int drop = 1;
696 93f1e401 Edgar E. Iglesias
697 93f1e401 Edgar E. Iglesias
                /* Multicast.  */
698 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
699 93f1e401 Edgar E. Iglesias
                    return size;
700 93f1e401 Edgar E. Iglesias
                }
701 93f1e401 Edgar E. Iglesias
702 93f1e401 Edgar E. Iglesias
                for (i = 0; i < 4; i++) {
703 93f1e401 Edgar E. Iglesias
                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
704 93f1e401 Edgar E. Iglesias
                        drop = 0;
705 93f1e401 Edgar E. Iglesias
                        break;
706 93f1e401 Edgar E. Iglesias
                    }
707 93f1e401 Edgar E. Iglesias
                }
708 93f1e401 Edgar E. Iglesias
709 93f1e401 Edgar E. Iglesias
                if (drop) {
710 93f1e401 Edgar E. Iglesias
                    return size;
711 93f1e401 Edgar E. Iglesias
                }
712 93f1e401 Edgar E. Iglesias
            }
713 93f1e401 Edgar E. Iglesias
        }
714 93f1e401 Edgar E. Iglesias
    }
715 93f1e401 Edgar E. Iglesias
716 93f1e401 Edgar E. Iglesias
    /* Extended mcast filtering enabled?  */
717 93f1e401 Edgar E. Iglesias
    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
718 93f1e401 Edgar E. Iglesias
        if (unicast) {
719 93f1e401 Edgar E. Iglesias
            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
720 93f1e401 Edgar E. Iglesias
                return size;
721 93f1e401 Edgar E. Iglesias
            }
722 93f1e401 Edgar E. Iglesias
        } else {
723 93f1e401 Edgar E. Iglesias
            if (broadcast) {
724 93f1e401 Edgar E. Iglesias
                /* Broadcast. ???  */
725 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
726 93f1e401 Edgar E. Iglesias
                    return size;
727 93f1e401 Edgar E. Iglesias
                }
728 93f1e401 Edgar E. Iglesias
            } else {
729 93f1e401 Edgar E. Iglesias
                int idx, bit;
730 93f1e401 Edgar E. Iglesias
731 93f1e401 Edgar E. Iglesias
                /* Multicast.  */
732 93f1e401 Edgar E. Iglesias
                if (!memcmp(buf, sa_ipmcast, 3)) {
733 93f1e401 Edgar E. Iglesias
                    return size;
734 93f1e401 Edgar E. Iglesias
                }
735 93f1e401 Edgar E. Iglesias
736 93f1e401 Edgar E. Iglesias
                idx  = (buf[4] & 0x7f) << 8;
737 93f1e401 Edgar E. Iglesias
                idx |= buf[5];
738 93f1e401 Edgar E. Iglesias
739 93f1e401 Edgar E. Iglesias
                bit = 1 << (idx & 0x1f);
740 93f1e401 Edgar E. Iglesias
                idx >>= 5;
741 93f1e401 Edgar E. Iglesias
742 93f1e401 Edgar E. Iglesias
                if (!(s->ext_mtable[idx] & bit)) {
743 93f1e401 Edgar E. Iglesias
                    return size;
744 93f1e401 Edgar E. Iglesias
                }
745 93f1e401 Edgar E. Iglesias
            }
746 93f1e401 Edgar E. Iglesias
        }
747 93f1e401 Edgar E. Iglesias
    }
748 93f1e401 Edgar E. Iglesias
749 93f1e401 Edgar E. Iglesias
    if (size < 12) {
750 93f1e401 Edgar E. Iglesias
        s->regs[R_IS] |= IS_RX_REJECT;
751 93f1e401 Edgar E. Iglesias
        enet_update_irq(s);
752 93f1e401 Edgar E. Iglesias
        return -1;
753 93f1e401 Edgar E. Iglesias
    }
754 93f1e401 Edgar E. Iglesias
755 93f1e401 Edgar E. Iglesias
    if (size > (s->c_rxmem - 4)) {
756 93f1e401 Edgar E. Iglesias
        size = s->c_rxmem - 4;
757 93f1e401 Edgar E. Iglesias
    }
758 93f1e401 Edgar E. Iglesias
759 93f1e401 Edgar E. Iglesias
    memcpy(s->rxmem, buf, size);
760 93f1e401 Edgar E. Iglesias
    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
761 93f1e401 Edgar E. Iglesias
762 93f1e401 Edgar E. Iglesias
    if (s->rcw[1] & RCW1_FCS) {
763 93f1e401 Edgar E. Iglesias
        size += 4; /* fcs is inband.  */
764 93f1e401 Edgar E. Iglesias
    }
765 93f1e401 Edgar E. Iglesias
766 93f1e401 Edgar E. Iglesias
    app[0] = 5 << 28;
767 93f1e401 Edgar E. Iglesias
    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
768 93f1e401 Edgar E. Iglesias
    /* Fold it once.  */
769 93f1e401 Edgar E. Iglesias
    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
770 93f1e401 Edgar E. Iglesias
    /* And twice to get rid of possible carries.  */
771 93f1e401 Edgar E. Iglesias
    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
772 93f1e401 Edgar E. Iglesias
    app[3] = csum16;
773 93f1e401 Edgar E. Iglesias
    app[4] = size & 0xffff;
774 93f1e401 Edgar E. Iglesias
775 93f1e401 Edgar E. Iglesias
    s->stats.rx_bytes += size;
776 93f1e401 Edgar E. Iglesias
    s->stats.rx++;
777 93f1e401 Edgar E. Iglesias
    if (multicast) {
778 93f1e401 Edgar E. Iglesias
        s->stats.rx_mcast++;
779 93f1e401 Edgar E. Iglesias
        app[2] |= 1 | (ip_multicast << 1);
780 93f1e401 Edgar E. Iglesias
    } else if (broadcast) {
781 93f1e401 Edgar E. Iglesias
        s->stats.rx_bcast++;
782 93f1e401 Edgar E. Iglesias
        app[2] |= 1 << 3;
783 93f1e401 Edgar E. Iglesias
    }
784 93f1e401 Edgar E. Iglesias
785 93f1e401 Edgar E. Iglesias
    /* Good frame.  */
786 93f1e401 Edgar E. Iglesias
    app[2] |= 1 << 6;
787 93f1e401 Edgar E. Iglesias
788 669b4983 Peter A. G. Crosthwaite
    stream_push(s->tx_dev, (void *)s->rxmem, size, app);
789 93f1e401 Edgar E. Iglesias
790 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] |= IS_RX_COMPLETE;
791 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
792 93f1e401 Edgar E. Iglesias
    return size;
793 93f1e401 Edgar E. Iglesias
}
794 93f1e401 Edgar E. Iglesias
795 4e68f7a0 Stefan Hajnoczi
static void eth_cleanup(NetClientState *nc)
796 93f1e401 Edgar E. Iglesias
{
797 93f1e401 Edgar E. Iglesias
    /* FIXME.  */
798 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
799 7267c094 Anthony Liguori
    g_free(s->rxmem);
800 7267c094 Anthony Liguori
    g_free(s);
801 93f1e401 Edgar E. Iglesias
}
802 93f1e401 Edgar E. Iglesias
803 93f1e401 Edgar E. Iglesias
static void
804 669b4983 Peter A. G. Crosthwaite
axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
805 93f1e401 Edgar E. Iglesias
{
806 545129e5 Peter Crosthwaite
    XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
807 93f1e401 Edgar E. Iglesias
808 93f1e401 Edgar E. Iglesias
    /* TX enable ?  */
809 93f1e401 Edgar E. Iglesias
    if (!(s->tc & TC_TX)) {
810 93f1e401 Edgar E. Iglesias
        return;
811 93f1e401 Edgar E. Iglesias
    }
812 93f1e401 Edgar E. Iglesias
813 93f1e401 Edgar E. Iglesias
    /* Jumbo or vlan sizes ?  */
814 93f1e401 Edgar E. Iglesias
    if (!(s->tc & TC_JUM)) {
815 93f1e401 Edgar E. Iglesias
        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
816 93f1e401 Edgar E. Iglesias
            return;
817 93f1e401 Edgar E. Iglesias
        }
818 93f1e401 Edgar E. Iglesias
    }
819 93f1e401 Edgar E. Iglesias
820 93f1e401 Edgar E. Iglesias
    if (hdr[0] & 1) {
821 93f1e401 Edgar E. Iglesias
        unsigned int start_off = hdr[1] >> 16;
822 93f1e401 Edgar E. Iglesias
        unsigned int write_off = hdr[1] & 0xffff;
823 93f1e401 Edgar E. Iglesias
        uint32_t tmp_csum;
824 93f1e401 Edgar E. Iglesias
        uint16_t csum;
825 93f1e401 Edgar E. Iglesias
826 93f1e401 Edgar E. Iglesias
        tmp_csum = net_checksum_add(size - start_off,
827 93f1e401 Edgar E. Iglesias
                                    (uint8_t *)buf + start_off);
828 93f1e401 Edgar E. Iglesias
        /* Accumulate the seed.  */
829 93f1e401 Edgar E. Iglesias
        tmp_csum += hdr[2] & 0xffff;
830 93f1e401 Edgar E. Iglesias
831 93f1e401 Edgar E. Iglesias
        /* Fold the 32bit partial checksum.  */
832 93f1e401 Edgar E. Iglesias
        csum = net_checksum_finish(tmp_csum);
833 93f1e401 Edgar E. Iglesias
834 93f1e401 Edgar E. Iglesias
        /* Writeback.  */
835 93f1e401 Edgar E. Iglesias
        buf[write_off] = csum >> 8;
836 93f1e401 Edgar E. Iglesias
        buf[write_off + 1] = csum & 0xff;
837 93f1e401 Edgar E. Iglesias
    }
838 93f1e401 Edgar E. Iglesias
839 b356f76d Jason Wang
    qemu_send_packet(qemu_get_queue(s->nic), buf, size);
840 93f1e401 Edgar E. Iglesias
841 93f1e401 Edgar E. Iglesias
    s->stats.tx_bytes += size;
842 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] |= IS_TX_COMPLETE;
843 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
844 93f1e401 Edgar E. Iglesias
}
845 93f1e401 Edgar E. Iglesias
846 93f1e401 Edgar E. Iglesias
static NetClientInfo net_xilinx_enet_info = {
847 2be64a68 Laszlo Ersek
    .type = NET_CLIENT_OPTIONS_KIND_NIC,
848 93f1e401 Edgar E. Iglesias
    .size = sizeof(NICState),
849 93f1e401 Edgar E. Iglesias
    .can_receive = eth_can_rx,
850 93f1e401 Edgar E. Iglesias
    .receive = eth_rx,
851 93f1e401 Edgar E. Iglesias
    .cleanup = eth_cleanup,
852 93f1e401 Edgar E. Iglesias
};
853 93f1e401 Edgar E. Iglesias
854 93f1e401 Edgar E. Iglesias
static int xilinx_enet_init(SysBusDevice *dev)
855 93f1e401 Edgar E. Iglesias
{
856 f0e7a81c Peter Crosthwaite
    XilinxAXIEnet *s = XILINX_AXI_ENET(dev);
857 93f1e401 Edgar E. Iglesias
858 93f1e401 Edgar E. Iglesias
    sysbus_init_irq(dev, &s->irq);
859 93f1e401 Edgar E. Iglesias
860 0dc31f3b Avi Kivity
    memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
861 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
862 93f1e401 Edgar E. Iglesias
863 93f1e401 Edgar E. Iglesias
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
864 93f1e401 Edgar E. Iglesias
    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
865 f79f2bfc Anthony Liguori
                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
866 b356f76d Jason Wang
    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
867 93f1e401 Edgar E. Iglesias
868 93f1e401 Edgar E. Iglesias
    tdk_init(&s->TEMAC.phy);
869 93f1e401 Edgar E. Iglesias
    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
870 93f1e401 Edgar E. Iglesias
871 93f1e401 Edgar E. Iglesias
    s->TEMAC.parent = s;
872 93f1e401 Edgar E. Iglesias
873 7267c094 Anthony Liguori
    s->rxmem = g_malloc(s->c_rxmem);
874 93f1e401 Edgar E. Iglesias
    axienet_reset(s);
875 93f1e401 Edgar E. Iglesias
876 93f1e401 Edgar E. Iglesias
    return 0;
877 93f1e401 Edgar E. Iglesias
}
878 93f1e401 Edgar E. Iglesias
879 669b4983 Peter A. G. Crosthwaite
static void xilinx_enet_initfn(Object *obj)
880 669b4983 Peter A. G. Crosthwaite
{
881 f0e7a81c Peter Crosthwaite
    XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
882 b15aaca4 Peter Crosthwaite
    Error *errp = NULL;
883 669b4983 Peter A. G. Crosthwaite
884 669b4983 Peter A. G. Crosthwaite
    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
885 b15aaca4 Peter Crosthwaite
                             (Object **) &s->tx_dev, &errp);
886 b15aaca4 Peter Crosthwaite
    assert_no_error(errp);
887 669b4983 Peter A. G. Crosthwaite
}
888 669b4983 Peter A. G. Crosthwaite
889 999e12bb Anthony Liguori
static Property xilinx_enet_properties[] = {
890 545129e5 Peter Crosthwaite
    DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
891 545129e5 Peter Crosthwaite
    DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
892 545129e5 Peter Crosthwaite
    DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
893 545129e5 Peter Crosthwaite
    DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
894 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
895 999e12bb Anthony Liguori
};
896 999e12bb Anthony Liguori
897 999e12bb Anthony Liguori
static void xilinx_enet_class_init(ObjectClass *klass, void *data)
898 999e12bb Anthony Liguori
{
899 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
900 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
901 669b4983 Peter A. G. Crosthwaite
    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
902 999e12bb Anthony Liguori
903 999e12bb Anthony Liguori
    k->init = xilinx_enet_init;
904 39bffca2 Anthony Liguori
    dc->props = xilinx_enet_properties;
905 669b4983 Peter A. G. Crosthwaite
    ssc->push = axienet_stream_push;
906 999e12bb Anthony Liguori
}
907 999e12bb Anthony Liguori
908 8c43a6f0 Andreas Färber
static const TypeInfo xilinx_enet_info = {
909 f0e7a81c Peter Crosthwaite
    .name          = TYPE_XILINX_AXI_ENET,
910 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
911 545129e5 Peter Crosthwaite
    .instance_size = sizeof(XilinxAXIEnet),
912 39bffca2 Anthony Liguori
    .class_init    = xilinx_enet_class_init,
913 669b4983 Peter A. G. Crosthwaite
    .instance_init = xilinx_enet_initfn,
914 669b4983 Peter A. G. Crosthwaite
    .interfaces = (InterfaceInfo[]) {
915 669b4983 Peter A. G. Crosthwaite
            { TYPE_STREAM_SLAVE },
916 669b4983 Peter A. G. Crosthwaite
            { }
917 669b4983 Peter A. G. Crosthwaite
    }
918 93f1e401 Edgar E. Iglesias
};
919 83f7d43a Andreas Färber
920 83f7d43a Andreas Färber
static void xilinx_enet_register_types(void)
921 93f1e401 Edgar E. Iglesias
{
922 39bffca2 Anthony Liguori
    type_register_static(&xilinx_enet_info);
923 93f1e401 Edgar E. Iglesias
}
924 93f1e401 Edgar E. Iglesias
925 83f7d43a Andreas Färber
type_init(xilinx_enet_register_types)