/[dynamips]/upstream/dynamips-0.2.7-RC1/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

Annotation of /upstream/dynamips-0.2.7-RC1/dev_am79c971.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Oct 6 16:05:34 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC2/dev_am79c971.c
File MIME type: text/plain
File size: 30192 byte(s)
dynamips-0.2.6-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26