Statistics
| Branch: | Revision:

root / hw / xilinx_axienet.c @ 079d0b7f

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