root / hw / lance.c @ ee6c0b51
History | View | Annotate | Download (13.8 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 | 7c9d8e07 | bellard | VLANClientState *vc; |
158 | 7c9d8e07 | bellard | uint8_t macaddr[6]; /* init mac address */ |
159 | 420557e8 | bellard | uint32_t leptr; |
160 | 420557e8 | bellard | uint16_t addr; |
161 | 66321a11 | bellard | uint16_t regs[LE_NREGS]; |
162 | 420557e8 | bellard | uint8_t phys[6]; /* mac address */ |
163 | 420557e8 | bellard | int irq;
|
164 | e80cfcfc | bellard | unsigned int rxptr, txptr; |
165 | e80cfcfc | bellard | uint32_t ledmaregs[LEDMA_REGS]; |
166 | 420557e8 | bellard | } LANCEState; |
167 | 420557e8 | bellard | |
168 | 420557e8 | bellard | static void lance_send(void *opaque); |
169 | 420557e8 | bellard | |
170 | e80cfcfc | bellard | static void lance_reset(void *opaque) |
171 | 420557e8 | bellard | { |
172 | e80cfcfc | bellard | LANCEState *s = opaque; |
173 | 7c9d8e07 | bellard | memcpy(s->phys, s->macaddr, 6);
|
174 | e80cfcfc | bellard | s->rxptr = 0;
|
175 | e80cfcfc | bellard | s->txptr = 0;
|
176 | 66321a11 | bellard | memset(s->regs, 0, LE_NREGS * 2); |
177 | 420557e8 | bellard | s->regs[LE_CSR0] = LE_C0_STOP; |
178 | e80cfcfc | bellard | memset(s->ledmaregs, 0, LEDMA_REGS * 4); |
179 | 420557e8 | bellard | } |
180 | 420557e8 | bellard | |
181 | 420557e8 | bellard | static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) |
182 | 420557e8 | bellard | { |
183 | 420557e8 | bellard | LANCEState *s = opaque; |
184 | 420557e8 | bellard | uint32_t saddr; |
185 | 420557e8 | bellard | |
186 | e80cfcfc | bellard | saddr = addr & LE_MAXREG; |
187 | 420557e8 | bellard | switch (saddr >> 1) { |
188 | 420557e8 | bellard | case LE_RDP:
|
189 | 66321a11 | bellard | DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
|
190 | 420557e8 | bellard | return s->regs[s->addr];
|
191 | 420557e8 | bellard | case LE_RAP:
|
192 | 66321a11 | bellard | DPRINTF("read areg = %4.4x\n", s->addr);
|
193 | 420557e8 | bellard | return s->addr;
|
194 | 420557e8 | bellard | default:
|
195 | 66321a11 | bellard | DPRINTF("read unknown(%d)\n", saddr>>1); |
196 | 420557e8 | bellard | break;
|
197 | 420557e8 | bellard | } |
198 | 420557e8 | bellard | return 0; |
199 | 420557e8 | bellard | } |
200 | 420557e8 | bellard | |
201 | 420557e8 | bellard | static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
202 | 420557e8 | bellard | { |
203 | 420557e8 | bellard | LANCEState *s = opaque; |
204 | 420557e8 | bellard | uint32_t saddr; |
205 | 8d5f07fa | bellard | uint16_t reg; |
206 | 420557e8 | bellard | |
207 | e80cfcfc | bellard | saddr = addr & LE_MAXREG; |
208 | 420557e8 | bellard | switch (saddr >> 1) { |
209 | 420557e8 | bellard | case LE_RDP:
|
210 | 66321a11 | bellard | DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
|
211 | 420557e8 | bellard | switch(s->addr) {
|
212 | 420557e8 | bellard | case LE_CSR0:
|
213 | 420557e8 | bellard | if (val & LE_C0_STOP) {
|
214 | 420557e8 | bellard | s->regs[LE_CSR0] = LE_C0_STOP; |
215 | 420557e8 | bellard | break;
|
216 | 420557e8 | bellard | } |
217 | 420557e8 | bellard | |
218 | 420557e8 | bellard | reg = s->regs[LE_CSR0]; |
219 | 420557e8 | bellard | |
220 | 420557e8 | bellard | // 1 = clear for some bits
|
221 | 420557e8 | bellard | reg &= ~(val & 0x7f00);
|
222 | 420557e8 | bellard | |
223 | 420557e8 | bellard | // generated bits
|
224 | 420557e8 | bellard | reg &= ~(LE_C0_ERR | LE_C0_INTR); |
225 | 420557e8 | bellard | if (reg & 0x7100) |
226 | 420557e8 | bellard | reg |= LE_C0_ERR; |
227 | 420557e8 | bellard | if (reg & 0x7f00) |
228 | 420557e8 | bellard | reg |= LE_C0_INTR; |
229 | 420557e8 | bellard | |
230 | 420557e8 | bellard | // direct bit
|
231 | 420557e8 | bellard | reg &= ~LE_C0_INEA; |
232 | 420557e8 | bellard | reg |= val & LE_C0_INEA; |
233 | 420557e8 | bellard | |
234 | 420557e8 | bellard | // exclusive bits
|
235 | 420557e8 | bellard | if (val & LE_C0_INIT) {
|
236 | 420557e8 | bellard | reg |= LE_C0_IDON | LE_C0_INIT; |
237 | 420557e8 | bellard | reg &= ~LE_C0_STOP; |
238 | 420557e8 | bellard | } |
239 | 420557e8 | bellard | else if (val & LE_C0_STRT) { |
240 | 420557e8 | bellard | reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; |
241 | 420557e8 | bellard | reg &= ~LE_C0_STOP; |
242 | 420557e8 | bellard | } |
243 | 420557e8 | bellard | |
244 | 420557e8 | bellard | s->regs[LE_CSR0] = reg; |
245 | 420557e8 | bellard | break;
|
246 | 420557e8 | bellard | case LE_CSR1:
|
247 | 420557e8 | bellard | s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); |
248 | 420557e8 | bellard | s->regs[s->addr] = val; |
249 | 420557e8 | bellard | break;
|
250 | 420557e8 | bellard | case LE_CSR2:
|
251 | 420557e8 | bellard | s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); |
252 | 420557e8 | bellard | s->regs[s->addr] = val; |
253 | 420557e8 | bellard | break;
|
254 | 420557e8 | bellard | case LE_CSR3:
|
255 | 420557e8 | bellard | s->regs[s->addr] = val; |
256 | 420557e8 | bellard | break;
|
257 | 420557e8 | bellard | } |
258 | 420557e8 | bellard | break;
|
259 | 420557e8 | bellard | case LE_RAP:
|
260 | 66321a11 | bellard | DPRINTF("write areg = %4.4x\n", val);
|
261 | 66321a11 | bellard | if (val < LE_NREGS)
|
262 | 420557e8 | bellard | s->addr = val; |
263 | 420557e8 | bellard | break;
|
264 | 420557e8 | bellard | default:
|
265 | 66321a11 | bellard | DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val); |
266 | 420557e8 | bellard | break;
|
267 | 420557e8 | bellard | } |
268 | 420557e8 | bellard | lance_send(s); |
269 | 420557e8 | bellard | } |
270 | 420557e8 | bellard | |
271 | 420557e8 | bellard | static CPUReadMemoryFunc *lance_mem_read[3] = { |
272 | 420557e8 | bellard | lance_mem_readw, |
273 | 420557e8 | bellard | lance_mem_readw, |
274 | 420557e8 | bellard | lance_mem_readw, |
275 | 420557e8 | bellard | }; |
276 | 420557e8 | bellard | |
277 | 420557e8 | bellard | static CPUWriteMemoryFunc *lance_mem_write[3] = { |
278 | 420557e8 | bellard | lance_mem_writew, |
279 | 420557e8 | bellard | lance_mem_writew, |
280 | 420557e8 | bellard | lance_mem_writew, |
281 | 420557e8 | bellard | }; |
282 | 420557e8 | bellard | |
283 | 420557e8 | bellard | |
284 | 420557e8 | bellard | #define MIN_BUF_SIZE 60 |
285 | 420557e8 | bellard | |
286 | 07435f74 | pbrook | static int lance_can_receive(void *opaque) |
287 | d861b05e | pbrook | { |
288 | d861b05e | pbrook | return 1; |
289 | d861b05e | pbrook | } |
290 | d861b05e | pbrook | |
291 | 420557e8 | bellard | static void lance_receive(void *opaque, const uint8_t *buf, int size) |
292 | 420557e8 | bellard | { |
293 | 420557e8 | bellard | LANCEState *s = opaque; |
294 | e80cfcfc | bellard | uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
295 | 420557e8 | bellard | struct lance_init_block *ib;
|
296 | 66321a11 | bellard | unsigned int i, old_rxptr; |
297 | 66321a11 | bellard | uint16_t temp16; |
298 | 66321a11 | bellard | uint8_t temp8; |
299 | 420557e8 | bellard | |
300 | 66321a11 | bellard | DPRINTF("receive size %d\n", size);
|
301 | 420557e8 | bellard | if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
302 | 420557e8 | bellard | return;
|
303 | 420557e8 | bellard | |
304 | 420557e8 | bellard | ib = (void *) iommu_translate(dmaptr);
|
305 | 420557e8 | bellard | |
306 | e80cfcfc | bellard | old_rxptr = s->rxptr; |
307 | e80cfcfc | bellard | for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { |
308 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); |
309 | 66321a11 | bellard | if (temp8 == (LE_R1_OWN)) {
|
310 | e80cfcfc | bellard | s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
|
311 | 66321a11 | bellard | temp16 = size + 4;
|
312 | 66321a11 | bellard | bswap16s(&temp16); |
313 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2); |
314 | e80cfcfc | bellard | cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); |
315 | 66321a11 | bellard | temp8 = LE_R1_POK; |
316 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); |
317 | 420557e8 | bellard | s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; |
318 | 66321a11 | bellard | if (s->regs[LE_CSR0] & LE_C0_INEA)
|
319 | 420557e8 | bellard | pic_set_irq(s->irq, 1);
|
320 | 66321a11 | bellard | DPRINTF("got packet, len %d\n", size);
|
321 | 420557e8 | bellard | return;
|
322 | 420557e8 | bellard | } |
323 | 420557e8 | bellard | } |
324 | 420557e8 | bellard | } |
325 | 420557e8 | bellard | |
326 | 420557e8 | bellard | static void lance_send(void *opaque) |
327 | 420557e8 | bellard | { |
328 | 420557e8 | bellard | LANCEState *s = opaque; |
329 | e80cfcfc | bellard | uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
330 | 420557e8 | bellard | struct lance_init_block *ib;
|
331 | 66321a11 | bellard | unsigned int i, old_txptr; |
332 | 66321a11 | bellard | uint16_t temp16; |
333 | 66321a11 | bellard | uint8_t temp8; |
334 | 420557e8 | bellard | char pkt_buf[PKT_BUF_SZ];
|
335 | 420557e8 | bellard | |
336 | 66321a11 | bellard | DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
|
337 | 420557e8 | bellard | if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
338 | 420557e8 | bellard | return;
|
339 | 420557e8 | bellard | |
340 | 420557e8 | bellard | ib = (void *) iommu_translate(dmaptr);
|
341 | 420557e8 | bellard | |
342 | 66321a11 | bellard | DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
|
343 | e80cfcfc | bellard | old_txptr = s->txptr; |
344 | e80cfcfc | bellard | for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { |
345 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); |
346 | 66321a11 | bellard | if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
|
347 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2); |
348 | 66321a11 | bellard | bswap16s(&temp16); |
349 | 66321a11 | bellard | temp16 = (~temp16) + 1;
|
350 | 66321a11 | bellard | cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); |
351 | 66321a11 | bellard | DPRINTF("sending packet, len %d\n", temp16);
|
352 | 7c9d8e07 | bellard | qemu_send_packet(s->vc, pkt_buf, temp16); |
353 | 66321a11 | bellard | temp8 = LE_T1_POK; |
354 | 66321a11 | bellard | cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); |
355 | e80cfcfc | bellard | s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
|
356 | 420557e8 | bellard | s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; |
357 | 420557e8 | bellard | } |
358 | 420557e8 | bellard | } |
359 | 66321a11 | bellard | if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
|
360 | 66321a11 | bellard | pic_set_irq(s->irq, 1);
|
361 | 420557e8 | bellard | } |
362 | 420557e8 | bellard | |
363 | 420557e8 | bellard | static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) |
364 | 420557e8 | bellard | { |
365 | e80cfcfc | bellard | LANCEState *s = opaque; |
366 | 420557e8 | bellard | uint32_t saddr; |
367 | 420557e8 | bellard | |
368 | e80cfcfc | bellard | saddr = (addr & LEDMA_MAXADDR) >> 2;
|
369 | e80cfcfc | bellard | return s->ledmaregs[saddr];
|
370 | 420557e8 | bellard | } |
371 | 420557e8 | bellard | |
372 | 420557e8 | bellard | static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
373 | 420557e8 | bellard | { |
374 | e80cfcfc | bellard | LANCEState *s = opaque; |
375 | 420557e8 | bellard | uint32_t saddr; |
376 | 420557e8 | bellard | |
377 | e80cfcfc | bellard | saddr = (addr & LEDMA_MAXADDR) >> 2;
|
378 | e80cfcfc | bellard | s->ledmaregs[saddr] = val; |
379 | 420557e8 | bellard | } |
380 | 420557e8 | bellard | |
381 | 420557e8 | bellard | static CPUReadMemoryFunc *ledma_mem_read[3] = { |
382 | 420557e8 | bellard | ledma_mem_readl, |
383 | 420557e8 | bellard | ledma_mem_readl, |
384 | 420557e8 | bellard | ledma_mem_readl, |
385 | 420557e8 | bellard | }; |
386 | 420557e8 | bellard | |
387 | 420557e8 | bellard | static CPUWriteMemoryFunc *ledma_mem_write[3] = { |
388 | 420557e8 | bellard | ledma_mem_writel, |
389 | 420557e8 | bellard | ledma_mem_writel, |
390 | 420557e8 | bellard | ledma_mem_writel, |
391 | 420557e8 | bellard | }; |
392 | 420557e8 | bellard | |
393 | e80cfcfc | bellard | static void lance_save(QEMUFile *f, void *opaque) |
394 | e80cfcfc | bellard | { |
395 | e80cfcfc | bellard | LANCEState *s = opaque; |
396 | e80cfcfc | bellard | int i;
|
397 | e80cfcfc | bellard | |
398 | e80cfcfc | bellard | qemu_put_be32s(f, &s->leptr); |
399 | e80cfcfc | bellard | qemu_put_be16s(f, &s->addr); |
400 | 66321a11 | bellard | for (i = 0; i < LE_NREGS; i ++) |
401 | e80cfcfc | bellard | qemu_put_be16s(f, &s->regs[i]); |
402 | e80cfcfc | bellard | qemu_put_buffer(f, s->phys, 6);
|
403 | e80cfcfc | bellard | qemu_put_be32s(f, &s->irq); |
404 | e80cfcfc | bellard | for (i = 0; i < LEDMA_REGS; i ++) |
405 | e80cfcfc | bellard | qemu_put_be32s(f, &s->ledmaregs[i]); |
406 | e80cfcfc | bellard | } |
407 | e80cfcfc | bellard | |
408 | e80cfcfc | bellard | static int lance_load(QEMUFile *f, void *opaque, int version_id) |
409 | e80cfcfc | bellard | { |
410 | e80cfcfc | bellard | LANCEState *s = opaque; |
411 | e80cfcfc | bellard | int i;
|
412 | e80cfcfc | bellard | |
413 | e80cfcfc | bellard | if (version_id != 1) |
414 | e80cfcfc | bellard | return -EINVAL;
|
415 | e80cfcfc | bellard | |
416 | e80cfcfc | bellard | qemu_get_be32s(f, &s->leptr); |
417 | e80cfcfc | bellard | qemu_get_be16s(f, &s->addr); |
418 | 66321a11 | bellard | for (i = 0; i < LE_NREGS; i ++) |
419 | e80cfcfc | bellard | qemu_get_be16s(f, &s->regs[i]); |
420 | e80cfcfc | bellard | qemu_get_buffer(f, s->phys, 6);
|
421 | e80cfcfc | bellard | qemu_get_be32s(f, &s->irq); |
422 | e80cfcfc | bellard | for (i = 0; i < LEDMA_REGS; i ++) |
423 | e80cfcfc | bellard | qemu_get_be32s(f, &s->ledmaregs[i]); |
424 | e80cfcfc | bellard | return 0; |
425 | e80cfcfc | bellard | } |
426 | e80cfcfc | bellard | |
427 | 7c9d8e07 | bellard | void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) |
428 | 420557e8 | bellard | { |
429 | 420557e8 | bellard | LANCEState *s; |
430 | 8d5f07fa | bellard | int lance_io_memory, ledma_io_memory;
|
431 | 420557e8 | bellard | |
432 | 420557e8 | bellard | s = qemu_mallocz(sizeof(LANCEState));
|
433 | 420557e8 | bellard | if (!s)
|
434 | 420557e8 | bellard | return;
|
435 | 420557e8 | bellard | |
436 | 8d5f07fa | bellard | s->irq = irq; |
437 | 8d5f07fa | bellard | |
438 | 420557e8 | bellard | lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
|
439 | 66321a11 | bellard | cpu_register_physical_memory(leaddr, 4, lance_io_memory);
|
440 | 8d5f07fa | bellard | |
441 | e80cfcfc | bellard | ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
|
442 | 8d5f07fa | bellard | cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
|
443 | 420557e8 | bellard | |
444 | 7c9d8e07 | bellard | memcpy(s->macaddr, nd->macaddr, 6);
|
445 | 7c9d8e07 | bellard | |
446 | 420557e8 | bellard | lance_reset(s); |
447 | 7c9d8e07 | bellard | |
448 | d861b05e | pbrook | s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s); |
449 | 7c9d8e07 | bellard | |
450 | 7c9d8e07 | bellard | snprintf(s->vc->info_str, sizeof(s->vc->info_str),
|
451 | 7c9d8e07 | bellard | "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
|
452 | 7c9d8e07 | bellard | s->macaddr[0],
|
453 | 7c9d8e07 | bellard | s->macaddr[1],
|
454 | 7c9d8e07 | bellard | s->macaddr[2],
|
455 | 7c9d8e07 | bellard | s->macaddr[3],
|
456 | 7c9d8e07 | bellard | s->macaddr[4],
|
457 | 7c9d8e07 | bellard | s->macaddr[5]);
|
458 | 7c9d8e07 | bellard | |
459 | e80cfcfc | bellard | register_savevm("lance", leaddr, 1, lance_save, lance_load, s); |
460 | e80cfcfc | bellard | qemu_register_reset(lance_reset, s); |
461 | 420557e8 | bellard | } |