/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_i8254x.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_i8254x.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32887 byte(s)
dynamips-0.2.7-RC1

1 dpavlin 7 /*
2     * Cisco router simulation platform.
3     * Copyright (C) 2007 Christophe Fillot. All rights reserved.
4     *
5     * Intel i8254x (Livengood) 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_i8254x.h"
27    
28     /* Debugging flags */
29     #define DEBUG_MII_REGS 0
30     #define DEBUG_ACCESS 1
31     #define DEBUG_TRANSMIT 0
32     #define DEBUG_RECEIVE 0
33     #define DEBUG_UNKNOWN 1
34    
35     /* Intel i8254x PCI vendor/product codes */
36     #define I8254X_PCI_VENDOR_ID 0x8086
37     #define I8254X_PCI_PRODUCT_ID 0x1001
38    
39     /* Maximum packet size */
40     #define I8254X_MAX_PKT_SIZE 16384
41    
42     /* Register list */
43     #define I8254X_REG_CTRL 0x0000 /* Control Register */
44     #define I8254X_REG_STATUS 0x0008 /* Device Status Register */
45     #define I8254X_REG_CTRLEXT 0x0018 /* Extended Control Register */
46     #define I8254X_REG_MDIC 0x0020 /* MDI Control Register */
47     #define I8254X_REG_FCAL 0x0028 /* Flow Control Address Low */
48     #define I8254X_REG_FCAH 0x002c /* Flow Control Address High */
49     #define I8254X_REG_FCT 0x0030 /* Flow Control Type */
50     #define I8254X_REG_VET 0x0038 /* VLAN Ether Type */
51     #define I8254X_REG_ICR 0x00c0 /* Interrupt Cause Read */
52     #define I8254X_REG_ITR 0x00c4 /* Interrupt Throttling Register */
53     #define I8254X_REG_ICS 0x00c8 /* Interrupt Cause Set Register */
54     #define I8254X_REG_IMS 0x00d0 /* Interrupt Mask Set/Read Register */
55     #define I8254X_REG_IMC 0x00d8 /* Interrupt Mask Clear Register */
56     #define I8254X_REG_RCTL 0x0100 /* Receive Control Register */
57     #define I8254X_REG_FCTTV 0x0170 /* Flow Control Transmit Timer Value */
58     #define I8254X_REG_TXCW 0x0178 /* Transmit Configuration Word */
59     #define I8254X_REG_RXCW 0x0180 /* Receive Configuration Word */
60     #define I8254X_REG_TCTL 0x0400 /* Transmit Control Register */
61     #define I8254X_REG_TIPG 0x0410 /* Transmit Inter Packet Gap */
62    
63     #define I8254X_REG_LEDCTL 0x0E00 /* LED Control */
64     #define I8254X_REG_PBA 0x1000 /* Packet Buffer Allocation */
65    
66     #define I8254X_REG_RDBAL 0x2800 /* RX Descriptor Base Address Low */
67     #define I8254X_REG_RDBAH 0x2804 /* RX Descriptor Base Address High */
68     #define I8254X_REG_RDLEN 0x2808 /* RX Descriptor Length */
69     #define I8254X_REG_RDH 0x2810 /* RX Descriptor Head */
70     #define I8254X_REG_RDT 0x2818 /* RX Descriptor Tail */
71     #define I82542_REG_RDH 0x0120 /* RDH for i82542 */
72     #define I82542_REG_RDT 0x0128 /* RDT for i82542 */
73     #define I8254X_REG_RDTR 0x2820 /* RX Delay Timer Register */
74     #define I8254X_REG_RXDCTL 0x3828 /* RX Descriptor Control */
75     #define I8254X_REG_RADV 0x282c /* RX Int. Absolute Delay Timer */
76     #define I8254X_REG_RSRPD 0x2c00 /* RX Small Packet Detect Interrupt */
77    
78     #define I8254X_REG_TXDMAC 0x3000 /* TX DMA Control */
79     #define I8254X_REG_TDBAL 0x3800 /* TX Descriptor Base Address Low */
80     #define I8254X_REG_TDBAH 0x3804 /* TX Descriptor Base Address Low */
81     #define I8254X_REG_TDLEN 0x3808 /* TX Descriptor Length */
82     #define I8254X_REG_TDH 0x3810 /* TX Descriptor Head */
83     #define I8254X_REG_TDT 0x3818 /* TX Descriptor Tail */
84     #define I82542_REG_TDH 0x0430 /* TDH for i82542 */
85     #define I82542_REG_TDT 0x0438 /* TDT for i82542 */
86     #define I8254X_REG_TIDV 0x3820 /* TX Interrupt Delay Value */
87     #define I8254X_REG_TXDCTL 0x3828 /* TX Descriptor Control */
88     #define I8254X_REG_TADV 0x382c /* TX Absolute Interrupt Delay Value */
89     #define I8254X_REG_TSPMT 0x3830 /* TCP Segmentation Pad & Min Threshold */
90    
91     #define I8254X_REG_RXCSUM 0x5000 /* RX Checksum Control */
92    
93    
94     /* CTRL - Control Register (0x0000) */
95     #define I8254X_CTRL_FD 0x00000001 /* Full Duplex */
96     #define I8254X_CTRL_LRST 0x00000008 /* Link Reset */
97     #define I8254X_CTRL_ASDE 0x00000020 /* Auto-speed detection */
98     #define I8254X_CTRL_SLU 0x00000040 /* Set Link Up */
99     #define I8254X_CTRL_ILOS 0x00000080 /* Invert Loss of Signal */
100     #define I8254X_CTRL_SPEED_MASK 0x00000300 /* Speed selection */
101     #define I8254X_CTRL_SPEED_SHIFT 8
102     #define I8254X_CTRL_FRCSPD 0x00000800 /* Force Speed */
103     #define I8254X_CTRL_FRCDPLX 0x00001000 /* Force Duplex */
104     #define I8254X_CTRL_SDP0_DATA 0x00040000 /* SDP0 data */
105     #define I8254X_CTRL_SDP1_DATA 0x00080000 /* SDP1 data */
106     #define I8254X_CTRL_SDP0_IODIR 0x00400000 /* SDP0 direction */
107     #define I8254X_CTRL_SDP1_IODIR 0x00800000 /* SDP1 direction */
108     #define I8254X_CTRL_RST 0x04000000 /* Device Reset */
109     #define I8254X_CTRL_RFCE 0x08000000 /* RX Flow Ctrl Enable */
110     #define I8254X_CTRL_TFCE 0x10000000 /* TX Flow Ctrl Enable */
111     #define I8254X_CTRL_VME 0x40000000 /* VLAN Mode Enable */
112     #define I8254X_CTRL_PHY_RST 0x80000000 /* PHY reset */
113    
114     /* STATUS - Device Status Register (0x0008) */
115     #define I8254X_STATUS_FD 0x00000001 /* Full Duplex */
116     #define I8254X_STATUS_LU 0x00000002 /* Link Up */
117     #define I8254X_STATUS_TXOFF 0x00000010 /* Transmit paused */
118     #define I8254X_STATUS_TBIMODE 0x00000020 /* TBI Mode */
119     #define I8254X_STATUS_SPEED_MASK 0x000000C0 /* Link Speed setting */
120     #define I8254X_STATUS_SPEED_SHIFT 6
121     #define I8254X_STATUS_ASDV_MASK 0x00000300 /* Auto Speed Detection */
122     #define I8254X_STATUS_ASDV_SHIFT 8
123     #define I8254X_STATUS_PCI66 0x00000800 /* PCI bus speed */
124     #define I8254X_STATUS_BUS64 0x00001000 /* PCI bus width */
125     #define I8254X_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
126     #define I8254X_STATUS_PCIXSPD_MASK 0x0000C000 /* PCI-X speed */
127     #define I8254X_STATUS_PCIXSPD_SHIFT 14
128    
129     /* CTRL_EXT - Extended Device Control Register (0x0018) */
130     #define I8254X_CTRLEXT_PHY_INT 0x00000020 /* PHY interrupt */
131     #define I8254X_CTRLEXT_SDP6_DATA 0x00000040 /* SDP6 data */
132     #define I8254X_CTRLEXT_SDP7_DATA 0x00000080 /* SDP7 data */
133     #define I8254X_CTRLEXT_SDP6_IODIR 0x00000400 /* SDP6 direction */
134     #define I8254X_CTRLEXT_SDP7_IODIR 0x00000800 /* SDP7 direction */
135     #define I8254X_CTRLEXT_ASDCHK 0x00001000 /* Auto-Speed Detect Chk */
136     #define I8254X_CTRLEXT_EE_RST 0x00002000 /* EEPROM reset */
137     #define I8254X_CTRLEXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
138     #define I8254X_CTRLEXT_RO_DIS 0x00020000 /* Relaxed Ordering Dis. */
139     #define I8254X_CTRLEXT_LNKMOD_MASK 0x00C00000 /* Link Mode */
140     #define I8254X_CTRLEXT_LNKMOD_SHIFT 22
141    
142     /* MDIC - MDI Control Register (0x0020) */
143     #define I8254X_MDIC_DATA_MASK 0x0000FFFF /* Data */
144     #define I8254X_MDIC_REG_MASK 0x001F0000 /* PHY Register */
145     #define I8254X_MDIC_REG_SHIFT 16
146     #define I8254X_MDIC_PHY_MASK 0x03E00000 /* PHY Address */
147     #define I8254X_MDIC_PHY_SHIFT 21
148     #define I8254X_MDIC_OP_MASK 0x0C000000 /* Opcode */
149     #define I8254X_MDIC_OP_SHIFT 26
150     #define I8254X_MDIC_R 0x10000000 /* Ready */
151     #define I8254X_MDIC_I 0x20000000 /* Interrupt Enable */
152     #define I8254X_MDIC_E 0x40000000 /* Error */
153    
154     /* ICR - Interrupt Cause Read (0x00c0) */
155     #define I8254X_ICR_TXDW 0x00000001 /* TX Desc Written back */
156     #define I8254X_ICR_TXQE 0x00000002 /* TX Queue Empty */
157     #define I8254X_ICR_LSC 0x00000004 /* Link Status Change */
158     #define I8254X_ICR_RXSEQ 0x00000008 /* RX Sequence Error */
159     #define I8254X_ICR_RXDMT0 0x00000010 /* RX Desc min threshold reached */
160     #define I8254X_ICR_RXO 0x00000040 /* RX Overrun */
161     #define I8254X_ICR_RXT0 0x00000080 /* RX Timer Interrupt */
162     #define I8254X_ICR_MDAC 0x00000200 /* MDIO Access Complete */
163     #define I8254X_ICR_RXCFG 0x00000400
164     #define I8254X_ICR_PHY_INT 0x00001000 /* PHY Interrupt */
165     #define I8254X_ICR_GPI_SDP6 0x00002000 /* GPI on SDP6 */
166     #define I8254X_ICR_GPI_SDP7 0x00004000 /* GPI on SDP7 */
167     #define I8254X_ICR_TXD_LOW 0x00008000 /* TX Desc low threshold hit */
168     #define I8254X_ICR_SRPD 0x00010000 /* Small RX packet detected */
169    
170     /* RCTL - Receive Control Register (0x0100) */
171     #define I8254X_RCTL_EN 0x00000002 /* Receiver Enable */
172     #define I8254X_RCTL_SBP 0x00000004 /* Store Bad Packets */
173     #define I8254X_RCTL_UPE 0x00000008 /* Unicast Promiscuous Enabled */
174     #define I8254X_RCTL_MPE 0x00000010 /* Xcast Promiscuous Enabled */
175     #define I8254X_RCTL_LPE 0x00000020 /* Long Packet Reception Enable */
176     #define I8254X_RCTL_LBM_MASK 0x000000C0 /* Loopback Mode */
177     #define I8254X_RCTL_LBM_SHIFT 6
178     #define I8254X_RCTL_RDMTS_MASK 0x00000300 /* RX Desc Min Threshold Size */
179     #define I8254X_RCTL_RDMTS_SHIFT 8
180     #define I8254X_RCTL_MO_MASK 0x00003000 /* Multicast Offset */
181     #define I8254X_RCTL_MO_SHIFT 12
182     #define I8254X_RCTL_BAM 0x00008000 /* Broadcast Accept Mode */
183     #define I8254X_RCTL_BSIZE_MASK 0x00030000 /* RX Buffer Size */
184     #define I8254X_RCTL_BSIZE_SHIFT 16
185     #define I8254X_RCTL_VFE 0x00040000 /* VLAN Filter Enable */
186     #define I8254X_RCTL_CFIEN 0x00080000 /* CFI Enable */
187     #define I8254X_RCTL_CFI 0x00100000 /* Canonical Form Indicator Bit */
188     #define I8254X_RCTL_DPF 0x00400000 /* Discard Pause Frames */
189     #define I8254X_RCTL_PMCF 0x00800000 /* Pass MAC Control Frames */
190     #define I8254X_RCTL_BSEX 0x02000000 /* Buffer Size Extension */
191     #define I8254X_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
192    
193     /* TCTL - Transmit Control Register (0x0400) */
194     #define I8254X_TCTL_EN 0x00000002 /* Transmit Enable */
195     #define I8254X_TCTL_PSP 0x00000008 /* Pad short packets */
196     #define I8254X_TCTL_SWXOFF 0x00400000 /* Software XOFF Transmission */
197    
198     /* PBA - Packet Buffer Allocation (0x1000) */
199     #define I8254X_PBA_RXA_MASK 0x0000FFFF /* RX Packet Buffer */
200     #define I8254X_PBA_RXA_SHIFT 0
201     #define I8254X_PBA_TXA_MASK 0xFFFF0000 /* TX Packet Buffer */
202     #define I8254X_PBA_TXA_SHIFT 16
203    
204     /* Flow Control Type */
205     #define I8254X_FCT_TYPE_DEFAULT 0x8808
206    
207     /* === TX Descriptor fields === */
208    
209     /* TX Packet Length (word 2) */
210     #define I8254X_TXDESC_LEN_MASK 0x0000ffff
211    
212     /* TX Descriptor CMD field (word 2) */
213     #define I8254X_TXDESC_IDE 0x80000000 /* Interrupt Delay Enable */
214     #define I8254X_TXDESC_VLE 0x40000000 /* VLAN Packet Enable */
215     #define I8254X_TXDESC_DEXT 0x20000000 /* Extension */
216     #define I8254X_TXDESC_RPS 0x10000000 /* Report Packet Sent */
217     #define I8254X_TXDESC_RS 0x08000000 /* Report Status */
218     #define I8254X_TXDESC_IC 0x04000000 /* Insert Checksum */
219     #define I8254X_TXDESC_IFCS 0x02000000 /* Insert FCS */
220     #define I8254X_TXDESC_EOP 0x01000000 /* End Of Packet */
221    
222     /* TX Descriptor STA field (word 3) */
223     #define I8254X_TXDESC_TU 0x00000008 /* Transmit Underrun */
224     #define I8254X_TXDESC_LC 0x00000004 /* Late Collision */
225     #define I8254X_TXDESC_EC 0x00000002 /* Excess Collisions */
226     #define I8254X_TXDESC_DD 0x00000001 /* Descriptor Done */
227    
228     /* === RX Descriptor fields === */
229    
230     /* RX Packet Length (word 2) */
231     #define I8254X_RXDESC_LEN_MASK 0x0000ffff
232    
233     /* RX Descriptor STA field (word 3) */
234     #define I8254X_RXDESC_PIF 0x00000080 /* Passed In-exact Filter */
235     #define I8254X_RXDESC_IPCS 0x00000040 /* IP cksum calculated */
236     #define I8254X_RXDESC_TCPCS 0x00000020 /* TCP cksum calculated */
237     #define I8254X_RXDESC_VP 0x00000008 /* Packet is 802.1Q */
238     #define I8254X_RXDESC_IXSM 0x00000004 /* Ignore cksum indication */
239     #define I8254X_RXDESC_EOP 0x00000002 /* End Of Packet */
240     #define I8254X_RXDESC_DD 0x00000001 /* Descriptor Done */
241    
242    
243    
244     /* Intel i8254x private data */
245     struct i8254x_data {
246     char *name;
247    
248     /* Lock test */
249     pthread_mutex_t lock;
250    
251     /* Physical (MAC) address */
252     n_eth_addr_t mac_addr;
253    
254     /* Device information */
255     struct vdevice *dev;
256    
257     /* PCI device information */
258     struct pci_device *pci_dev;
259    
260     /* Virtual machine */
261     vm_instance_t *vm;
262    
263     /* NetIO descriptor */
264     netio_desc_t *nio;
265    
266     /* TX ring scanner task id */
267     ptask_id_t tx_tid;
268    
269     /* Interrupt registers */
270     m_uint32_t icr,imr;
271    
272     /* Device Control Register */
273     m_uint32_t ctrl;
274    
275     /* Extended Control Register */
276     m_uint32_t ctrl_ext;
277    
278     /* RX/TX Control Registers */
279     m_uint32_t rctl,tctl;
280    
281     /* RX buffer size (computed from RX control register */
282     m_uint32_t rx_buf_size;
283    
284     /* RX/TX ring base addresses */
285     m_uint64_t rx_addr,tx_addr;
286    
287     /* RX/TX descriptor length */
288     m_uint32_t rdlen,tdlen;
289    
290     /* RX/TX descriptor head and tail */
291     m_uint32_t rdh,rdt,tdh,tdt;
292    
293     /* TX packet buffer */
294     m_uint8_t tx_buffer[I8254X_MAX_PKT_SIZE];
295    
296     /* RX IRQ count */
297     m_uint32_t rx_irq_cnt;
298    
299     /* MII/PHY handling */
300     u_int mii_state;
301     u_int mii_bit;
302     u_int mii_opcode;
303     u_int mii_phy;
304     u_int mii_reg;
305     u_int mii_data_pos;
306     u_int mii_data;
307     u_int mii_regs[32][32];
308     };
309    
310     /* TX descriptor */
311     struct tx_desc {
312     m_uint32_t tdes[4];
313     };
314    
315     /* RX descriptor */
316     struct rx_desc {
317     m_uint32_t rdes[4];
318     };
319    
320     #define LVG_LOCK(d) pthread_mutex_lock(&(d)->lock)
321     #define LVG_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)
322    
323     /* Log an message */
324     #define LVG_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
325    
326     /* Read a MII register */
327     static m_uint16_t mii_reg_read(struct i8254x_data *d)
328     {
329     #if DEBUG_MII_REGS
330     LVG_LOG(d,"MII PHY read %d reg %d\n",d->mii_phy,d->mii_reg);
331     #endif
332    
333     switch(d->mii_reg) {
334     case 0x00:
335     return((d->mii_regs[d->mii_phy][d->mii_reg] & ~0x8200) | 0x2000);
336     case 0x01:
337     return(0x782c);
338     case 0x02:
339     return(0x0013);
340     case 0x03:
341     return(0x61d4);
342     case 0x05:
343     return(0x41e1);
344     case 0x06:
345     return(0x1);
346     case 0x11:
347     return(0x4700);
348     default:
349     return(d->mii_regs[d->mii_phy][d->mii_reg]);
350     }
351     }
352    
353     /* Write a MII register */
354     static void mii_reg_write(struct i8254x_data *d)
355     {
356     #if DEBUG_MII_REGS
357     LVG_LOG(d,"MII PHY write %d reg %d value %04x\n",
358     d->mii_phy,d->mii_reg,d->mii_data);
359     #endif
360     assert(d->mii_phy < 32);
361     assert(d->mii_reg < 32);
362     d->mii_regs[d->mii_phy][d->mii_reg] = d->mii_data;
363     }
364    
365     enum {
366     MII_OPCODE_READ = 1,
367     MII_OPCODE_WRITE,
368     };
369    
370     /* MII Finite State Machine */
371     static void mii_access(struct i8254x_data *d)
372     {
373     switch(d->mii_state) {
374     case 0: /* reset */
375     d->mii_phy = 0;
376     d->mii_reg = 0;
377     d->mii_data_pos = 15;
378     d->mii_data = 0;
379    
380     case 1: /* idle */
381     if (!d->mii_bit)
382     d->mii_state = 2;
383     else
384     d->mii_state = 1;
385     break;
386    
387     case 2: /* start */
388     d->mii_state = d->mii_bit ? 3 : 0;
389     break;
390    
391     case 3: /* opcode */
392     d->mii_state = d->mii_bit ? 4 : 5;
393     break;
394    
395     case 4: /* read: opcode "10" */
396     if (!d->mii_bit) {
397     d->mii_opcode = MII_OPCODE_READ;
398     d->mii_state = 6;
399     } else {
400     d->mii_state = 0;
401     }
402     break;
403    
404     case 5: /* write: opcode "01" */
405     if (d->mii_bit) {
406     d->mii_opcode = MII_OPCODE_WRITE;
407     d->mii_state = 6;
408     } else {
409     d->mii_state = 0;
410     }
411     break;
412    
413     case 6 ... 10: /* phy */
414     d->mii_phy <<= 1;
415     d->mii_phy |= d->mii_bit;
416     d->mii_state++;
417     break;
418    
419     case 11 ... 15: /* reg */
420     d->mii_reg <<= 1;
421     d->mii_reg |= d->mii_bit;
422     d->mii_state++;
423     break;
424    
425     case 16 ... 17: /* ta */
426     if (d->mii_opcode == MII_OPCODE_READ)
427     d->mii_state = 18;
428     else
429     d->mii_state++;
430     break;
431    
432     case 18:
433     if (d->mii_opcode == MII_OPCODE_READ) {
434     d->mii_data = mii_reg_read(d);
435     d->mii_state++;
436     }
437    
438     case 19 ... 35:
439     if (d->mii_opcode == MII_OPCODE_READ) {
440     d->mii_bit = (d->mii_data >> d->mii_data_pos) & 0x1;
441     } else {
442     d->mii_data |= d->mii_bit << d->mii_data_pos;
443     }
444    
445     if (!d->mii_data_pos) {
446     if (d->mii_opcode == MII_OPCODE_WRITE)
447     mii_reg_write(d);
448     d->mii_state = 0;
449     } else {
450     d->mii_state++;
451     }
452    
453     d->mii_data_pos--;
454     break;
455    
456     default:
457     printf("MII: impossible state %u!\n",d->mii_state);
458     }
459     }
460    
461     /* Update the interrupt status */
462     static inline void dev_i8254x_update_irq_status(struct i8254x_data *d)
463     {
464     if (d->icr & d->imr)
465     pci_dev_trigger_irq(d->vm,d->pci_dev);
466     }
467    
468     /* Compute RX buffer size */
469     static inline void dev_i8254x_set_rx_buf_size(struct i8254x_data *d)
470     {
471     m_uint32_t bsize;
472    
473     bsize = (d->rctl & I8254X_RCTL_BSIZE_MASK) >> I8254X_RCTL_BSIZE_SHIFT;
474    
475     if (!(d->rctl & I8254X_RCTL_BSEX)) {
476     /* Standard buffer sizes */
477     switch(bsize) {
478     case 0:
479     d->rx_buf_size = 2048;
480     break;
481     case 1:
482     d->rx_buf_size = 1024;
483     break;
484     case 2:
485     d->rx_buf_size = 512;
486     break;
487     case 3:
488     d->rx_buf_size = 256;
489     break;
490     }
491     } else {
492     /* Extended buffer sizes */
493     switch(bsize) {
494     case 0:
495     d->rx_buf_size = 0; /* invalid */
496     break;
497     case 1:
498     d->rx_buf_size = 16384;
499     break;
500     case 2:
501     d->rx_buf_size = 8192;
502     break;
503     case 3:
504     d->rx_buf_size = 4096;
505     break;
506     }
507     }
508     }
509    
510     /*
511     * dev_i8254x_access()
512     */
513     void *dev_i8254x_access(cpu_gen_t *cpu,struct vdevice *dev,
514     m_uint32_t offset,u_int op_size,u_int op_type,
515     m_uint64_t *data)
516     {
517     struct i8254x_data *d = dev->priv_data;
518    
519     if (op_type == MTS_READ)
520     *data = 0x0;
521    
522     #if DEBUG_ACCESS
523     if (op_type == MTS_READ) {
524     cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n",
525     offset,cpu_get_pc(cpu),op_size);
526     } else {
527     cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, "
528     "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size);
529     }
530     #endif
531    
532     LVG_LOCK(d);
533    
534     switch(offset) {
535     /* Link is Up and Full Duplex */
536     case I8254X_REG_STATUS:
537     if (op_type == MTS_READ)
538     *data = I8254X_STATUS_LU | I8254X_STATUS_FD ;
539     break;
540    
541     /* Device Control Register */
542     case I8254X_REG_CTRL:
543     if (op_type == MTS_WRITE)
544     d->ctrl = *data;
545     else
546     *data = d->ctrl;
547     break;
548    
549     /* Extended Device Control Register */
550     case I8254X_REG_CTRLEXT:
551     if (op_type == MTS_WRITE) {
552     /* MDIO clock set ? */
553     if (!(d->ctrl_ext & I8254X_CTRLEXT_SDP6_DATA) &&
554     (*data & I8254X_CTRLEXT_SDP6_DATA))
555     {
556     if (*data & I8254X_CTRLEXT_SDP7_IODIR)
557     d->mii_bit = (*data & I8254X_CTRLEXT_SDP7_DATA) ? 1 : 0;
558    
559     mii_access(d);
560     }
561    
562     d->ctrl_ext = *data;
563     } else {
564     *data = d->ctrl_ext;
565    
566     if (!(d->ctrl_ext & I8254X_CTRLEXT_SDP7_IODIR)) {
567     if (d->mii_bit)
568     *data |= I8254X_CTRLEXT_SDP7_DATA;
569     else
570     *data &= ~I8254X_CTRLEXT_SDP7_DATA;
571     }
572     }
573     break;
574    
575     /* XXX */
576     case I8254X_REG_MDIC:
577     if (op_type == MTS_READ)
578     *data = 1 << 28;
579     break;
580    
581     /*
582     * Interrupt Cause Read Register.
583     *
584     * Notice: a read clears all interrupt bits.
585     */
586     case I8254X_REG_ICR:
587     if (op_type == MTS_READ) {
588     *data = d->icr;
589     d->icr = 0;
590    
591     if (d->rx_irq_cnt > 0) {
592     d->icr |= I8254X_ICR_RXT0;
593     d->rx_irq_cnt--;
594     }
595    
596     dev_i8254x_update_irq_status(d);
597     }
598     break;
599    
600     /* Interrupt Cause Set Register */
601     case I8254X_REG_ICS:
602     if (op_type == MTS_WRITE) {
603     d->icr |= *data;
604     dev_i8254x_update_irq_status(d);
605     }
606     break;
607    
608     /* Interrupt Mask Set/Read Register */
609     case I8254X_REG_IMS:
610     if (op_type == MTS_WRITE) {
611     d->imr |= *data;
612     dev_i8254x_update_irq_status(d);
613     } else {
614     *data = d->imr;
615     }
616     break;
617    
618     /* Interrupt Mask Clear Register */
619     case I8254X_REG_IMC:
620     if (op_type == MTS_WRITE) {
621     d->imr &= ~(*data);
622     dev_i8254x_update_irq_status(d);
623     }
624     break;
625    
626     /* Receive Control Register */
627     case I8254X_REG_RCTL:
628     if (op_type == MTS_READ) {
629     *data = d->rctl;
630     } else {
631     d->rctl = *data;
632     dev_i8254x_set_rx_buf_size(d);
633     }
634     break;
635    
636     /* Transmit Control Register */
637     case I8254X_REG_TCTL:
638     if (op_type == MTS_READ)
639     *data = d->tctl;
640     else
641     d->tctl = *data;
642     break;
643    
644     /* RX Descriptor Base Address Low */
645     case I8254X_REG_RDBAL:
646     if (op_type == MTS_WRITE) {
647     d->rx_addr &= 0xFFFFFFFF00000000ULL;
648     d->rx_addr |= (m_uint32_t)(*data);
649     } else {
650     *data = (m_uint32_t)d->rx_addr;
651     }
652     break;
653    
654     /* RX Descriptor Base Address High */
655     case I8254X_REG_RDBAH:
656     if (op_type == MTS_WRITE) {
657     d->rx_addr &= 0x00000000FFFFFFFFULL;
658     d->rx_addr |= *data << 32;
659     } else {
660     *data = d->rx_addr >> 32;
661     }
662     break;
663    
664     /* TX Descriptor Base Address Low */
665     case I8254X_REG_TDBAL:
666     if (op_type == MTS_WRITE) {
667     d->tx_addr &= 0xFFFFFFFF00000000ULL;
668     d->tx_addr |= (m_uint32_t)(*data);
669     } else {
670     *data = (m_uint32_t)d->tx_addr;
671     }
672     break;
673    
674     /* TX Descriptor Base Address High */
675     case I8254X_REG_TDBAH:
676     if (op_type == MTS_WRITE) {
677     d->tx_addr &= 0x00000000FFFFFFFFULL;
678     d->tx_addr |= *data << 32;
679     } else {
680     *data = d->tx_addr >> 32;
681     }
682     break;
683    
684     /* RX Descriptor Length */
685     case I8254X_REG_RDLEN:
686     if (op_type == MTS_WRITE)
687     d->rdlen = *data & 0xFFF80;
688     else
689     *data = d->rdlen;
690     break;
691    
692     /* TX Descriptor Length */
693     case I8254X_REG_TDLEN:
694     if (op_type == MTS_WRITE)
695     d->tdlen = *data & 0xFFF80;
696     else
697     *data = d->tdlen;
698     break;
699    
700     /* RX Descriptor Head */
701     case I82542_REG_RDH:
702     case I8254X_REG_RDH:
703     if (op_type == MTS_WRITE)
704     d->rdh = *data & 0xFFFF;
705     else
706     *data = d->rdh;
707     break;
708    
709     /* RX Descriptor Tail */
710     case I8254X_REG_RDT:
711     case I82542_REG_RDT:
712     if (op_type == MTS_WRITE)
713     d->rdt = *data & 0xFFFF;
714     else
715     *data = d->rdt;
716     break;
717    
718     /* TX Descriptor Head */
719     case I82542_REG_TDH:
720     case I8254X_REG_TDH:
721     if (op_type == MTS_WRITE)
722     d->tdh = *data & 0xFFFF;
723     else
724     *data = d->tdh;
725     break;
726    
727     /* TX Descriptor Tail */
728     case I82542_REG_TDT:
729     case I8254X_REG_TDT:
730     if (op_type == MTS_WRITE)
731     d->tdt = *data & 0xFFFF;
732     else
733     *data = d->tdt;
734     break;
735    
736     #if DEBUG_UNKNOWN
737     default:
738     if (op_type == MTS_READ) {
739     cpu_log(cpu,d->name,
740     "read access to unknown offset=0x%x, "
741     "pc=0x%llx (size=%u)\n",
742     offset,cpu_get_pc(cpu),op_size);
743     } else {
744     cpu_log(cpu,d->name,
745     "write access to unknown offset=0x%x, pc=0x%llx, "
746     "val=0x%llx (size=%u)\n",
747     offset,cpu_get_pc(cpu),*data,op_size);
748     }
749     #endif
750     }
751    
752     LVG_UNLOCK(d);
753     return NULL;
754     }
755    
756     /* Read a TX descriptor */
757     static void txdesc_read(struct i8254x_data *d,m_uint64_t txd_addr,
758     struct tx_desc *txd)
759     {
760     /* Get the descriptor from VM physical RAM */
761     physmem_copy_from_vm(d->vm,txd,txd_addr,sizeof(struct tx_desc));
762    
763     /* byte-swapping */
764     txd->tdes[0] = vmtoh32(txd->tdes[0]);
765     txd->tdes[1] = vmtoh32(txd->tdes[1]);
766     txd->tdes[2] = vmtoh32(txd->tdes[2]);
767     txd->tdes[3] = vmtoh32(txd->tdes[3]);
768     }
769    
770     /* Handle the TX ring */
771     static int dev_i8254x_handle_txring(struct i8254x_data *d)
772     {
773     m_uint64_t txd_addr,buf_addr;
774     m_uint32_t buf_len,tot_len;
775     m_uint32_t norm_len,icr;
776     struct tx_desc txd;
777     m_uint8_t *pkt_ptr;
778    
779     /* Transmit Enabled ? */
780     if (!(d->tctl & I8254X_TCTL_EN))
781     return(FALSE);
782    
783     /* If Head is at same position than Tail, the ring is empty */
784     if (d->tdh == d->tdt)
785     return(FALSE);
786    
787     LVG_LOCK(d);
788    
789     /* Empty packet for now */
790     pkt_ptr = d->tx_buffer;
791     tot_len = 0;
792     icr = 0;
793    
794     while(d->tdh != d->tdt) {
795     txd_addr = d->tx_addr + (d->tdh * sizeof(struct tx_desc));
796     txdesc_read(d,txd_addr,&txd);
797    
798     /* Copy the packet buffer */
799     buf_addr = ((m_uint64_t)txd.tdes[1] << 32) | txd.tdes[0];
800     buf_len = txd.tdes[2] & I8254X_TXDESC_LEN_MASK;
801    
802     norm_len = normalize_size(buf_len,4,0);
803     physmem_copy_from_vm(d->vm,pkt_ptr,buf_addr,norm_len);
804     mem_bswap32(pkt_ptr,norm_len);
805    
806     pkt_ptr += buf_len;
807     tot_len += buf_len;
808    
809     /* Write the descriptor done bit if required */
810     if (txd.tdes[2] & I8254X_TXDESC_RS) {
811     txd.tdes[3] |= I8254X_TXDESC_DD;
812     icr |= I8254X_ICR_TXDW;
813     physmem_copy_u32_to_vm(d->vm,txd_addr+0x0c,txd.tdes[3]);
814     }
815    
816     /* Go to the next descriptor. Wrap ring if we are at end */
817     if (++d->tdh == (d->tdlen / sizeof(struct tx_desc)))
818     d->tdh = 0;
819    
820     /* End of packet ? */
821     if (txd.tdes[2] & I8254X_TXDESC_EOP) {
822     netio_send(d->nio,d->tx_buffer,tot_len);
823     break;
824     }
825     }
826    
827     if (d->tdh == d->tdt)
828     icr |= I8254X_ICR_TXQE;
829    
830     /* Update the interrupt cause register and trigger IRQ if needed */
831     d->icr |= icr;
832     dev_i8254x_update_irq_status(d);
833     LVG_UNLOCK(d);
834     return(TRUE);
835     }
836    
837     /* Read a RX descriptor */
838     static void rxdesc_read(struct i8254x_data *d,m_uint64_t rxd_addr,
839     struct rx_desc *rxd)
840     {
841     /* Get the descriptor from VM physical RAM */
842     physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc));
843    
844     /* byte-swapping */
845     rxd->rdes[0] = vmtoh32(rxd->rdes[0]);
846     rxd->rdes[1] = vmtoh32(rxd->rdes[1]);
847     rxd->rdes[2] = vmtoh32(rxd->rdes[2]);
848     rxd->rdes[3] = vmtoh32(rxd->rdes[3]);
849     }
850    
851     /*
852     * Put a packet in the RX ring.
853     */
854     static int dev_i8254x_receive_pkt(struct i8254x_data *d,
855     u_char *pkt,ssize_t pkt_len)
856     {
857     m_uint64_t rxd_addr,buf_addr;
858     m_uint32_t cur_len,norm_len,tot_len;
859     struct rx_desc rxd;
860     m_uint32_t icr;
861     u_char *pkt_ptr;
862    
863     if (!d->rx_buf_size)
864     return(FALSE);
865    
866     LVG_LOCK(d);
867     pkt_ptr = pkt;
868     tot_len = pkt_len;
869     icr = 0;
870    
871     while(tot_len > 0) {
872     /* No descriptor available: RX overrun condition */
873     if (d->rdh == d->rdt) {
874     icr |= I8254X_ICR_RXO;
875     break;
876     }
877    
878     rxd_addr = d->rx_addr + (d->rdh * sizeof(struct rx_desc));
879     rxdesc_read(d,rxd_addr,&rxd);
880    
881     cur_len = (tot_len > d->rx_buf_size) ? d->rx_buf_size : tot_len;
882    
883     /* Copy the packet data into the RX buffer */
884     buf_addr = ((m_uint64_t)rxd.rdes[1] << 32) | rxd.rdes[0];
885    
886     norm_len = normalize_size(cur_len,4,0);
887     mem_bswap32(pkt_ptr,norm_len);
888     physmem_copy_to_vm(d->vm,pkt_ptr,buf_addr,norm_len);
889     tot_len -= cur_len;
890     pkt_ptr += cur_len;
891    
892     /* Set length field */
893     rxd.rdes[2] = cur_len;
894    
895     /* Set the status */
896     rxd.rdes[3] = I8254X_RXDESC_IXSM|I8254X_RXDESC_DD;
897    
898     if (!tot_len) {
899     rxd.rdes[3] |= I8254X_RXDESC_EOP;
900     icr |= I8254X_ICR_RXT0;
901     d->rx_irq_cnt++;
902     rxd.rdes[2] += 4; /* FCS */
903     }
904    
905     /* Write back updated descriptor */
906     physmem_copy_u32_to_vm(d->vm,rxd_addr+0x08,rxd.rdes[2]);
907     physmem_copy_u32_to_vm(d->vm,rxd_addr+0x0c,rxd.rdes[3]);
908    
909     /* Goto to the next descriptor, and wrap if necessary */
910     if (++d->rdh == (d->rdlen / sizeof(struct rx_desc)))
911     d->rdh = 0;
912     }
913    
914     /* Update the interrupt cause register and trigger IRQ if needed */
915     d->icr |= icr;
916     dev_i8254x_update_irq_status(d);
917     LVG_UNLOCK(d);
918     return(TRUE);
919     }
920    
921     /* Handle the RX ring */
922     static int dev_i8254x_handle_rxring(netio_desc_t *nio,
923     u_char *pkt,ssize_t pkt_len,
924     struct i8254x_data *d)
925     {
926     /*
927     * Don't start receive if RX has not been enabled in RCTL register.
928     */
929     if (!(d->rctl & I8254X_RCTL_EN))
930     return(FALSE);
931    
932     #if DEBUG_RECEIVE
933     LVG_LOG(d,"receiving a packet of %d bytes\n",pkt_len);
934     mem_dump(log_file,pkt,pkt_len);
935     #endif
936    
937     /*
938     * Receive only multicast/broadcast trafic + unicast traffic
939     * for this virtual machine.
940     */
941     //if (dec21140_handle_mac_addr(d,pkt))
942     return(dev_i8254x_receive_pkt(d,pkt,pkt_len));
943    
944     return(FALSE);
945     }
946    
947     /*
948     * pci_i8254x_read()
949     *
950     * Read a PCI register.
951     */
952     static m_uint32_t pci_i8254x_read(cpu_gen_t *cpu,struct pci_device *dev,
953     int reg)
954     {
955     struct i8254x_data *d = dev->priv_data;
956    
957     #if DEBUG_PCI_REGS
958     I8254X_LOG(d,"read PCI register 0x%x\n",reg);
959     #endif
960    
961     switch (reg) {
962     case 0x00:
963     return((I8254X_PCI_PRODUCT_ID << 16) | I8254X_PCI_VENDOR_ID);
964     case 0x08:
965     return(0x02000002);
966     case PCI_REG_BAR0:
967     return(d->dev->phys_addr);
968     default:
969     return(0);
970     }
971     }
972    
973     /*
974     * pci_i8254x_write()
975     *
976     * Write a PCI register.
977     */
978     static void pci_i8254x_write(cpu_gen_t *cpu,struct pci_device *dev,
979     int reg,m_uint32_t value)
980     {
981     struct i8254x_data *d = dev->priv_data;
982    
983     #if DEBUG_PCI_REGS
984     LVG_LOG(d,"write PCI register 0x%x, value 0x%x\n",reg,value);
985     #endif
986    
987     switch(reg) {
988     case PCI_REG_BAR0:
989     vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
990     LVG_LOG(d,"registers are mapped at 0x%x\n",value);
991     break;
992     }
993     }
994    
995     /*
996     * dev_i8254x_init()
997     */
998     struct i8254x_data *
999     dev_i8254x_init(vm_instance_t *vm,char *name,int interface_type,
1000     struct pci_bus *pci_bus,int pci_device,int irq)
1001     {
1002     struct i8254x_data *d;
1003     struct pci_device *pci_dev;
1004     struct vdevice *dev;
1005    
1006     /* Allocate the private data structure for I8254X */
1007     if (!(d = malloc(sizeof(*d)))) {
1008     fprintf(stderr,"%s (i8254x): out of memory\n",name);
1009     return NULL;
1010     }
1011    
1012     memset(d,0,sizeof(*d));
1013     pthread_mutex_init(&d->lock,NULL);
1014    
1015     /* Add as PCI device */
1016     pci_dev = pci_dev_add(pci_bus,name,
1017     I8254X_PCI_VENDOR_ID,I8254X_PCI_PRODUCT_ID,
1018     pci_device,0,irq,
1019     d,NULL,pci_i8254x_read,pci_i8254x_write);
1020    
1021     if (!pci_dev) {
1022     fprintf(stderr,"%s (i8254x): unable to create PCI device.\n",name);
1023     goto err_pci_dev;
1024     }
1025    
1026     /* Create the device itself */
1027     if (!(dev = dev_create(name))) {
1028     fprintf(stderr,"%s (i8254x): unable to create device.\n",name);
1029     goto err_dev;
1030     }
1031    
1032     d->name = name;
1033     d->vm = vm;
1034     d->pci_dev = pci_dev;
1035     d->dev = dev;
1036    
1037     dev->phys_addr = 0;
1038     dev->phys_len = 0x10000;
1039     dev->handler = dev_i8254x_access;
1040     dev->priv_data = d;
1041     return(d);
1042    
1043     err_dev:
1044     pci_dev_remove(pci_dev);
1045     err_pci_dev:
1046     free(d);
1047     return NULL;
1048     }
1049    
1050     /* Remove an Intel i8254x device */
1051     void dev_i8254x_remove(struct i8254x_data *d)
1052     {
1053     if (d != NULL) {
1054     pci_dev_remove(d->pci_dev);
1055     vm_unbind_device(d->vm,d->dev);
1056     cpu_group_rebuild_mts(d->vm->cpu_group);
1057     free(d->dev);
1058     free(d);
1059     }
1060     }
1061    
1062     /* Bind a NIO to an Intel i8254x device */
1063     int dev_i8254x_set_nio(struct i8254x_data *d,netio_desc_t *nio)
1064     {
1065     /* check that a NIO is not already bound */
1066     if (d->nio != NULL)
1067     return(-1);
1068    
1069     d->nio = nio;
1070     d->tx_tid = ptask_add((ptask_callback)dev_i8254x_handle_txring,d,NULL);
1071     netio_rxl_add(nio,(netio_rx_handler_t)dev_i8254x_handle_rxring,d,NULL);
1072     return(0);
1073     }
1074    
1075     /* Unbind a NIO from an Intel i8254x device */
1076     void dev_i8254x_unset_nio(struct i8254x_data *d)
1077     {
1078     if (d->nio != NULL) {
1079     ptask_remove(d->tx_tid);
1080     netio_rxl_remove(d->nio);
1081     d->nio = NULL;
1082     }
1083     }

  ViewVC Help
Powered by ViewVC 1.1.26