/[dynamips]/trunk/dev_am79c971.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/dev_am79c971.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 31100 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (C) 2006 Christophe Fillot. All rights reserved.
4 *
5 * AMD Am79c971 FastEthernet chip emulation.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <assert.h>
16
17 #include "utils.h"
18 #include "cpu.h"
19 #include "vm.h"
20 #include "dynamips.h"
21 #include "memory.h"
22 #include "device.h"
23 #include "net.h"
24 #include "net_io.h"
25 #include "ptask.h"
26 #include "dev_am79c971.h"
27
28 /* Debugging flags */
29 #define DEBUG_CSR_REGS 0
30 #define DEBUG_BCR_REGS 0
31 #define DEBUG_PCI_REGS 0
32 #define DEBUG_ACCESS 0
33 #define DEBUG_TRANSMIT 1
34 #define DEBUG_RECEIVE 1
35 #define DEBUG_UNKNOWN 0
36
37 /* AMD Am79c971 PCI vendor/product codes */
38 #define AM79C971_PCI_VENDOR_ID 0x1022
39 #define AM79C971_PCI_PRODUCT_ID 0x2000
40
41 /* Maximum packet size */
42 #define AM79C971_MAX_PKT_SIZE 2048
43
44 /* Send up to 16 packets in a TX ring scan pass */
45 #define AM79C971_TXRING_PASS_COUNT 16
46
47 /* CSR0: Controller Status and Control Register */
48 #define AM79C971_CSR0_ERR 0x00008000 /* Error (BABL,CERR,MISS,MERR) */
49 #define AM79C971_CSR0_BABL 0x00004000 /* Transmitter Timeout Error */
50 #define AM79C971_CSR0_CERR 0x00002000 /* Collision Error */
51 #define AM79C971_CSR0_MISS 0x00001000 /* Missed Frame */
52 #define AM79C971_CSR0_MERR 0x00000800 /* Memory Error */
53 #define AM79C971_CSR0_RINT 0x00000400 /* Receive Interrupt */
54 #define AM79C971_CSR0_TINT 0x00000200 /* Transmit Interrupt */
55 #define AM79C971_CSR0_IDON 0x00000100 /* Initialization Done */
56 #define AM79C971_CSR0_INTR 0x00000080 /* Interrupt Flag */
57 #define AM79C971_CSR0_IENA 0x00000040 /* Interrupt Enable */
58 #define AM79C971_CSR0_RXON 0x00000020 /* Receive On */
59 #define AM79C971_CSR0_TXON 0x00000010 /* Transmit On */
60 #define AM79C971_CSR0_TDMD 0x00000008 /* Transmit Demand */
61 #define AM79C971_CSR0_STOP 0x00000004 /* Stop */
62 #define AM79C971_CSR0_STRT 0x00000002 /* Start */
63 #define AM79C971_CSR0_INIT 0x00000001 /* Initialization */
64
65 /* CSR3: Interrupt Masks and Deferral Control */
66 #define AM79C971_CSR3_BABLM 0x00004000 /* Transmit. Timeout Int. Mask */
67 #define AM79C971_CSR3_CERRM 0x00002000 /* Collision Error Int. Mask*/
68 #define AM79C971_CSR3_MISSM 0x00001000 /* Missed Frame Interrupt Mask */
69 #define AM79C971_CSR3_MERRM 0x00000800 /* Memory Error Interrupt Mask */
70 #define AM79C971_CSR3_RINTM 0x00000400 /* Receive Interrupt Mask */
71 #define AM79C971_CSR3_TINTM 0x00000200 /* Transmit Interrupt Mask */
72 #define AM79C971_CSR3_IDONM 0x00000100 /* Initialization Done Mask */
73 #define AM79C971_CSR3_BSWP 0x00000004 /* Byte Swap */
74 #define AM79C971_CSR3_IM_MASK 0x00007F00 /* Interrupt Masks for CSR3 */
75
76 /* CSR5: Extended Control and Interrupt 1 */
77 #define AM79C971_CSR5_TOKINTD 0x00008000 /* Receive Interrupt Mask */
78 #define AM79C971_CSR5_SPND 0x00000001 /* Suspend */
79
80 /* CSR15: Mode */
81 #define AM79C971_CSR15_PROM 0x00008000 /* Promiscous Mode */
82 #define AM79C971_CSR15_DRCVBC 0x00004000 /* Disable Receive Broadcast */
83 #define AM79C971_CSR15_DRCVPA 0x00002000 /* Disable Receive PHY address */
84 #define AM79C971_CSR15_DTX 0x00000002 /* Disable Transmit */
85 #define AM79C971_CSR15_DRX 0x00000001 /* Disable Receive */
86
87 /* AMD 79C971 Initialization block length */
88 #define AM79C971_INIT_BLOCK_LEN 0x1c
89
90 /* RX descriptors */
91 #define AM79C971_RMD1_OWN 0x80000000 /* OWN=1: owned by Am79c971 */
92 #define AM79C971_RMD1_ERR 0x40000000 /* Error */
93 #define AM79C971_RMD1_FRAM 0x20000000 /* Framing Error */
94 #define AM79C971_RMD1_OFLO 0x10000000 /* Overflow Error */
95 #define AM79C971_RMD1_CRC 0x08000000 /* Invalid CRC */
96 #define AM79C971_RMD1_BUFF 0x08000000 /* Buffer Error (chaining) */
97 #define AM79C971_RMD1_STP 0x02000000 /* Start of Packet */
98 #define AM79C971_RMD1_ENP 0x01000000 /* End of Packet */
99 #define AM79C971_RMD1_BPE 0x00800000 /* Bus Parity Error */
100 #define AM79C971_RMD1_PAM 0x00400000 /* Physical Address Match */
101 #define AM79C971_RMD1_LAFM 0x00200000 /* Logical Addr. Filter Match */
102 #define AM79C971_RMD1_BAM 0x00100000 /* Broadcast Address Match */
103 #define AM79C971_RMD1_LEN 0x00000FFF /* Buffer Length */
104
105 #define AM79C971_RMD2_LEN 0x00000FFF /* Received byte count */
106
107 /* TX descriptors */
108 #define AM79C971_TMD1_OWN 0x80000000 /* OWN=1: owned by Am79c971 */
109 #define AM79C971_TMD1_ERR 0x40000000 /* Error */
110 #define AM79C971_TMD1_ADD_FCS 0x20000000 /* FCS generation */
111 #define AM79C971_TMD1_STP 0x02000000 /* Start of Packet */
112 #define AM79C971_TMD1_ENP 0x01000000 /* End of Packet */
113 #define AM79C971_TMD1_LEN 0x00000FFF /* Buffer Length */
114
115 /* RX Descriptor */
116 struct rx_desc {
117 m_uint32_t rmd[4];
118 };
119
120 /* TX Descriptor */
121 struct tx_desc {
122 m_uint32_t tmd[4];
123 };
124
125 /* AMD 79C971 Data */
126 struct am79c971_data {
127 char *name;
128
129 /* Lock */
130 pthread_mutex_t lock;
131
132 /* Interface type (10baseT or 100baseTX) */
133 int type;
134
135 /* RX/TX clearing count */
136 int rx_tx_clear_count;
137
138 /* Current RAP (Register Address Pointer) value */
139 m_uint8_t rap;
140
141 /* CSR and BCR registers */
142 m_uint32_t csr[256],bcr[256];
143
144 /* RX/TX rings start addresses */
145 m_uint32_t rx_start,tx_start;
146
147 /* RX/TX number of descriptors (log2) */
148 m_uint32_t rx_l2len,tx_l2len;
149
150 /* RX/TX number of descriptors */
151 m_uint32_t rx_len,tx_len;
152
153 /* RX/TX ring positions */
154 m_uint32_t rx_pos,tx_pos;
155
156 /* MII registers */
157 m_uint16_t mii_regs[32][32];
158
159 /* Physical (MAC) address */
160 n_eth_addr_t mac_addr;
161
162 /* Device information */
163 struct vdevice *dev;
164
165 /* PCI device information */
166 struct pci_device *pci_dev;
167
168 /* Virtual machine */
169 vm_instance_t *vm;
170
171 /* NetIO descriptor */
172 netio_desc_t *nio;
173
174 /* TX ring scanner task id */
175 ptask_id_t tx_tid;
176 };
177
178 /* Log an am79c971 message */
179 #define AM79C971_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
180
181 /* Lock/Unlock primitives */
182 #define AM79C971_LOCK(d) pthread_mutex_lock(&(d)->lock)
183 #define AM79C971_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)
184
185 static m_uint16_t mii_reg_values[32] = {
186 0x1000, 0x782D, 0x0013, 0x78E2, 0x01E1, 0xC9E1, 0x000F, 0x2001,
187 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
188 0x0104, 0x4780, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
189 0x0000, 0x0000, 0x00C8, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000,
190
191 #if 0
192 0x1000, 0x782D, 0x0013, 0x78e2, 0x01E1, 0xC9E1, 0x0000, 0x0000,
193 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
194 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x8060,
195 0x8023, 0x0820, 0x0000, 0x3800, 0xA3B9, 0x0000, 0x0000, 0x0000,
196 #endif
197 };
198
199 /* Read a MII register */
200 static m_uint16_t mii_reg_read(struct am79c971_data *d,u_int phy,u_int reg)
201 {
202 if ((phy >= 32) || (reg >= 32))
203 return(0);
204
205 return(d->mii_regs[phy][reg]);
206 }
207
208 /* Write a MII register */
209 static void mii_reg_write(struct am79c971_data *d,u_int phy,u_int reg,
210 m_uint16_t value)
211 {
212 if ((phy < 32) && (reg < 32))
213 d->mii_regs[phy][reg] = value;
214 }
215
216 /* Check if a packet must be delivered to the emulated chip */
217 static inline int am79c971_handle_mac_addr(struct am79c971_data *d,
218 m_uint8_t *pkt)
219 {
220 n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt;
221
222 /* Accept systematically frames if we are running in promiscuous mode */
223 if (d->csr[15] & AM79C971_CSR15_PROM)
224 return(TRUE);
225
226 /* Accept systematically all multicast frames */
227 if (eth_addr_is_mcast(&hdr->daddr))
228 return(TRUE);
229
230 /* Accept frames directly for us, discard others */
231 if (!memcmp(&d->mac_addr,&hdr->daddr,N_ETH_ALEN))
232 return(TRUE);
233
234 return(FALSE);
235 }
236
237 /* Update the Interrupt Flag bit of csr0 */
238 static void am79c971_update_irq_status(struct am79c971_data *d)
239 {
240 m_uint32_t mask;
241
242 /* Bits set in CR3 disable the specified interrupts */
243 mask = AM79C971_CSR3_IM_MASK & ~(d->csr[3] & AM79C971_CSR3_IM_MASK);
244
245 if (d->csr[0] & mask)
246 d->csr[0] |= AM79C971_CSR0_INTR;
247 else
248 d->csr[0] &= ~AM79C971_CSR0_INTR;
249
250 if ((d->csr[0] & (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) ==
251 (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA))
252 {
253 pci_dev_trigger_irq(d->vm,d->pci_dev);
254 } else {
255 pci_dev_clear_irq(d->vm,d->pci_dev);
256 }
257 }
258
259 /* Update RX/TX ON bits of csr0 */
260 static void am79c971_update_rx_tx_on_bits(struct am79c971_data *d)
261 {
262 /*
263 * Set RX ON if DRX in csr15 is cleared, and set TX on if DTX
264 * in csr15 is cleared. The START bit must be set.
265 */
266 d->csr[0] &= ~(AM79C971_CSR0_RXON|AM79C971_CSR0_TXON);
267
268 if (d->csr[0] & AM79C971_CSR0_STRT) {
269 if (!(d->csr[15] & AM79C971_CSR15_DRX))
270 d->csr[0] |= AM79C971_CSR0_RXON;
271
272 if (!(d->csr[15] & AM79C971_CSR15_DTX))
273 d->csr[0] |= AM79C971_CSR0_TXON;
274 }
275 }
276
277 /* Update RX/TX descriptor lengths */
278 static void am79c971_update_rx_tx_len(struct am79c971_data *d)
279 {
280 d->rx_len = 1 << d->rx_l2len;
281 d->tx_len = 1 << d->tx_l2len;
282
283 /* Normalize ring sizes */
284 if (d->rx_len > 512) d->rx_len = 512;
285 if (d->tx_len > 512) d->tx_len = 512;
286 }
287
288 /* Fetch the initialization block from memory */
289 static int am79c971_fetch_init_block(struct am79c971_data *d)
290 {
291 m_uint32_t ib[AM79C971_INIT_BLOCK_LEN];
292 m_uint32_t ib_addr,ib_tmp;
293
294 /* The init block address is contained in csr1 (low) and csr2 (high) */
295 ib_addr = (d->csr[2] << 16) | d->csr[1];
296
297 if (!ib_addr) {
298 AM79C971_LOG(d,"trying to fetch init block at address 0...\n");
299 return(-1);
300 }
301
302 AM79C971_LOG(d,"fetching init block at address 0x%8.8x\n",ib_addr);
303 physmem_copy_from_vm(d->vm,ib,ib_addr,sizeof(ib));
304
305 /* Extract RX/TX ring addresses */
306 d->rx_start = vmtoh32(ib[5]);
307 d->tx_start = vmtoh32(ib[6]);
308
309 /* Set csr15 from mode field */
310 ib_tmp = vmtoh32(ib[0]);
311 d->csr[15] = ib_tmp & 0xffff;
312
313 /* Extract RX/TX ring sizes */
314 d->rx_l2len = (ib_tmp >> 20) & 0x0F;
315 d->tx_l2len = (ib_tmp >> 28) & 0x0F;
316 am79c971_update_rx_tx_len(d);
317
318 AM79C971_LOG(d,"rx_ring = 0x%8.8x (%u), tx_ring = 0x%8.8x (%u)\n",
319 d->rx_start,d->rx_len,d->tx_start,d->tx_len);
320
321 /* Get the physical MAC address */
322 ib_tmp = vmtoh32(ib[1]);
323 d->csr[12] = ib_tmp & 0xFFFF;
324 d->csr[13] = ib_tmp >> 16;
325
326 d->mac_addr.eth_addr_byte[3] = (ib_tmp >> 24) & 0xFF;
327 d->mac_addr.eth_addr_byte[2] = (ib_tmp >> 16) & 0xFF;
328 d->mac_addr.eth_addr_byte[1] = (ib_tmp >> 8) & 0xFF;
329 d->mac_addr.eth_addr_byte[0] = ib_tmp & 0xFF;
330
331 ib_tmp = vmtoh32(ib[2]);
332 d->csr[14] = ib_tmp & 0xFFFF;
333 d->mac_addr.eth_addr_byte[5] = (ib_tmp >> 8) & 0xFF;
334 d->mac_addr.eth_addr_byte[4] = ib_tmp & 0xFF;
335
336 /*
337 * Mark the initialization as done is csr0.
338 */
339 d->csr[0] |= AM79C971_CSR0_IDON;
340
341 /* Update RX/TX ON bits of csr0 since csr15 has been modified */
342 am79c971_update_rx_tx_on_bits(d);
343 AM79C971_LOG(d,"CSR0 = 0x%4.4x\n",d->csr[0]);
344 return(0);
345 }
346
347 /* RDP (Register Data Port) access */
348 static void am79c971_rdp_access(cpu_gen_t *cpu,struct am79c971_data *d,
349 u_int op_type,m_uint64_t *data)
350 {
351 m_uint32_t mask;
352
353 #if DEBUG_CSR_REGS
354 if (op_type == MTS_READ) {
355 cpu_log(cpu,d->name,"read access to CSR %d\n",d->rap);
356 } else {
357 cpu_log(cpu,d->name,"write access to CSR %d, value=0x%x\n",d->rap,*data);
358 }
359 #endif
360
361 switch(d->rap) {
362 case 0: /* CSR0: Controller Status and Control Register */
363 if (op_type == MTS_READ) {
364 //AM79C971_LOG(d,"reading CSR0 (val=0x%4.4x)\n",d->csr[0]);
365 *data = d->csr[0];
366 } else {
367 /*
368 * The STOP bit clears other bits.
369 * It has precedence over INIT and START bits.
370 */
371 if (*data & AM79C971_CSR0_STOP) {
372 //AM79C971_LOG(d,"stopping interface!\n");
373 d->csr[0] = AM79C971_CSR0_STOP;
374 d->tx_pos = d->rx_pos = 0;
375 am79c971_update_irq_status(d);
376 break;
377 }
378
379 /* These bits are cleared when set to 1 */
380 mask = AM79C971_CSR0_BABL | AM79C971_CSR0_CERR;
381 mask |= AM79C971_CSR0_MISS | AM79C971_CSR0_MERR;
382 mask |= AM79C971_CSR0_IDON;
383
384 if (++d->rx_tx_clear_count == 3) {
385 mask |= AM79C971_CSR0_RINT | AM79C971_CSR0_TINT;
386 d->rx_tx_clear_count = 0;
387 }
388
389 d->csr[0] &= ~(*data & mask);
390
391 /* Save the Interrupt Enable bit */
392 d->csr[0] |= *data & AM79C971_CSR0_IENA;
393
394 /* If INIT bit is set, fetch the initialization block */
395 if (*data & AM79C971_CSR0_INIT) {
396 d->csr[0] |= AM79C971_CSR0_INIT;
397 d->csr[0] &= ~AM79C971_CSR0_STOP;
398 am79c971_fetch_init_block(d);
399 }
400
401 /* If STRT bit is set, clear the stop bit */
402 if (*data & AM79C971_CSR0_STRT) {
403 //AM79C971_LOG(d,"enabling interface!\n");
404 d->csr[0] |= AM79C971_CSR0_STRT;
405 d->csr[0] &= ~AM79C971_CSR0_STOP;
406 am79c971_update_rx_tx_on_bits(d);
407 }
408
409 /* Update IRQ status */
410 am79c971_update_irq_status(d);
411 }
412 break;
413
414 case 6: /* CSR6: RX/TX Descriptor Table Length */
415 if (op_type == MTS_WRITE) {
416 d->rx_l2len = (*data >> 8) & 0x0F;
417 d->tx_l2len = (*data >> 12) & 0x0F;
418 am79c971_update_rx_tx_len(d);
419 } else {
420 *data = (d->tx_l2len << 12) | (d->rx_l2len << 8);
421 }
422 break;
423
424 case 15: /* CSR15: Mode */
425 if (op_type == MTS_WRITE) {
426 d->csr[15] = *data;
427 am79c971_update_rx_tx_on_bits(d);
428 } else {
429 *data = d->csr[15];
430 }
431 break;
432
433 case 88:
434 if (op_type == MTS_READ) {
435 switch(d->type) {
436 case AM79C971_TYPE_100BASE_TX:
437 *data = 0x2623003;
438 break;
439 default:
440 *data = 0;
441 break;
442 }
443 }
444 break;
445
446 default:
447 if (op_type == MTS_READ) {
448 *data = d->csr[d->rap];
449 } else {
450 d->csr[d->rap] = *data;
451 }
452
453 #if DEBUG_UNKNOWN
454 if (op_type == MTS_READ) {
455 cpu_log(cpu,d->name,"read access to unknown CSR %d\n",d->rap);
456 } else {
457 cpu_log(cpu,d->name,"write access to unknown CSR %d, value=0x%x\n",
458 d->rap,*data);
459 }
460 #endif
461 }
462 }
463
464 /* BDP (BCR Data Port) access */
465 static void am79c971_bdp_access(cpu_gen_t *cpu,struct am79c971_data *d,
466 u_int op_type,m_uint64_t *data)
467 {
468 u_int mii_phy,mii_reg;
469
470 #if DEBUG_BCR_REGS
471 if (op_type == MTS_READ) {
472 cpu_log(cpu,d->name,"read access to BCR %d\n",d->rap);
473 } else {
474 cpu_log(cpu,d->name,"write access to BCR %d, value=0x%x\n",d->rap,*data);
475 }
476 #endif
477
478 switch(d->rap) {
479 case 9:
480 if (op_type == MTS_READ)
481 *data = 1;
482 break;
483
484 case 34: /* BCR34: MII Management Data Register */
485 mii_phy = (d->bcr[33] >> 5) & 0x1F;
486 mii_reg = (d->bcr[33] >> 0) & 0x1F;
487
488 if (op_type == MTS_READ)
489 *data = mii_reg_read(d,mii_phy,mii_reg);
490 //else
491 //mii_reg_write(d,mii_phy,mii_reg,*data);
492 break;
493
494 default:
495 if (op_type == MTS_READ) {
496 *data = d->bcr[d->rap];
497 } else {
498 d->bcr[d->rap] = *data;
499 }
500
501 #if DEBUG_UNKNOWN
502 if (op_type == MTS_READ) {
503 cpu_log(cpu,d->name,"read access to unknown BCR %d\n",d->rap);
504 } else {
505 cpu_log(cpu,d->name,
506 "write access to unknown BCR %d, value=0x%x\n",
507 d->rap,*data);
508 }
509 #endif
510 }
511 }
512
513 /*
514 * dev_am79c971_access()
515 */
516 void *dev_am79c971_access(cpu_gen_t *cpu,struct vdevice *dev,
517 m_uint32_t offset,u_int op_size,u_int op_type,
518 m_uint64_t *data)
519 {
520 struct am79c971_data *d = dev->priv_data;
521
522 if (op_type == MTS_READ)
523 *data = 0;
524
525 #if DEBUG_ACCESS
526 if (op_type == MTS_READ) {
527 cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n",
528 offset,cpu_get_pc(cpu),op_size);
529 } else {
530 cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, "
531 "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size);
532 }
533 #endif
534
535 AM79C971_LOCK(d);
536
537 switch(offset) {
538 case 0x14: /* RAP (Register Address Pointer) */
539 if (op_type == MTS_WRITE) {
540 d->rap = *data & 0xFF;
541 } else {
542 *data = d->rap;
543 }
544 break;
545
546 case 0x10: /* RDP (Register Data Port) */
547 am79c971_rdp_access(cpu,d,op_type,data);
548 break;
549
550 case 0x1c: /* BDP (BCR Data Port) */
551 am79c971_bdp_access(cpu,d,op_type,data);
552 break;
553 }
554
555 AM79C971_UNLOCK(d);
556 return NULL;
557 }
558
559 /* Read a RX descriptor */
560 static int rxdesc_read(struct am79c971_data *d,m_uint32_t rxd_addr,
561 struct rx_desc *rxd)
562 {
563 m_uint32_t buf[4];
564 m_uint8_t sw_style;
565
566 /* Get the software style */
567 sw_style = d->bcr[20];
568
569 /* Read the descriptor from VM physical RAM */
570 physmem_copy_from_vm(d->vm,&buf,rxd_addr,sizeof(struct rx_desc));
571
572 switch(sw_style) {
573 case 2:
574 rxd->rmd[0] = vmtoh32(buf[0]); /* rb addr */
575 rxd->rmd[1] = vmtoh32(buf[1]); /* own flag, ... */
576 rxd->rmd[2] = vmtoh32(buf[2]); /* rfrtag, mcnt, ... */
577 rxd->rmd[3] = vmtoh32(buf[3]); /* user */
578 break;
579
580 case 3:
581 rxd->rmd[0] = vmtoh32(buf[2]); /* rb addr */
582 rxd->rmd[1] = vmtoh32(buf[1]); /* own flag, ... */
583 rxd->rmd[2] = vmtoh32(buf[0]); /* rfrtag, mcnt, ... */
584 rxd->rmd[3] = vmtoh32(buf[3]); /* user */
585 break;
586
587 default:
588 AM79C971_LOG(d,"invalid software style %u!\n",sw_style);
589 return(-1);
590 }
591
592 return(0);
593 }
594
595 /* Set the address of the next RX descriptor */
596 static inline void rxdesc_set_next(struct am79c971_data *d)
597 {
598 d->rx_pos++;
599
600 if (d->rx_pos == d->rx_len)
601 d->rx_pos = 0;
602 }
603
604 /* Compute the address of the current RX descriptor */
605 static inline m_uint32_t rxdesc_get_current(struct am79c971_data *d)
606 {
607 return(d->rx_start + (d->rx_pos * sizeof(struct rx_desc)));
608 }
609
610 /* Put a packet in buffer of a descriptor */
611 static void rxdesc_put_pkt(struct am79c971_data *d,struct rx_desc *rxd,
612 u_char **pkt,ssize_t *pkt_len)
613 {
614 ssize_t len,cp_len;
615
616 /* Compute the data length to copy */
617 len = ~((rxd->rmd[1] & AM79C971_RMD1_LEN) - 1);
618 len &= AM79C971_RMD1_LEN;
619 cp_len = m_min(len,*pkt_len);
620
621 /* Copy packet data to the VM physical RAM */
622 #if DEBUG_RECEIVE
623 AM79C971_LOG(d,"am79c971_handle_rxring: storing %u bytes at 0x%8.8x\n",
624 cp_len, rxd->rmd[0]);
625 #endif
626 physmem_copy_to_vm(d->vm,*pkt,rxd->rmd[0],cp_len);
627
628 *pkt += cp_len;
629 *pkt_len -= cp_len;
630 }
631
632 /*
633 * Put a packet in the RX ring.
634 */
635 static int am79c971_receive_pkt(struct am79c971_data *d,
636 u_char *pkt,ssize_t pkt_len)
637 {
638 m_uint32_t rx_start,rx_current,rx_next,rxdn_rmd1;
639 struct rx_desc rxd0,rxdn,*rxdc;
640 ssize_t tot_len = pkt_len;
641 u_char *pkt_ptr = pkt;
642 m_uint8_t sw_style;
643 int i;
644
645 /* Truncate the packet if it is too big */
646 pkt_len = m_min(pkt_len,AM79C971_MAX_PKT_SIZE);
647
648 /* Copy the current rxring descriptor */
649 rx_start = rx_current = rxdesc_get_current(d);
650 rxdesc_read(d,rx_start,&rxd0);
651
652 /* We must have the first descriptor... */
653 if (!(rxd0.rmd[1] & AM79C971_RMD1_OWN))
654 return(FALSE);
655
656 for(i=0,rxdc=&rxd0;;i++)
657 {
658 #if DEBUG_RECEIVE
659 AM79C971_LOG(d,"am79c971_handle_rxring: i=%d, addr=0x%8.8x: "
660 "rmd[0]=0x%x, rmd[1]=0x%x, rmd[2]=0x%x, rmd[3]=0x%x\n",
661 i,rx_current,
662 rxdc->rmd[0],rxdc->rmd[1],rxdc->rmd[2],rxdc->rmd[3]);
663 #endif
664 /* Put data into the descriptor buffer */
665 rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len);
666
667 /* Go to the next descriptor */
668 rxdesc_set_next(d);
669
670 /* If this is not the first descriptor, clear the OWN bit */
671 if (i != 0)
672 rxdc->rmd[1] &= ~AM79C971_RMD1_OWN;
673
674 /* If we have finished, mark the descriptor as end of packet */
675 if (tot_len == 0) {
676 rxdc->rmd[1] |= AM79C971_RMD1_ENP;
677 physmem_copy_u32_to_vm(d->vm,rx_current+4,rxdc->rmd[1]);
678
679 /* Get the software style */
680 sw_style = d->bcr[20];
681
682 /* Update the message byte count field */
683 rxdc->rmd[2] &= ~AM79C971_RMD2_LEN;
684 rxdc->rmd[2] |= pkt_len + 4;
685
686 switch(sw_style) {
687 case 2:
688 physmem_copy_u32_to_vm(d->vm,rx_current+8,rxdc->rmd[2]);
689 break;
690 case 3:
691 physmem_copy_u32_to_vm(d->vm,rx_current,rxdc->rmd[2]);
692 break;
693 default:
694 AM79C971_LOG(d,"invalid software style %u!\n",sw_style);
695 }
696
697 break;
698 }
699
700 /* Try to acquire the next descriptor */
701 rx_next = rxdesc_get_current(d);
702 rxdn_rmd1 = physmem_copy_u32_from_vm(d->vm,rx_next+4);
703
704 if (!(rxdn_rmd1 & AM79C971_RMD1_OWN)) {
705 rxdc->rmd[1] |= AM79C971_RMD1_ERR | AM79C971_RMD1_BUFF;
706 rxdc->rmd[1] |= AM79C971_RMD1_ENP;
707 physmem_copy_u32_to_vm(d->vm,rx_current+4,rxdc->rmd[1]);
708 break;
709 }
710
711 /* Update rmd1 to store change of OWN bit */
712 physmem_copy_u32_to_vm(d->vm,rx_current+4,rxdc->rmd[1]);
713
714 /* Read the next descriptor from VM physical RAM */
715 rxdesc_read(d,rx_next,&rxdn);
716 rxdc = &rxdn;
717 rx_current = rx_next;
718 }
719
720 /* Update the first RX descriptor */
721 rxd0.rmd[1] &= ~AM79C971_RMD1_OWN;
722 rxd0.rmd[1] |= AM79C971_RMD1_STP;
723 physmem_copy_u32_to_vm(d->vm,rx_start+4,rxd0.rmd[1]);
724
725 d->csr[0] |= AM79C971_CSR0_RINT;
726 am79c971_update_irq_status(d);
727 return(TRUE);
728 }
729
730 /* Handle the RX ring */
731 static int am79c971_handle_rxring(netio_desc_t *nio,
732 u_char *pkt,ssize_t pkt_len,
733 struct am79c971_data *d)
734 {
735 n_eth_hdr_t *hdr;
736
737 /*
738 * Don't start receive if the RX ring address has not been set
739 * and if RX ON is not set.
740 */
741 if ((d->rx_start == 0) || !(d->csr[0] & AM79C971_CSR0_RXON))
742 return(FALSE);
743
744 #if DEBUG_RECEIVE
745 AM79C971_LOG(d,"receiving a packet of %d bytes\n",pkt_len);
746 mem_dump(log_file,pkt,pkt_len);
747 #endif
748
749 AM79C971_LOCK(d);
750
751 /*
752 * Receive only multicast/broadcast trafic + unicast traffic
753 * for this virtual machine.
754 */
755 hdr = (n_eth_hdr_t *)pkt;
756
757 if (am79c971_handle_mac_addr(d,pkt))
758 am79c971_receive_pkt(d,pkt,pkt_len);
759
760 AM79C971_UNLOCK(d);
761 return(TRUE);
762 }
763
764 /* Read a TX descriptor */
765 static int txdesc_read(struct am79c971_data *d,m_uint32_t txd_addr,
766 struct tx_desc *txd)
767 {
768 m_uint32_t buf[4];
769 m_uint8_t sw_style;
770
771 /* Get the software style */
772 sw_style = d->bcr[20];
773
774 /* Read the descriptor from VM physical RAM */
775 physmem_copy_from_vm(d->vm,&buf,txd_addr,sizeof(struct tx_desc));
776
777 switch(sw_style) {
778 case 2:
779 txd->tmd[0] = vmtoh32(buf[0]); /* tb addr */
780 txd->tmd[1] = vmtoh32(buf[1]); /* own flag, ... */
781 txd->tmd[2] = vmtoh32(buf[2]); /* buff, uflo, ... */
782 txd->tmd[3] = vmtoh32(buf[3]); /* user */
783 break;
784
785 case 3:
786 txd->tmd[0] = vmtoh32(buf[2]); /* tb addr */
787 txd->tmd[1] = vmtoh32(buf[1]); /* own flag, ... */
788 txd->tmd[2] = vmtoh32(buf[0]); /* buff, uflo, ... */
789 txd->tmd[3] = vmtoh32(buf[3]); /* user */
790 break;
791
792 default:
793 AM79C971_LOG(d,"invalid software style %u!\n",sw_style);
794 return(-1);
795 }
796
797 return(0);
798 }
799
800 /* Set the address of the next TX descriptor */
801 static inline void txdesc_set_next(struct am79c971_data *d)
802 {
803 d->tx_pos++;
804
805 if (d->tx_pos == d->tx_len)
806 d->tx_pos = 0;
807 }
808
809 /* Compute the address of the current TX descriptor */
810 static inline m_uint32_t txdesc_get_current(struct am79c971_data *d)
811 {
812 return(d->tx_start + (d->tx_pos * sizeof(struct tx_desc)));
813 }
814
815 /* Handle the TX ring (single packet) */
816 static int am79c971_handle_txring_single(struct am79c971_data *d)
817 {
818 u_char pkt[AM79C971_MAX_PKT_SIZE],*pkt_ptr;
819 struct tx_desc txd0,ctxd,ntxd,*ptxd;
820 m_uint32_t tx_start,tx_current;
821 m_uint32_t clen,tot_len;
822
823 if ((d->tx_start == 0) || !(d->csr[0] & AM79C971_CSR0_TXON))
824 return(FALSE);
825
826 /* Copy the current txring descriptor */
827 tx_start = tx_current = txdesc_get_current(d);
828 ptxd = &txd0;
829 txdesc_read(d,tx_start,ptxd);
830
831 /* If we don't own the first descriptor, we cannot transmit */
832 if (!(ptxd->tmd[1] & AM79C971_TMD1_OWN))
833 return(FALSE);
834
835 #if DEBUG_TRANSMIT
836 AM79C971_LOG(d,"am79c971_handle_txring: 1st desc: "
837 "tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x\n",
838 ptxd->tmd[0],ptxd->tmd[1],ptxd->tmd[2],ptxd->tmd[3]);
839 #endif
840
841 /* Empty packet for now */
842 pkt_ptr = pkt;
843 tot_len = 0;
844
845 for(;;) {
846 #if DEBUG_TRANSMIT
847 AM79C971_LOG(d,"am79c971_handle_txring: loop: "
848 "tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x\n",
849 ptxd->tmd[0],ptxd->tmd[1],ptxd->tmd[2],ptxd->tmd[3]);
850 #endif
851 /* Copy packet data */
852 clen = ~((ptxd->tmd[1] & AM79C971_TMD1_LEN) - 1);
853 clen &= AM79C971_TMD1_LEN;
854
855 physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tmd[0],clen);
856
857 pkt_ptr += clen;
858 tot_len += clen;
859
860 /* Clear the OWN bit if this is not the first descriptor */
861 if (!(ptxd->tmd[1] & AM79C971_TMD1_STP)) {
862 ptxd->tmd[1] &= ~AM79C971_TMD1_OWN;
863 physmem_copy_u32_to_vm(d->vm,tx_current+4,ptxd->tmd[1]);
864 }
865
866 /* Set the next descriptor */
867 txdesc_set_next(d);
868
869 /* Stop now if end of packet has been reached */
870 if (ptxd->tmd[1] & AM79C971_TMD1_ENP)
871 break;
872
873 /* Read the next descriptor and try to acquire it */
874 tx_current = txdesc_get_current(d);
875 txdesc_read(d,tx_current,&ntxd);
876
877 if (!(ntxd.tmd[1] & AM79C971_TMD1_OWN)) {
878 AM79C971_LOG(d,"am79c971_handle_txring: UNDERFLOW!\n");
879 return(FALSE);
880 }
881
882 memcpy(&ctxd,&ntxd,sizeof(struct tx_desc));
883 ptxd = &ctxd;
884 }
885
886 if (tot_len != 0) {
887 #if DEBUG_TRANSMIT
888 AM79C971_LOG(d,"sending packet of %u bytes\n",tot_len);
889 mem_dump(log_file,pkt,tot_len);
890 #endif
891 /* rewrite ISL header if required */
892 cisco_isl_rewrite(pkt,tot_len);
893
894 /* send it on wire */
895 netio_send(d->nio,pkt,tot_len);
896 }
897
898 /* Clear the OWN flag of the first descriptor */
899 txd0.tmd[1] &= ~AM79C971_TMD1_OWN;
900 physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.tmd[1]);
901
902 /* Generate TX interrupt */
903 d->csr[0] |= AM79C971_CSR0_TINT;
904 am79c971_update_irq_status(d);
905 return(TRUE);
906 }
907
908 /* Handle the TX ring */
909 static int am79c971_handle_txring(struct am79c971_data *d)
910 {
911 int i;
912
913 AM79C971_LOCK(d);
914
915 for(i=0;i<AM79C971_TXRING_PASS_COUNT;i++)
916 if (!am79c971_handle_txring_single(d))
917 break;
918
919 AM79C971_UNLOCK(d);
920 return(TRUE);
921 }
922
923 /*
924 * pci_am79c971_read()
925 *
926 * Read a PCI register.
927 */
928 static m_uint32_t pci_am79c971_read(cpu_gen_t *cpu,struct pci_device *dev,
929 int reg)
930 {
931 struct am79c971_data *d = dev->priv_data;
932
933 #if DEBUG_PCI_REGS
934 AM79C971_LOG(d,"read PCI register 0x%x\n",reg);
935 #endif
936
937 switch (reg) {
938 case 0x00:
939 return((AM79C971_PCI_PRODUCT_ID << 16) | AM79C971_PCI_VENDOR_ID);
940 case 0x08:
941 return(0x02000002);
942 case PCI_REG_BAR1:
943 return(d->dev->phys_addr);
944 default:
945 return(0);
946 }
947 }
948
949 /*
950 * pci_am79c971_write()
951 *
952 * Write a PCI register.
953 */
954 static void pci_am79c971_write(cpu_gen_t *cpu,struct pci_device *dev,
955 int reg,m_uint32_t value)
956 {
957 struct am79c971_data *d = dev->priv_data;
958
959 #if DEBUG_PCI_REGS
960 AM79C971_LOG(d,"write PCI register 0x%x, value 0x%x\n",reg,value);
961 #endif
962
963 switch(reg) {
964 case PCI_REG_BAR1:
965 vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
966 AM79C971_LOG(d,"registers are mapped at 0x%x\n",value);
967 break;
968 }
969 }
970
971 /*
972 * dev_am79c971_init()
973 *
974 * Generic AMD Am79c971 initialization code.
975 */
976 struct am79c971_data *
977 dev_am79c971_init(vm_instance_t *vm,char *name,int interface_type,
978 struct pci_bus *pci_bus,int pci_device,int irq)
979 {
980 struct am79c971_data *d;
981 struct pci_device *pci_dev;
982 struct vdevice *dev;
983
984 /* Allocate the private data structure for AM79C971 */
985 if (!(d = malloc(sizeof(*d)))) {
986 fprintf(stderr,"%s (AM79C971): out of memory\n",name);
987 return NULL;
988 }
989
990 memset(d,0,sizeof(*d));
991 memcpy(d->mii_regs[0],mii_reg_values,sizeof(mii_reg_values));
992 pthread_mutex_init(&d->lock,NULL);
993
994 /* Add as PCI device */
995 pci_dev = pci_dev_add(pci_bus,name,
996 AM79C971_PCI_VENDOR_ID,AM79C971_PCI_PRODUCT_ID,
997 pci_device,0,irq,
998 d,NULL,pci_am79c971_read,pci_am79c971_write);
999
1000 if (!pci_dev) {
1001 fprintf(stderr,"%s (AM79C971): unable to create PCI device.\n",name);
1002 goto err_pci_dev;
1003 }
1004
1005 /* Create the device itself */
1006 if (!(dev = dev_create(name))) {
1007 fprintf(stderr,"%s (AM79C971): unable to create device.\n",name);
1008 goto err_dev;
1009 }
1010
1011 d->name = name;
1012 d->vm = vm;
1013 d->type = interface_type;
1014 d->pci_dev = pci_dev;
1015 d->dev = dev;
1016
1017 dev->phys_addr = 0;
1018 dev->phys_len = 0x4000;
1019 dev->handler = dev_am79c971_access;
1020 dev->priv_data = d;
1021 return(d);
1022
1023 err_dev:
1024 pci_dev_remove(pci_dev);
1025 err_pci_dev:
1026 free(d);
1027 return NULL;
1028 }
1029
1030 /* Remove an AMD Am79c971 device */
1031 void dev_am79c971_remove(struct am79c971_data *d)
1032 {
1033 if (d != NULL) {
1034 pci_dev_remove(d->pci_dev);
1035 vm_unbind_device(d->vm,d->dev);
1036 cpu_group_rebuild_mts(d->vm->cpu_group);
1037 free(d->dev);
1038 free(d);
1039 }
1040 }
1041
1042 /* Bind a NIO to an AMD Am79c971 device */
1043 int dev_am79c971_set_nio(struct am79c971_data *d,netio_desc_t *nio)
1044 {
1045 /* check that a NIO is not already bound */
1046 if (d->nio != NULL)
1047 return(-1);
1048
1049 d->nio = nio;
1050 d->tx_tid = ptask_add((ptask_callback)am79c971_handle_txring,d,NULL);
1051 netio_rxl_add(nio,(netio_rx_handler_t)am79c971_handle_rxring,d,NULL);
1052 return(0);
1053 }
1054
1055 /* Unbind a NIO from an AMD Am79c971 device */
1056 void dev_am79c971_unset_nio(struct am79c971_data *d)
1057 {
1058 if (d->nio != NULL) {
1059 ptask_remove(d->tx_tid);
1060 netio_rxl_remove(d->nio);
1061 d->nio = NULL;
1062 }
1063 }

  ViewVC Help
Powered by ViewVC 1.1.26