/[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

Annotation of /trunk/dev_am79c971.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * 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 dpavlin 7 #include "cpu.h"
19     #include "vm.h"
20 dpavlin 1 #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 dpavlin 11 #define DEBUG_TRANSMIT 1
34     #define DEBUG_RECEIVE 1
35 dpavlin 1 #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 dpavlin 8 /* Lock */
130     pthread_mutex_t lock;
131    
132 dpavlin 1 /* Interface type (10baseT or 100baseTX) */
133     int type;
134    
135 dpavlin 8 /* RX/TX clearing count */
136     int rx_tx_clear_count;
137    
138 dpavlin 1 /* 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 dpavlin 8 /* Lock/Unlock primitives */
182     #define AM79C971_LOCK(d) pthread_mutex_lock(&(d)->lock)
183     #define AM79C971_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)
184 dpavlin 1
185     static m_uint16_t mii_reg_values[32] = {
186 dpavlin 8 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 dpavlin 1 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
194     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x8060,
195 dpavlin 8 0x8023, 0x0820, 0x0000, 0x3800, 0xA3B9, 0x0000, 0x0000, 0x0000,
196     #endif
197 dpavlin 1 };
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 dpavlin 8 /* Accept systematically frames if we are running in promiscuous mode */
223 dpavlin 1 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 dpavlin 8 static void am79c971_update_irq_status(struct am79c971_data *d)
239 dpavlin 1 {
240     m_uint32_t mask;
241    
242 dpavlin 8 /* Bits set in CR3 disable the specified interrupts */
243     mask = AM79C971_CSR3_IM_MASK & ~(d->csr[3] & AM79C971_CSR3_IM_MASK);
244 dpavlin 1
245     if (d->csr[0] & mask)
246     d->csr[0] |= AM79C971_CSR0_INTR;
247 dpavlin 8 else
248     d->csr[0] &= ~AM79C971_CSR0_INTR;
249 dpavlin 1
250 dpavlin 8 if ((d->csr[0] & (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) ==
251     (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA))
252     {
253 dpavlin 1 pci_dev_trigger_irq(d->vm,d->pci_dev);
254 dpavlin 8 } else {
255     pci_dev_clear_irq(d->vm,d->pci_dev);
256 dpavlin 1 }
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 dpavlin 7 static void am79c971_rdp_access(cpu_gen_t *cpu,struct am79c971_data *d,
349 dpavlin 1 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 dpavlin 8 am79c971_update_irq_status(d);
376 dpavlin 1 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 dpavlin 8
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 dpavlin 1 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 dpavlin 8
409     /* Update IRQ status */
410     am79c971_update_irq_status(d);
411 dpavlin 1 }
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 dpavlin 8 break;
423 dpavlin 1
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 dpavlin 7 static void am79c971_bdp_access(cpu_gen_t *cpu,struct am79c971_data *d,
466 dpavlin 1 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 dpavlin 11 cpu_log(cpu,d->name,
506     "write access to unknown BCR %d, value=0x%x\n",
507 dpavlin 1 d->rap,*data);
508     }
509     #endif
510     }
511     }
512    
513     /*
514     * dev_am79c971_access()
515     */
516 dpavlin 7 void *dev_am79c971_access(cpu_gen_t *cpu,struct vdevice *dev,
517 dpavlin 1 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 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
529 dpavlin 1 } else {
530     cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, "
531 dpavlin 7 "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size);
532 dpavlin 1 }
533     #endif
534    
535 dpavlin 8 AM79C971_LOCK(d);
536    
537 dpavlin 1 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 dpavlin 8 AM79C971_UNLOCK(d);
556 dpavlin 1 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 dpavlin 8
645 dpavlin 1 /* 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 dpavlin 8 am79c971_update_irq_status(d);
727 dpavlin 1 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 dpavlin 11 if ((d->rx_start == 0) || !(d->csr[0] & AM79C971_CSR0_RXON))
742 dpavlin 1 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 dpavlin 8 AM79C971_LOCK(d);
750    
751 dpavlin 1 /*
752     * Receive only multicast/broadcast trafic + unicast traffic
753     * for this virtual machine.
754     */
755     hdr = (n_eth_hdr_t *)pkt;
756 dpavlin 11
757 dpavlin 1 if (am79c971_handle_mac_addr(d,pkt))
758     am79c971_receive_pkt(d,pkt,pkt_len);
759    
760 dpavlin 8 AM79C971_UNLOCK(d);
761 dpavlin 1 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 dpavlin 11
823 dpavlin 1 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 dpavlin 11
831 dpavlin 1 /* If we don't own the first descriptor, we cannot transmit */
832     if (!(ptxd->tmd[1] & AM79C971_TMD1_OWN))
833     return(FALSE);
834 dpavlin 11
835 dpavlin 1 #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 dpavlin 8
855 dpavlin 1 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 dpavlin 11 /* rewrite ISL header if required */
892     cisco_isl_rewrite(pkt,tot_len);
893    
894 dpavlin 1 /* 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 dpavlin 8 am79c971_update_irq_status(d);
905 dpavlin 1 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 dpavlin 8 AM79C971_LOCK(d);
914    
915 dpavlin 1 for(i=0;i<AM79C971_TXRING_PASS_COUNT;i++)
916     if (!am79c971_handle_txring_single(d))
917     break;
918    
919 dpavlin 8 AM79C971_UNLOCK(d);
920 dpavlin 1 return(TRUE);
921     }
922    
923     /*
924     * pci_am79c971_read()
925     *
926     * Read a PCI register.
927     */
928 dpavlin 7 static m_uint32_t pci_am79c971_read(cpu_gen_t *cpu,struct pci_device *dev,
929 dpavlin 1 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 dpavlin 7 static void pci_am79c971_write(cpu_gen_t *cpu,struct pci_device *dev,
955 dpavlin 1 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 dpavlin 8 pthread_mutex_init(&d->lock,NULL);
993 dpavlin 1
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 dpavlin 11 {
1045 dpavlin 1 /* 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