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