/[dynamips]/trunk/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 /trunk/dev_i8254x.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (hide annotations)
Sat Oct 6 16:26:06 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC3/dev_i8254x.c
File MIME type: text/plain
File size: 34676 byte(s)
dynamips-0.2.7-RC3

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

  ViewVC Help
Powered by ViewVC 1.1.26