root / hw / lance.c @ 697584ab
History | View | Annotate | Download (14 kB)
1 | 420557e8 | bellard | /*
|
---|---|---|---|
2 | 420557e8 | bellard | * QEMU Lance emulation
|
3 | 420557e8 | bellard | *
|
4 | 66321a11 | bellard | * Copyright (c) 2003-2005 Fabrice Bellard
|
5 | 420557e8 | bellard | *
|
6 | 420557e8 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 420557e8 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 420557e8 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 420557e8 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 420557e8 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 420557e8 | bellard | * furnished to do so, subject to the following conditions:
|
12 | 420557e8 | bellard | *
|
13 | 420557e8 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 420557e8 | bellard | * all copies or substantial portions of the Software.
|
15 | 420557e8 | bellard | *
|
16 | 420557e8 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 420557e8 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 420557e8 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 420557e8 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 420557e8 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 420557e8 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 420557e8 | bellard | * THE SOFTWARE.
|
23 | 420557e8 | bellard | */
|
24 | 420557e8 | bellard | #include "vl.h" |
25 | 420557e8 | bellard | |
26 | 420557e8 | bellard | /* debug LANCE card */
|
27 | 8d5f07fa | bellard | //#define DEBUG_LANCE
|
28 | 420557e8 | bellard | |
29 | 66321a11 | bellard | #ifdef DEBUG_LANCE
|
30 | 66321a11 | bellard | #define DPRINTF(fmt, args...) \
|
31 | 66321a11 | bellard | do { printf("LANCE: " fmt , ##args); } while (0) |
32 | 66321a11 | bellard | #else
|
33 | 66321a11 | bellard | #define DPRINTF(fmt, args...)
|
34 | 66321a11 | bellard | #endif
|
35 | 66321a11 | bellard | |
36 | 420557e8 | bellard | #ifndef LANCE_LOG_TX_BUFFERS
|
37 | 420557e8 | bellard | #define LANCE_LOG_TX_BUFFERS 4 |
38 | 420557e8 | bellard | #define LANCE_LOG_RX_BUFFERS 4 |
39 | 420557e8 | bellard | #endif
|
40 | 420557e8 | bellard | |
41 | 420557e8 | bellard | #define LE_CSR0 0 |
42 | 420557e8 | bellard | #define LE_CSR1 1 |
43 | 420557e8 | bellard | #define LE_CSR2 2 |
44 | 420557e8 | bellard | #define LE_CSR3 3 |
45 | 66321a11 | bellard | #define LE_NREGS (LE_CSR3 + 1) |
46 | 66321a11 | bellard | #define LE_MAXREG LE_CSR3
|
47 | 420557e8 | bellard | |
48 | 420557e8 | bellard | #define LE_RDP 0 |
49 | 420557e8 | bellard | #define LE_RAP 1 |
50 | 420557e8 | bellard | |
51 | 420557e8 | bellard | #define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ |
52 | 420557e8 | bellard | |
53 | 420557e8 | bellard | #define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ |
54 | 420557e8 | bellard | #define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ |
55 | 420557e8 | bellard | #define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ |
56 | 420557e8 | bellard | #define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ |
57 | 420557e8 | bellard | #define LE_C0_MERR 0x0800 /* ME: Memory error */ |
58 | 420557e8 | bellard | #define LE_C0_RINT 0x0400 /* Received interrupt */ |
59 | 420557e8 | bellard | #define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ |
60 | 420557e8 | bellard | #define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ |
61 | 420557e8 | bellard | #define LE_C0_INTR 0x0080 /* Interrupt or error */ |
62 | 420557e8 | bellard | #define LE_C0_INEA 0x0040 /* Interrupt enable */ |
63 | 420557e8 | bellard | #define LE_C0_RXON 0x0020 /* Receiver on */ |
64 | 420557e8 | bellard | #define LE_C0_TXON 0x0010 /* Transmitter on */ |
65 | 420557e8 | bellard | #define LE_C0_TDMD 0x0008 /* Transmitter demand */ |
66 | 420557e8 | bellard | #define LE_C0_STOP 0x0004 /* Stop the card */ |
67 | 420557e8 | bellard | #define LE_C0_STRT 0x0002 /* Start the card */ |
68 | 420557e8 | bellard | #define LE_C0_INIT 0x0001 /* Init the card */ |
69 | 420557e8 | bellard | |
70 | 420557e8 | bellard | #define LE_C3_BSWP 0x4 /* SWAP */ |
71 | 420557e8 | bellard | #define LE_C3_ACON 0x2 /* ALE Control */ |
72 | 420557e8 | bellard | #define LE_C3_BCON 0x1 /* Byte control */ |
73 | 420557e8 | bellard | |
74 | 420557e8 | bellard | /* Receive message descriptor 1 */
|
75 | 420557e8 | bellard | #define LE_R1_OWN 0x80 /* Who owns the entry */ |
76 | 420557e8 | bellard | #define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ |
77 | 420557e8 | bellard | #define LE_R1_FRA 0x20 /* FRA: Frame error */ |
78 | 420557e8 | bellard | #define LE_R1_OFL 0x10 /* OFL: Frame overflow */ |
79 | 420557e8 | bellard | #define LE_R1_CRC 0x08 /* CRC error */ |
80 | 420557e8 | bellard | #define LE_R1_BUF 0x04 /* BUF: Buffer error */ |
81 | 420557e8 | bellard | #define LE_R1_SOP 0x02 /* Start of packet */ |
82 | 420557e8 | bellard | #define LE_R1_EOP 0x01 /* End of packet */ |
83 | 420557e8 | bellard | #define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ |
84 | 420557e8 | bellard | |
85 | 420557e8 | bellard | #define LE_T1_OWN 0x80 /* Lance owns the packet */ |
86 | 420557e8 | bellard | #define LE_T1_ERR 0x40 /* Error summary */ |
87 | 420557e8 | bellard | #define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ |
88 | 420557e8 | bellard | #define LE_T1_EONE 0x08 /* Error: one retry needed */ |
89 | 420557e8 | bellard | #define LE_T1_EDEF 0x04 /* Error: deferred */ |
90 | 420557e8 | bellard | #define LE_T1_SOP 0x02 /* Start of packet */ |
91 | 420557e8 | bellard | #define LE_T1_EOP 0x01 /* End of packet */ |
92 | 420557e8 | bellard | #define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ |
93 | 420557e8 | bellard | |
94 | 420557e8 | bellard | #define LE_T3_BUF 0x8000 /* Buffer error */ |
95 | 420557e8 | bellard | #define LE_T3_UFL 0x4000 /* Error underflow */ |
96 | 420557e8 | bellard | #define LE_T3_LCOL 0x1000 /* Error late collision */ |
97 | 420557e8 | bellard | #define LE_T3_CLOS 0x0800 /* Error carrier loss */ |
98 | 420557e8 | bellard | #define LE_T3_RTY 0x0400 /* Error retry */ |
99 | 420557e8 | bellard | #define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ |
100 | 420557e8 | bellard | |
101 | 420557e8 | bellard | #define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) |
102 | 420557e8 | bellard | #define TX_RING_MOD_MASK (TX_RING_SIZE - 1) |
103 | 420557e8 | bellard | #define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) |
104 | 420557e8 | bellard | |
105 | 420557e8 | bellard | #define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) |
106 | 420557e8 | bellard | #define RX_RING_MOD_MASK (RX_RING_SIZE - 1) |
107 | 420557e8 | bellard | #define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) |
108 | 420557e8 | bellard | |
109 | 420557e8 | bellard | #define PKT_BUF_SZ 1544 |
110 | 420557e8 | bellard | #define RX_BUFF_SIZE PKT_BUF_SZ
|
111 | 420557e8 | bellard | #define TX_BUFF_SIZE PKT_BUF_SZ
|
112 | 420557e8 | bellard | |
113 | 420557e8 | bellard | struct lance_rx_desc {
|
114 | 420557e8 | bellard | unsigned short rmd0; /* low address of packet */ |
115 | 420557e8 | bellard | unsigned char rmd1_bits; /* descriptor bits */ |
116 | 420557e8 | bellard | unsigned char rmd1_hadr; /* high address of packet */ |
117 | 420557e8 | bellard | short length; /* This length is 2s complement (negative)! |
118 | 420557e8 | bellard | * Buffer length
|
119 | 420557e8 | bellard | */
|
120 | 420557e8 | bellard | unsigned short mblength; /* This is the actual number of bytes received */ |
121 | 420557e8 | bellard | }; |
122 | 420557e8 | bellard | |
123 | 420557e8 | bellard | struct lance_tx_desc {
|
124 | 420557e8 | bellard | unsigned short tmd0; /* low address of packet */ |
125 | 420557e8 | bellard | unsigned char tmd1_bits; /* descriptor bits */ |
126 | 420557e8 | bellard | unsigned char tmd1_hadr; /* high address of packet */ |
127 | 420557e8 | bellard | short length; /* Length is 2s complement (negative)! */ |
128 | 420557e8 | bellard | unsigned short misc; |
129 | 420557e8 | bellard | }; |
130 | 420557e8 | bellard | |
131 | 420557e8 | bellard | /* The LANCE initialization block, described in databook. */
|
132 | 420557e8 | bellard | /* On the Sparc, this block should be on a DMA region */
|
133 | 420557e8 | bellard | struct lance_init_block {
|
134 | 420557e8 | bellard | unsigned short mode; /* Pre-set mode (reg. 15) */ |
135 | 420557e8 | bellard | unsigned char phys_addr[6]; /* Physical ethernet address */ |
136 | 420557e8 | bellard | unsigned filter[2]; /* Multicast filter. */ |
137 | 420557e8 | bellard | |
138 | 420557e8 | bellard | /* Receive and transmit ring base, along with extra bits. */
|
139 | 420557e8 | bellard | unsigned short rx_ptr; /* receive descriptor addr */ |
140 | 420557e8 | bellard | unsigned short rx_len; /* receive len and high addr */ |
141 | 420557e8 | bellard | unsigned short tx_ptr; /* transmit descriptor addr */ |
142 | 420557e8 | bellard | unsigned short tx_len; /* transmit len and high addr */ |
143 | 420557e8 | bellard | |
144 | 420557e8 | bellard | /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
|
145 | 420557e8 | bellard | struct lance_rx_desc brx_ring[RX_RING_SIZE];
|
146 | 420557e8 | bellard | struct lance_tx_desc btx_ring[TX_RING_SIZE];
|
147 | 420557e8 | bellard | |
148 | 420557e8 | bellard | char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
|
149 | 420557e8 | bellard | char pad[2]; /* align rx_buf for copy_and_sum(). */ |
150 | 420557e8 | bellard | char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
|
151 | 420557e8 | bellard | }; |
152 | 420557e8 | bellard | |
153 | 420557e8 | bellard | #define LEDMA_REGS 4 |
154 | e80cfcfc | bellard | #define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) |
155 | 420557e8 | bellard | |
156 | 420557e8 | bellard | typedef struct LANCEState { |
157 | 420557e8 | bellard | NetDriverState *nd; |
158 | 420557e8 | bellard | uint32_t leptr; |
159 | 420557e8 | bellard | uint16_t addr; |
160 | 66321a11 | bellard | uint16_t regs[LE_NREGS]; |
161 | 420557e8 | bellard | uint8_t phys[6]; /* mac address */ |
162 | 420557e8 | bellard | int irq;
|
163 | e80cfcfc | bellard | unsigned int rxptr, txptr; |
164 | e80cfcfc | bellard | uint32_t ledmaregs[LEDMA_REGS]; |
165 | 420557e8 | bellard | } LANCEState; |
166 | 420557e8 | bellard | |
167 | 420557e8 | bellard | static void lance_send(void *opaque); |
168 | 420557e8 | bellard | |
169 | e80cfcfc | bellard | static void lance_reset(void *opaque) |
170 | 420557e8 | bellard | { |
171 | e80cfcfc | bellard | LANCEState *s = opaque; |
172 | 420557e8 | bellard | memcpy(s->phys, s->nd->macaddr, 6);
|
173 | e80cfcfc | bellard | s->rxptr = 0;
|
174 | e80cfcfc | bellard | s->txptr = 0;
|
175 | 66321a11 | bellard | memset(s->regs, 0, LE_NREGS * 2); |
176 | 420557e8 | bellard | s->regs[LE_CSR0] = LE_C0_STOP; |
177 | e80cfcfc | bellard | memset(s->ledmaregs, 0, LEDMA_REGS * 4); |
178 | 420557e8 | bellard | } |
179 | 420557e8 | bellard | |
180 | 420557e8 | bellard | static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) |
181 | 420557e8 | bellard | { |
182 | 420557e8 | bellard | LANCEState *s = opaque; |
183 | 420557e8 | bellard | uint32_t saddr; |
184 | 420557e8 | bellard | |
185 | e80cfcfc | bellard | saddr = addr & LE_MAXREG; |
186 | 420557e8 | bellard | switch (saddr >> 1) { |
187 | 420557e8 | bellard | case LE_RDP:
|
188 | 66321a11 | bellard | DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
|
189 | 420557e8 | bellard | return s->regs[s->addr];
|
190 | 420557e8 | bellard | case LE_RAP:
|
191 | 66321a11 | bellard | DPRINTF("read areg = %4.4x\n", s->addr);
|
192 | 420557e8 | bellard | return s->addr;
|
193 | 420557e8 | bellard | default:
|
194 | 66321a11 | bellard | DPRINTF("read unknown(%d)\n", saddr>>1); |
195 | 420557e8 | bellard | break;
|
196 | 420557e8 | bellard | } |
197 | 420557e8 | bellard | return 0; |
198 | 420557e8 | bellard | } |
199 | 420557e8 | bellard | |
200 | 420557e8 | bellard | static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
201 | 420557e8 | bellard | { |
202 | 420557e8 | bellard | LANCEState *s = opaque; |
203 | 420557e8 | bellard | uint32_t saddr; |
204 | 8d5f07fa | bellard | uint16_t reg; |
205 | 420557e8 | bellard | |
206 | e80cfcfc | bellard | saddr = addr & LE_MAXREG; |
207 | 420557e8 | bellard | switch (saddr >> 1) { |
208 | 420557e8 | bellard | case LE_RDP:
|
209 | 66321a11 | bellard | DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
|
210 | 420557e8 | bellard | switch(s->addr) {
|
211 | 420557e8 | bellard | case LE_CSR0:
|
212 | 420557e8 | bellard | if (val & LE_C0_STOP) {
|
213 | 420557e8 | bellard | s->regs[LE_CSR0] = LE_C0_STOP; |
214 | 420557e8 | bellard | break;
|
215 | 420557e8 | bellard | } |
216 | 420557e8 | bellard | |
217 | 420557e8 | bellard | reg = s->regs[LE_CSR0]; |
218 | 420557e8 | bellard | |
219 | 420557e8 | bellard | // 1 = clear for some bits
|
220 | 420557e8 | bellard | reg &= ~(val & 0x7f00);
|
221 | 420557e8 | bellard | |
222 | 420557e8 | bellard | // generated bits
|
223 | 420557e8 | bellard | reg &= ~(LE_C0_ERR | LE_C0_INTR); |
224 | 420557e8 | bellard | if (reg & 0x7100) |
225 | 420557e8 | bellard | reg |= LE_C0_ERR; |
226 | 420557e8 | bellard | if (reg & 0x7f00) |
227 | 420557e8 | bellard | reg |= LE_C0_INTR; |
228 | 420557e8 | bellard | |
229 | 420557e8 | bellard | // direct bit
|
230 | 420557e8 | bellard | reg &= ~LE_C0_INEA; |
231 | 420557e8 | bellard | reg |= val & LE_C0_INEA; |
232 | 420557e8 | bellard | |
233 | 420557e8 | bellard | // exclusive bits
|
234 | 420557e8 | bellard | if (val & LE_C0_INIT) {
|
235 | 420557e8 | bellard | reg |= LE_C0_IDON | LE_C0_INIT; |
236 | 420557e8 | bellard | reg &= ~LE_C0_STOP; |
237 | 420557e8 | bellard | } |
238 | 420557e8 | bellard | else if (val & LE_C0_STRT) { |
239 | 420557e8 | bellard | reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; |
240 | 420557e8 | bellard | reg &= ~LE_C0_STOP; |
241 | 420557e8 | bellard | } |
242 | 420557e8 | bellard | |
243 | 420557e8 | bellard | s->regs[LE_CSR0] = reg; |
244 | 420557e8 | bellard | break;
|
245 | 420557e8 | bellard | case LE_CSR1:
|
246 | 420557e8 | bellard | s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); |
247 | 420557e8 | bellard | s->regs[s->addr] = val; |
248 | 420557e8 | bellard | break;
|
249 | 420557e8 | bellard | case LE_CSR2:
|
250 | 420557e8 | bellard | s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); |
251 | 420557e8 | bellard | s->regs[s->addr] = val; |
252 | 420557e8 | bellard | break;
|
253 | 420557e8 | bellard | case LE_CSR3:
|
254 | 420557e8 | bellard | s->regs[s->addr] = val; |
255 | 420557e8 | bellard | break;
|
256 | 420557e8 | bellard | } |
257 | 420557e8 | bellard | break;
|
258 | 420557e8 | bellard | case LE_RAP:
|
259 | 66321a11 | bellard | DPRINTF("write areg = %4.4x\n", val);
|
260 | 66321a11 | bellard | if (val < LE_NREGS)
|
261 | 420557e8 | bellard | s->addr = val; |
262 | 420557e8 | bellard | break;
|
263 | 420557e8 | bellard | default:
|
264 | 66321a11 | bellard | DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val); |
265 | 420557e8 | bellard | break;
|
266 | 420557e8 | bellard | } |
267 | 420557e8 | bellard | lance_send(s); |
268 | 420557e8 | bellard | } |
269 | 420557e8 | bellard | |
270 | 420557e8 | bellard | static CPUReadMemoryFunc *lance_mem_read[3] = { |
271 | 420557e8 | bellard | lance_mem_readw, |
272 | 420557e8 | bellard | lance_mem_readw, |
273 | 420557e8 | bellard | lance_mem_readw, |
274 | 420557e8 | bellard | }; |
275 | 420557e8 | bellard | |
276 | 420557e8 | bellard | static CPUWriteMemoryFunc *lance_mem_write[3] = { |
277 | 420557e8 | bellard | lance_mem_writew, |
278 | 420557e8 | bellard | lance_mem_writew, |
279 | 420557e8 | bellard | lance_mem_writew, |
280 | 420557e8 | bellard | }; |
281 | 420557e8 | bellard | |
282 | 420557e8 | bellard | |
283 | 420557e8 | bellard | /* return the max buffer size if the LANCE can receive more data */
|
284 | 420557e8 | bellard | static int lance_can_receive(void *opaque) |
285 | 420557e8 | bellard | { |
286 | 420557e8 | bellard | LANCEState *s = opaque; |
287 | e80cfcfc | bellard | uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
288 | 420557e8 | bellard | struct lance_init_block *ib;
|
289 | 420557e8 | bellard | int i;
|
290 | 66321a11 | bellard | uint8_t temp8; |
291 | 420557e8 | bellard | |
292 | 420557e8 | bellard | if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
293 | 420557e8 | bellard | return 0; |
294 | 420557e8 | bellard | |
295 | 420557e8 | bellard | ib = (void *) iommu_translate(dmaptr);
|
296 | 420557e8 | bellard | |
297 | 420557e8 | bellard | for (i = 0; i < RX_RING_SIZE; i++) { |
298 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); |
299 | 66321a11 | bellard | if (temp8 == (LE_R1_OWN)) {
|
300 | 66321a11 | bellard | DPRINTF("can receive %d\n", RX_BUFF_SIZE);
|
301 | 420557e8 | bellard | return RX_BUFF_SIZE;
|
302 | 420557e8 | bellard | } |
303 | 420557e8 | bellard | } |
304 | 66321a11 | bellard | DPRINTF("cannot receive\n");
|
305 | 420557e8 | bellard | return 0; |
306 | 420557e8 | bellard | } |
307 | 420557e8 | bellard | |
308 | 420557e8 | bellard | #define MIN_BUF_SIZE 60 |
309 | 420557e8 | bellard | |
310 | 420557e8 | bellard | static void lance_receive(void *opaque, const uint8_t *buf, int size) |
311 | 420557e8 | bellard | { |
312 | 420557e8 | bellard | LANCEState *s = opaque; |
313 | e80cfcfc | bellard | uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
314 | 420557e8 | bellard | struct lance_init_block *ib;
|
315 | 66321a11 | bellard | unsigned int i, old_rxptr; |
316 | 66321a11 | bellard | uint16_t temp16; |
317 | 66321a11 | bellard | uint8_t temp8; |
318 | 420557e8 | bellard | |
319 | 66321a11 | bellard | DPRINTF("receive size %d\n", size);
|
320 | 420557e8 | bellard | if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
321 | 420557e8 | bellard | return;
|
322 | 420557e8 | bellard | |
323 | 420557e8 | bellard | ib = (void *) iommu_translate(dmaptr);
|
324 | 420557e8 | bellard | |
325 | e80cfcfc | bellard | old_rxptr = s->rxptr; |
326 | e80cfcfc | bellard | for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { |
327 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); |
328 | 66321a11 | bellard | if (temp8 == (LE_R1_OWN)) {
|
329 | e80cfcfc | bellard | s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
|
330 | 66321a11 | bellard | temp16 = size + 4;
|
331 | 66321a11 | bellard | bswap16s(&temp16); |
332 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2); |
333 | e80cfcfc | bellard | cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); |
334 | 66321a11 | bellard | temp8 = LE_R1_POK; |
335 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); |
336 | 420557e8 | bellard | s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; |
337 | 66321a11 | bellard | if (s->regs[LE_CSR0] & LE_C0_INEA)
|
338 | 420557e8 | bellard | pic_set_irq(s->irq, 1);
|
339 | 66321a11 | bellard | DPRINTF("got packet, len %d\n", size);
|
340 | 420557e8 | bellard | return;
|
341 | 420557e8 | bellard | } |
342 | 420557e8 | bellard | } |
343 | 420557e8 | bellard | } |
344 | 420557e8 | bellard | |
345 | 420557e8 | bellard | static void lance_send(void *opaque) |
346 | 420557e8 | bellard | { |
347 | 420557e8 | bellard | LANCEState *s = opaque; |
348 | e80cfcfc | bellard | uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
349 | 420557e8 | bellard | struct lance_init_block *ib;
|
350 | 66321a11 | bellard | unsigned int i, old_txptr; |
351 | 66321a11 | bellard | uint16_t temp16; |
352 | 66321a11 | bellard | uint8_t temp8; |
353 | 420557e8 | bellard | char pkt_buf[PKT_BUF_SZ];
|
354 | 420557e8 | bellard | |
355 | 66321a11 | bellard | DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
|
356 | 420557e8 | bellard | if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
357 | 420557e8 | bellard | return;
|
358 | 420557e8 | bellard | |
359 | 420557e8 | bellard | ib = (void *) iommu_translate(dmaptr);
|
360 | 420557e8 | bellard | |
361 | 66321a11 | bellard | DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
|
362 | e80cfcfc | bellard | old_txptr = s->txptr; |
363 | e80cfcfc | bellard | for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { |
364 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); |
365 | 66321a11 | bellard | if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
|
366 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2); |
367 | 66321a11 | bellard | bswap16s(&temp16); |
368 | 66321a11 | bellard | temp16 = (~temp16) + 1;
|
369 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); |
370 | 66321a11 | bellard | DPRINTF("sending packet, len %d\n", temp16);
|
371 | 66321a11 | bellard | qemu_send_packet(s->nd, pkt_buf, temp16); |
372 | 66321a11 | bellard | temp8 = LE_T1_POK; |
373 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); |
374 | e80cfcfc | bellard | s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
|
375 | 420557e8 | bellard | s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; |
376 | 420557e8 | bellard | } |
377 | 420557e8 | bellard | } |
378 | 66321a11 | bellard | if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
|
379 | 66321a11 | bellard | pic_set_irq(s->irq, 1);
|
380 | 420557e8 | bellard | } |
381 | 420557e8 | bellard | |
382 | 420557e8 | bellard | static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) |
383 | 420557e8 | bellard | { |
384 | e80cfcfc | bellard | LANCEState *s = opaque; |
385 | 420557e8 | bellard | uint32_t saddr; |
386 | 420557e8 | bellard | |
387 | e80cfcfc | bellard | saddr = (addr & LEDMA_MAXADDR) >> 2;
|
388 | e80cfcfc | bellard | return s->ledmaregs[saddr];
|
389 | 420557e8 | bellard | } |
390 | 420557e8 | bellard | |
391 | 420557e8 | bellard | static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
392 | 420557e8 | bellard | { |
393 | e80cfcfc | bellard | LANCEState *s = opaque; |
394 | 420557e8 | bellard | uint32_t saddr; |
395 | 420557e8 | bellard | |
396 | e80cfcfc | bellard | saddr = (addr & LEDMA_MAXADDR) >> 2;
|
397 | e80cfcfc | bellard | s->ledmaregs[saddr] = val; |
398 | 420557e8 | bellard | } |
399 | 420557e8 | bellard | |
400 | 420557e8 | bellard | static CPUReadMemoryFunc *ledma_mem_read[3] = { |
401 | 420557e8 | bellard | ledma_mem_readl, |
402 | 420557e8 | bellard | ledma_mem_readl, |
403 | 420557e8 | bellard | ledma_mem_readl, |
404 | 420557e8 | bellard | }; |
405 | 420557e8 | bellard | |
406 | 420557e8 | bellard | static CPUWriteMemoryFunc *ledma_mem_write[3] = { |
407 | 420557e8 | bellard | ledma_mem_writel, |
408 | 420557e8 | bellard | ledma_mem_writel, |
409 | 420557e8 | bellard | ledma_mem_writel, |
410 | 420557e8 | bellard | }; |
411 | 420557e8 | bellard | |
412 | e80cfcfc | bellard | static void lance_save(QEMUFile *f, void *opaque) |
413 | e80cfcfc | bellard | { |
414 | e80cfcfc | bellard | LANCEState *s = opaque; |
415 | e80cfcfc | bellard | int i;
|
416 | e80cfcfc | bellard | |
417 | e80cfcfc | bellard | qemu_put_be32s(f, &s->leptr); |
418 | e80cfcfc | bellard | qemu_put_be16s(f, &s->addr); |
419 | 66321a11 | bellard | for (i = 0; i < LE_NREGS; i ++) |
420 | e80cfcfc | bellard | qemu_put_be16s(f, &s->regs[i]); |
421 | e80cfcfc | bellard | qemu_put_buffer(f, s->phys, 6);
|
422 | e80cfcfc | bellard | qemu_put_be32s(f, &s->irq); |
423 | e80cfcfc | bellard | for (i = 0; i < LEDMA_REGS; i ++) |
424 | e80cfcfc | bellard | qemu_put_be32s(f, &s->ledmaregs[i]); |
425 | e80cfcfc | bellard | } |
426 | e80cfcfc | bellard | |
427 | e80cfcfc | bellard | static int lance_load(QEMUFile *f, void *opaque, int version_id) |
428 | e80cfcfc | bellard | { |
429 | e80cfcfc | bellard | LANCEState *s = opaque; |
430 | e80cfcfc | bellard | int i;
|
431 | e80cfcfc | bellard | |
432 | e80cfcfc | bellard | if (version_id != 1) |
433 | e80cfcfc | bellard | return -EINVAL;
|
434 | e80cfcfc | bellard | |
435 | e80cfcfc | bellard | qemu_get_be32s(f, &s->leptr); |
436 | e80cfcfc | bellard | qemu_get_be16s(f, &s->addr); |
437 | 66321a11 | bellard | for (i = 0; i < LE_NREGS; i ++) |
438 | e80cfcfc | bellard | qemu_get_be16s(f, &s->regs[i]); |
439 | e80cfcfc | bellard | qemu_get_buffer(f, s->phys, 6);
|
440 | e80cfcfc | bellard | qemu_get_be32s(f, &s->irq); |
441 | e80cfcfc | bellard | for (i = 0; i < LEDMA_REGS; i ++) |
442 | e80cfcfc | bellard | qemu_get_be32s(f, &s->ledmaregs[i]); |
443 | e80cfcfc | bellard | return 0; |
444 | e80cfcfc | bellard | } |
445 | e80cfcfc | bellard | |
446 | 8d5f07fa | bellard | void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) |
447 | 420557e8 | bellard | { |
448 | 420557e8 | bellard | LANCEState *s; |
449 | 8d5f07fa | bellard | int lance_io_memory, ledma_io_memory;
|
450 | 420557e8 | bellard | |
451 | 420557e8 | bellard | s = qemu_mallocz(sizeof(LANCEState));
|
452 | 420557e8 | bellard | if (!s)
|
453 | 420557e8 | bellard | return;
|
454 | 420557e8 | bellard | |
455 | 8d5f07fa | bellard | s->nd = nd; |
456 | 8d5f07fa | bellard | s->irq = irq; |
457 | 8d5f07fa | bellard | |
458 | 420557e8 | bellard | lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
|
459 | 66321a11 | bellard | cpu_register_physical_memory(leaddr, 4, lance_io_memory);
|
460 | 8d5f07fa | bellard | |
461 | e80cfcfc | bellard | ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
|
462 | 8d5f07fa | bellard | cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
|
463 | 420557e8 | bellard | |
464 | 420557e8 | bellard | lance_reset(s); |
465 | 420557e8 | bellard | qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); |
466 | e80cfcfc | bellard | register_savevm("lance", leaddr, 1, lance_save, lance_load, s); |
467 | e80cfcfc | bellard | qemu_register_reset(lance_reset, s); |
468 | 420557e8 | bellard | } |