Fix OpenSolaris build breaking typos
[qemu] / hw / xilinx_ethlite.c
1 /*
2  * QEMU model of the Xilinx Ethernet Lite MAC.
3  *
4  * Copyright (c) 2009 Edgar E. Iglesias.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "sysbus.h"
26 #include "hw.h"
27 #include "net.h"
28
29 #define D(x)
30 #define R_TX_BUF0     0
31 #define R_TX_LEN0     (0x07f4 / 4)
32 #define R_TX_GIE0     (0x07f8 / 4)
33 #define R_TX_CTRL0    (0x07fc / 4)
34 #define R_TX_BUF1     (0x0800 / 4)
35 #define R_TX_LEN1     (0x0ff4 / 4)
36 #define R_TX_CTRL1    (0x0ffc / 4)
37
38 #define R_RX_BUF0     (0x1000 / 4)
39 #define R_RX_CTRL0    (0x17fc / 4)
40 #define R_RX_BUF1     (0x1800 / 4)
41 #define R_RX_CTRL1    (0x1ffc / 4)
42 #define R_MAX         (0x2000 / 4)
43
44 #define GIE_GIE    0x80000000
45
46 #define CTRL_I     0x8
47 #define CTRL_P     0x2
48 #define CTRL_S     0x1
49
50 struct xlx_ethlite
51 {
52     SysBusDevice busdev;
53     qemu_irq irq;
54     VLANClientState *vc;
55
56     uint32_t c_tx_pingpong;
57     uint32_t c_rx_pingpong;
58     unsigned int txbuf;
59     unsigned int rxbuf;
60
61     uint8_t macaddr[6];
62     uint32_t regs[R_MAX];
63 };
64
65 static inline void eth_pulse_irq(struct xlx_ethlite *s)
66 {
67     /* Only the first gie reg is active.  */
68     if (s->regs[R_TX_GIE0] & GIE_GIE) {
69         qemu_irq_pulse(s->irq);
70     }
71 }
72
73 static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
74 {
75     struct xlx_ethlite *s = opaque;
76     uint32_t r = 0;
77
78     addr >>= 2;
79
80     switch (addr)
81     {
82         case R_TX_GIE0:
83         case R_TX_LEN0:
84         case R_TX_LEN1:
85         case R_TX_CTRL1:
86         case R_TX_CTRL0:
87         case R_RX_CTRL1:
88         case R_RX_CTRL0:
89             r = s->regs[addr];
90             D(qemu_log("%s %x=%x\n", __func__, addr * 4, r));
91             break;
92
93         /* Rx packet data is endian fixed at the way into the rx rams. This
94          * speeds things up because the ethlite MAC does not have a len
95          * register. That means the CPU will issue MMIO reads for the entire
96          * 2k rx buffer even for small packets.
97          */
98         default:
99             r = s->regs[addr];
100             break;
101     }
102     return r;
103 }
104
105 static void
106 eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
107 {
108     struct xlx_ethlite *s = opaque;
109     unsigned int base = 0;
110
111     addr >>= 2;
112     switch (addr) 
113     {
114         case R_TX_CTRL0:
115         case R_TX_CTRL1:
116             if (addr == R_TX_CTRL1)
117                 base = 0x800 / 4;
118
119             D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
120             if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
121                 qemu_send_packet(s->vc,
122                                  (void *) &s->regs[base],
123                                  s->regs[base + R_TX_LEN0]);
124                 D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
125                 if (s->regs[base + R_TX_CTRL0] & CTRL_I)
126                     eth_pulse_irq(s);
127             } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
128                 memcpy(&s->macaddr[0], &s->regs[base], 6);
129                 if (s->regs[base + R_TX_CTRL0] & CTRL_I)
130                     eth_pulse_irq(s);
131             }
132
133             /* We are fast and get ready pretty much immediately so
134                we actually never flip the S nor P bits to one.  */
135             s->regs[addr] = value & ~(CTRL_P | CTRL_S);
136             break;
137
138         /* Keep these native.  */
139         case R_TX_LEN0:
140         case R_TX_LEN1:
141         case R_TX_GIE0:
142         case R_RX_CTRL0:
143         case R_RX_CTRL1:
144             D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
145             s->regs[addr] = value;
146             break;
147
148         /* Packet data, make sure it stays BE.  */
149         default:
150             s->regs[addr] = cpu_to_be32(value);
151             break;
152     }
153 }
154
155 static CPUReadMemoryFunc * const eth_read[] = {
156     NULL, NULL, &eth_readl,
157 };
158
159 static CPUWriteMemoryFunc * const eth_write[] = {
160     NULL, NULL, &eth_writel,
161 };
162
163 static int eth_can_rx(VLANClientState *vc)
164 {
165     struct xlx_ethlite *s = vc->opaque;
166     int r;
167     r = !(s->regs[R_RX_CTRL0] & CTRL_S);
168     return r;
169 }
170
171 static ssize_t eth_rx(VLANClientState *vc, const uint8_t *buf, size_t size)
172 {
173     struct xlx_ethlite *s = vc->opaque;
174     unsigned int rxbase = s->rxbuf * (0x800 / 4);
175     int i;
176
177     /* DA filter.  */
178     if (!(buf[0] & 0x80) && memcmp(&s->macaddr[0], buf, 6))
179         return size;
180
181     if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
182         D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
183         return -1;
184     }
185
186     D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase));
187     memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
188
189     /* Bring it into host endianess.  */
190     for (i = 0; i < ((size + 3) / 4); i++) {
191        uint32_t d = s->regs[rxbase + R_RX_BUF0 + i];
192        s->regs[rxbase + R_RX_BUF0 + i] = be32_to_cpu(d);
193     }
194
195     s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
196     if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
197         eth_pulse_irq(s);
198
199     /* If c_rx_pingpong was set flip buffers.  */
200     s->rxbuf ^= s->c_rx_pingpong;
201     return size;
202 }
203
204 static void eth_cleanup(VLANClientState *vc)
205 {
206     struct xlx_ethlite *s = vc->opaque;
207     qemu_free(s);
208 }
209
210 static int xilinx_ethlite_init(SysBusDevice *dev)
211 {
212     struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
213     int regs;
214
215     sysbus_init_irq(dev, &s->irq);
216     s->rxbuf = 0;
217
218     regs = cpu_register_io_memory(eth_read, eth_write, s);
219     sysbus_init_mmio(dev, R_MAX * 4, regs);
220
221     qdev_get_macaddr(&dev->qdev, s->macaddr);
222     s->vc = qdev_get_vlan_client(&dev->qdev,
223                                  eth_can_rx, eth_rx, NULL, eth_cleanup, s);
224     return 0;
225 }
226
227 static SysBusDeviceInfo xilinx_ethlite_info = {
228     .init = xilinx_ethlite_init,
229     .qdev.name  = "xilinx,ethlite",
230     .qdev.size  = sizeof(struct xlx_ethlite),
231     .qdev.props = (Property[]) {
232         DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
233         DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
234         DEFINE_PROP_END_OF_LIST(),
235     }
236 };
237
238 static void xilinx_ethlite_register(void)
239 {
240     sysbus_register_withprop(&xilinx_ethlite_info);
241 }
242
243 device_init(xilinx_ethlite_register)