/[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 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 34882 byte(s)
make working copy

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     /* Intel i8254x private data */
251     struct i8254x_data {
252     char *name;
253    
254     /* Lock test */
255     pthread_mutex_t lock;
256    
257     /* Physical (MAC) address */
258     n_eth_addr_t mac_addr;
259    
260     /* Device information */
261     struct vdevice *dev;
262    
263     /* PCI device information */
264     struct pci_device *pci_dev;
265    
266     /* Virtual machine */
267     vm_instance_t *vm;
268    
269     /* NetIO descriptor */
270     netio_desc_t *nio;
271    
272     /* TX ring scanner task id */
273     ptask_id_t tx_tid;
274    
275     /* Interrupt registers */
276     m_uint32_t icr,imr;
277    
278     /* Device Control Register */
279     m_uint32_t ctrl;
280    
281     /* Extended Control Register */
282     m_uint32_t ctrl_ext;
283    
284 dpavlin 8 /* Flow Control registers */
285     m_uint32_t fcal,fcah,fct;
286    
287     /* RX Delay Timer */
288     m_uint32_t rdtr;
289    
290 dpavlin 7 /* RX/TX Control Registers */
291     m_uint32_t rctl,tctl;
292    
293     /* RX buffer size (computed from RX control register */
294     m_uint32_t rx_buf_size;
295    
296     /* RX/TX ring base addresses */
297     m_uint64_t rx_addr,tx_addr;
298    
299     /* RX/TX descriptor length */
300     m_uint32_t rdlen,tdlen;
301    
302     /* RX/TX descriptor head and tail */
303     m_uint32_t rdh,rdt,tdh,tdt;
304    
305     /* TX packet buffer */
306     m_uint8_t tx_buffer[I8254X_MAX_PKT_SIZE];
307    
308     /* RX IRQ count */
309     m_uint32_t rx_irq_cnt;
310    
311     /* MII/PHY handling */
312     u_int mii_state;
313     u_int mii_bit;
314     u_int mii_opcode;
315     u_int mii_phy;
316     u_int mii_reg;
317     u_int mii_data_pos;
318     u_int mii_data;
319     u_int mii_regs[32][32];
320     };
321    
322     /* TX descriptor */
323     struct tx_desc {
324     m_uint32_t tdes[4];
325     };
326    
327     /* RX descriptor */
328     struct rx_desc {
329     m_uint32_t rdes[4];
330     };
331    
332     #define LVG_LOCK(d) pthread_mutex_lock(&(d)->lock)
333     #define LVG_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)
334    
335     /* Log an message */
336     #define LVG_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
337    
338     /* Read a MII register */
339     static m_uint16_t mii_reg_read(struct i8254x_data *d)
340     {
341     #if DEBUG_MII_REGS
342     LVG_LOG(d,"MII PHY read %d reg %d\n",d->mii_phy,d->mii_reg);
343     #endif
344    
345     switch(d->mii_reg) {
346     case 0x00:
347     return((d->mii_regs[d->mii_phy][d->mii_reg] & ~0x8200) | 0x2000);
348     case 0x01:
349     return(0x782c);
350     case 0x02:
351     return(0x0013);
352     case 0x03:
353     return(0x61d4);
354     case 0x05:
355     return(0x41e1);
356     case 0x06:
357 dpavlin 8 return(0x0001);
358 dpavlin 7 case 0x11:
359     return(0x4700);
360     default:
361     return(d->mii_regs[d->mii_phy][d->mii_reg]);
362     }
363     }
364    
365     /* Write a MII register */
366     static void mii_reg_write(struct i8254x_data *d)
367     {
368     #if DEBUG_MII_REGS
369     LVG_LOG(d,"MII PHY write %d reg %d value %04x\n",
370     d->mii_phy,d->mii_reg,d->mii_data);
371     #endif
372     assert(d->mii_phy < 32);
373     assert(d->mii_reg < 32);
374     d->mii_regs[d->mii_phy][d->mii_reg] = d->mii_data;
375     }
376    
377     enum {
378     MII_OPCODE_READ = 1,
379     MII_OPCODE_WRITE,
380     };
381    
382     /* MII Finite State Machine */
383     static void mii_access(struct i8254x_data *d)
384     {
385     switch(d->mii_state) {
386     case 0: /* reset */
387     d->mii_phy = 0;
388     d->mii_reg = 0;
389     d->mii_data_pos = 15;
390     d->mii_data = 0;
391    
392     case 1: /* idle */
393     if (!d->mii_bit)
394     d->mii_state = 2;
395     else
396     d->mii_state = 1;
397     break;
398    
399     case 2: /* start */
400     d->mii_state = d->mii_bit ? 3 : 0;
401     break;
402    
403     case 3: /* opcode */
404     d->mii_state = d->mii_bit ? 4 : 5;
405     break;
406    
407     case 4: /* read: opcode "10" */
408     if (!d->mii_bit) {
409     d->mii_opcode = MII_OPCODE_READ;
410     d->mii_state = 6;
411     } else {
412     d->mii_state = 0;
413     }
414     break;
415    
416     case 5: /* write: opcode "01" */
417     if (d->mii_bit) {
418     d->mii_opcode = MII_OPCODE_WRITE;
419     d->mii_state = 6;
420     } else {
421     d->mii_state = 0;
422     }
423     break;
424    
425     case 6 ... 10: /* phy */
426     d->mii_phy <<= 1;
427     d->mii_phy |= d->mii_bit;
428     d->mii_state++;
429     break;
430    
431     case 11 ... 15: /* reg */
432     d->mii_reg <<= 1;
433     d->mii_reg |= d->mii_bit;
434     d->mii_state++;
435     break;
436    
437     case 16 ... 17: /* ta */
438     if (d->mii_opcode == MII_OPCODE_READ)
439     d->mii_state = 18;
440     else
441     d->mii_state++;
442     break;
443    
444     case 18:
445     if (d->mii_opcode == MII_OPCODE_READ) {
446     d->mii_data = mii_reg_read(d);
447     d->mii_state++;
448     }
449    
450     case 19 ... 35:
451     if (d->mii_opcode == MII_OPCODE_READ) {
452     d->mii_bit = (d->mii_data >> d->mii_data_pos) & 0x1;
453     } else {
454     d->mii_data |= d->mii_bit << d->mii_data_pos;
455     }
456    
457     if (!d->mii_data_pos) {
458     if (d->mii_opcode == MII_OPCODE_WRITE)
459     mii_reg_write(d);
460     d->mii_state = 0;
461     } else {
462     d->mii_state++;
463     }
464    
465     d->mii_data_pos--;
466     break;
467    
468     default:
469     printf("MII: impossible state %u!\n",d->mii_state);
470     }
471     }
472    
473     /* Update the interrupt status */
474     static inline void dev_i8254x_update_irq_status(struct i8254x_data *d)
475     {
476     if (d->icr & d->imr)
477     pci_dev_trigger_irq(d->vm,d->pci_dev);
478 dpavlin 11 else
479 dpavlin 8 pci_dev_clear_irq(d->vm,d->pci_dev);
480 dpavlin 7 }
481    
482     /* Compute RX buffer size */
483     static inline void dev_i8254x_set_rx_buf_size(struct i8254x_data *d)
484     {
485     m_uint32_t bsize;
486    
487     bsize = (d->rctl & I8254X_RCTL_BSIZE_MASK) >> I8254X_RCTL_BSIZE_SHIFT;
488    
489     if (!(d->rctl & I8254X_RCTL_BSEX)) {
490     /* Standard buffer sizes */
491     switch(bsize) {
492     case 0:
493     d->rx_buf_size = 2048;
494     break;
495     case 1:
496     d->rx_buf_size = 1024;
497     break;
498     case 2:
499     d->rx_buf_size = 512;
500     break;
501     case 3:
502     d->rx_buf_size = 256;
503     break;
504     }
505     } else {
506     /* Extended buffer sizes */
507     switch(bsize) {
508     case 0:
509     d->rx_buf_size = 0; /* invalid */
510     break;
511     case 1:
512     d->rx_buf_size = 16384;
513     break;
514     case 2:
515     d->rx_buf_size = 8192;
516     break;
517     case 3:
518     d->rx_buf_size = 4096;
519     break;
520     }
521     }
522     }
523    
524     /*
525     * dev_i8254x_access()
526     */
527     void *dev_i8254x_access(cpu_gen_t *cpu,struct vdevice *dev,
528     m_uint32_t offset,u_int op_size,u_int op_type,
529     m_uint64_t *data)
530     {
531     struct i8254x_data *d = dev->priv_data;
532    
533     if (op_type == MTS_READ)
534     *data = 0x0;
535    
536     #if DEBUG_ACCESS
537     if (op_type == MTS_READ) {
538     cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n",
539     offset,cpu_get_pc(cpu),op_size);
540     } else {
541     cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, "
542     "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size);
543     }
544     #endif
545    
546     LVG_LOCK(d);
547    
548     switch(offset) {
549 dpavlin 8 #if 0 /* TODO */
550     case 0x180:
551     if (op_type == MTS_READ)
552 dpavlin 11 *data = 0xFFFFFFFF; //0xDC004020; //1 << 31;
553 dpavlin 8 break;
554     #endif
555    
556 dpavlin 7 /* Link is Up and Full Duplex */
557     case I8254X_REG_STATUS:
558     if (op_type == MTS_READ)
559 dpavlin 8 *data = I8254X_STATUS_LU | I8254X_STATUS_FD;
560 dpavlin 7 break;
561    
562     /* Device Control Register */
563     case I8254X_REG_CTRL:
564     if (op_type == MTS_WRITE)
565     d->ctrl = *data;
566     else
567     *data = d->ctrl;
568     break;
569    
570     /* Extended Device Control Register */
571     case I8254X_REG_CTRLEXT:
572     if (op_type == MTS_WRITE) {
573     /* MDIO clock set ? */
574     if (!(d->ctrl_ext & I8254X_CTRLEXT_SDP6_DATA) &&
575     (*data & I8254X_CTRLEXT_SDP6_DATA))
576     {
577     if (*data & I8254X_CTRLEXT_SDP7_IODIR)
578     d->mii_bit = (*data & I8254X_CTRLEXT_SDP7_DATA) ? 1 : 0;
579    
580     mii_access(d);
581     }
582    
583     d->ctrl_ext = *data;
584     } else {
585     *data = d->ctrl_ext;
586    
587     if (!(d->ctrl_ext & I8254X_CTRLEXT_SDP7_IODIR)) {
588     if (d->mii_bit)
589     *data |= I8254X_CTRLEXT_SDP7_DATA;
590     else
591     *data &= ~I8254X_CTRLEXT_SDP7_DATA;
592     }
593     }
594     break;
595    
596     /* XXX */
597     case I8254X_REG_MDIC:
598     if (op_type == MTS_READ)
599     *data = 1 << 28;
600     break;
601    
602     /*
603     * Interrupt Cause Read Register.
604     *
605     * Notice: a read clears all interrupt bits.
606     */
607     case I8254X_REG_ICR:
608     if (op_type == MTS_READ) {
609     *data = d->icr;
610     d->icr = 0;
611    
612     if (d->rx_irq_cnt > 0) {
613     d->icr |= I8254X_ICR_RXT0;
614     d->rx_irq_cnt--;
615     }
616    
617     dev_i8254x_update_irq_status(d);
618     }
619     break;
620    
621     /* Interrupt Cause Set Register */
622     case I8254X_REG_ICS:
623     if (op_type == MTS_WRITE) {
624     d->icr |= *data;
625     dev_i8254x_update_irq_status(d);
626     }
627     break;
628    
629     /* Interrupt Mask Set/Read Register */
630     case I8254X_REG_IMS:
631     if (op_type == MTS_WRITE) {
632     d->imr |= *data;
633     dev_i8254x_update_irq_status(d);
634     } else {
635     *data = d->imr;
636     }
637     break;
638    
639     /* Interrupt Mask Clear Register */
640     case I8254X_REG_IMC:
641     if (op_type == MTS_WRITE) {
642     d->imr &= ~(*data);
643     dev_i8254x_update_irq_status(d);
644     }
645     break;
646    
647     /* Receive Control Register */
648     case I8254X_REG_RCTL:
649     if (op_type == MTS_READ) {
650     *data = d->rctl;
651     } else {
652     d->rctl = *data;
653     dev_i8254x_set_rx_buf_size(d);
654     }
655     break;
656    
657     /* Transmit Control Register */
658     case I8254X_REG_TCTL:
659     if (op_type == MTS_READ)
660     *data = d->tctl;
661     else
662     d->tctl = *data;
663     break;
664    
665     /* RX Descriptor Base Address Low */
666     case I8254X_REG_RDBAL:
667 dpavlin 8 case I82542_REG_RDBAL:
668 dpavlin 7 if (op_type == MTS_WRITE) {
669     d->rx_addr &= 0xFFFFFFFF00000000ULL;
670     d->rx_addr |= (m_uint32_t)(*data);
671     } else {
672     *data = (m_uint32_t)d->rx_addr;
673     }
674     break;
675    
676     /* RX Descriptor Base Address High */
677     case I8254X_REG_RDBAH:
678 dpavlin 8 case I82542_REG_RDBAH:
679 dpavlin 7 if (op_type == MTS_WRITE) {
680     d->rx_addr &= 0x00000000FFFFFFFFULL;
681     d->rx_addr |= *data << 32;
682     } else {
683     *data = d->rx_addr >> 32;
684     }
685     break;
686    
687     /* TX Descriptor Base Address Low */
688     case I8254X_REG_TDBAL:
689 dpavlin 8 case I82542_REG_TDBAL:
690 dpavlin 7 if (op_type == MTS_WRITE) {
691     d->tx_addr &= 0xFFFFFFFF00000000ULL;
692     d->tx_addr |= (m_uint32_t)(*data);
693     } else {
694     *data = (m_uint32_t)d->tx_addr;
695     }
696     break;
697    
698     /* TX Descriptor Base Address High */
699     case I8254X_REG_TDBAH:
700 dpavlin 8 case I82542_REG_TDBAH:
701 dpavlin 7 if (op_type == MTS_WRITE) {
702     d->tx_addr &= 0x00000000FFFFFFFFULL;
703     d->tx_addr |= *data << 32;
704     } else {
705     *data = d->tx_addr >> 32;
706     }
707     break;
708    
709     /* RX Descriptor Length */
710     case I8254X_REG_RDLEN:
711 dpavlin 8 case I82542_REG_RDLEN:
712 dpavlin 7 if (op_type == MTS_WRITE)
713     d->rdlen = *data & 0xFFF80;
714     else
715     *data = d->rdlen;
716     break;
717    
718     /* TX Descriptor Length */
719     case I8254X_REG_TDLEN:
720 dpavlin 8 case I82542_REG_TDLEN:
721 dpavlin 7 if (op_type == MTS_WRITE)
722     d->tdlen = *data & 0xFFF80;
723     else
724     *data = d->tdlen;
725     break;
726    
727     /* RX Descriptor Head */
728     case I82542_REG_RDH:
729     case I8254X_REG_RDH:
730     if (op_type == MTS_WRITE)
731     d->rdh = *data & 0xFFFF;
732     else
733     *data = d->rdh;
734     break;
735    
736     /* RX Descriptor Tail */
737     case I8254X_REG_RDT:
738     case I82542_REG_RDT:
739     if (op_type == MTS_WRITE)
740     d->rdt = *data & 0xFFFF;
741     else
742     *data = d->rdt;
743     break;
744    
745     /* TX Descriptor Head */
746     case I82542_REG_TDH:
747     case I8254X_REG_TDH:
748     if (op_type == MTS_WRITE)
749     d->tdh = *data & 0xFFFF;
750     else
751     *data = d->tdh;
752     break;
753    
754     /* TX Descriptor Tail */
755     case I82542_REG_TDT:
756     case I8254X_REG_TDT:
757     if (op_type == MTS_WRITE)
758     d->tdt = *data & 0xFFFF;
759     else
760     *data = d->tdt;
761     break;
762    
763 dpavlin 8 /* Flow Control Address Low */
764     case I8254X_REG_FCAL:
765     if (op_type == MTS_WRITE)
766     d->fcal = *data;
767     else
768     *data = d->fcal;
769     break;
770    
771     /* Flow Control Address High */
772     case I8254X_REG_FCAH:
773     if (op_type == MTS_WRITE)
774     d->fcah = *data & 0xFFFF;
775     else
776     *data = d->fcah;
777     break;
778    
779     /* Flow Control Type */
780     case I8254X_REG_FCT:
781     if (op_type == MTS_WRITE)
782     d->fct = *data & 0xFFFF;
783     else
784     *data = d->fct;
785     break;
786    
787     /* RX Delay Timer */
788     case I8254X_REG_RDTR:
789     case I82542_REG_RDTR:
790     if (op_type == MTS_WRITE)
791     d->rdtr = *data & 0xFFFF;
792     else
793     *data = d->rdtr;
794     break;
795    
796 dpavlin 7 #if DEBUG_UNKNOWN
797     default:
798     if (op_type == MTS_READ) {
799     cpu_log(cpu,d->name,
800     "read access to unknown offset=0x%x, "
801     "pc=0x%llx (size=%u)\n",
802     offset,cpu_get_pc(cpu),op_size);
803     } else {
804     cpu_log(cpu,d->name,
805     "write access to unknown offset=0x%x, pc=0x%llx, "
806     "val=0x%llx (size=%u)\n",
807     offset,cpu_get_pc(cpu),*data,op_size);
808     }
809     #endif
810     }
811    
812     LVG_UNLOCK(d);
813     return NULL;
814     }
815    
816     /* Read a TX descriptor */
817     static void txdesc_read(struct i8254x_data *d,m_uint64_t txd_addr,
818     struct tx_desc *txd)
819     {
820     /* Get the descriptor from VM physical RAM */
821     physmem_copy_from_vm(d->vm,txd,txd_addr,sizeof(struct tx_desc));
822    
823     /* byte-swapping */
824     txd->tdes[0] = vmtoh32(txd->tdes[0]);
825     txd->tdes[1] = vmtoh32(txd->tdes[1]);
826     txd->tdes[2] = vmtoh32(txd->tdes[2]);
827     txd->tdes[3] = vmtoh32(txd->tdes[3]);
828     }
829    
830     /* Handle the TX ring */
831     static int dev_i8254x_handle_txring(struct i8254x_data *d)
832     {
833     m_uint64_t txd_addr,buf_addr;
834     m_uint32_t buf_len,tot_len;
835     m_uint32_t norm_len,icr;
836     struct tx_desc txd;
837     m_uint8_t *pkt_ptr;
838    
839     /* Transmit Enabled ? */
840     if (!(d->tctl & I8254X_TCTL_EN))
841     return(FALSE);
842    
843     /* If Head is at same position than Tail, the ring is empty */
844     if (d->tdh == d->tdt)
845     return(FALSE);
846    
847     LVG_LOCK(d);
848 dpavlin 11
849 dpavlin 7 /* Empty packet for now */
850     pkt_ptr = d->tx_buffer;
851     tot_len = 0;
852     icr = 0;
853    
854     while(d->tdh != d->tdt) {
855     txd_addr = d->tx_addr + (d->tdh * sizeof(struct tx_desc));
856     txdesc_read(d,txd_addr,&txd);
857    
858     /* Copy the packet buffer */
859     buf_addr = ((m_uint64_t)txd.tdes[1] << 32) | txd.tdes[0];
860     buf_len = txd.tdes[2] & I8254X_TXDESC_LEN_MASK;
861    
862 dpavlin 11 //printf("COPYING DATA FROM 0x%8.8llx\n",buf_addr);
863 dpavlin 7 norm_len = normalize_size(buf_len,4,0);
864     physmem_copy_from_vm(d->vm,pkt_ptr,buf_addr,norm_len);
865     mem_bswap32(pkt_ptr,norm_len);
866    
867     pkt_ptr += buf_len;
868     tot_len += buf_len;
869    
870     /* Write the descriptor done bit if required */
871     if (txd.tdes[2] & I8254X_TXDESC_RS) {
872     txd.tdes[3] |= I8254X_TXDESC_DD;
873     icr |= I8254X_ICR_TXDW;
874     physmem_copy_u32_to_vm(d->vm,txd_addr+0x0c,txd.tdes[3]);
875     }
876    
877     /* Go to the next descriptor. Wrap ring if we are at end */
878     if (++d->tdh == (d->tdlen / sizeof(struct tx_desc)))
879     d->tdh = 0;
880    
881     /* End of packet ? */
882     if (txd.tdes[2] & I8254X_TXDESC_EOP) {
883 dpavlin 11 #if DEBUG_TRANSMIT
884     LVG_LOG(d,"sending packet of %u bytes\n",tot_len);
885     mem_dump(log_file,d->tx_buffer,tot_len);
886     #endif
887 dpavlin 7 netio_send(d->nio,d->tx_buffer,tot_len);
888     break;
889     }
890     }
891    
892     if (d->tdh == d->tdt)
893     icr |= I8254X_ICR_TXQE;
894    
895     /* Update the interrupt cause register and trigger IRQ if needed */
896     d->icr |= icr;
897     dev_i8254x_update_irq_status(d);
898     LVG_UNLOCK(d);
899     return(TRUE);
900     }
901    
902     /* Read a RX descriptor */
903     static void rxdesc_read(struct i8254x_data *d,m_uint64_t rxd_addr,
904     struct rx_desc *rxd)
905     {
906     /* Get the descriptor from VM physical RAM */
907     physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc));
908    
909     /* byte-swapping */
910     rxd->rdes[0] = vmtoh32(rxd->rdes[0]);
911     rxd->rdes[1] = vmtoh32(rxd->rdes[1]);
912     rxd->rdes[2] = vmtoh32(rxd->rdes[2]);
913     rxd->rdes[3] = vmtoh32(rxd->rdes[3]);
914     }
915    
916     /*
917     * Put a packet in the RX ring.
918     */
919     static int dev_i8254x_receive_pkt(struct i8254x_data *d,
920     u_char *pkt,ssize_t pkt_len)
921     {
922     m_uint64_t rxd_addr,buf_addr;
923     m_uint32_t cur_len,norm_len,tot_len;
924     struct rx_desc rxd;
925     m_uint32_t icr;
926     u_char *pkt_ptr;
927    
928     if (!d->rx_buf_size)
929     return(FALSE);
930    
931     LVG_LOCK(d);
932     pkt_ptr = pkt;
933     tot_len = pkt_len;
934     icr = 0;
935    
936     while(tot_len > 0) {
937     /* No descriptor available: RX overrun condition */
938     if (d->rdh == d->rdt) {
939     icr |= I8254X_ICR_RXO;
940     break;
941     }
942    
943     rxd_addr = d->rx_addr + (d->rdh * sizeof(struct rx_desc));
944     rxdesc_read(d,rxd_addr,&rxd);
945    
946     cur_len = (tot_len > d->rx_buf_size) ? d->rx_buf_size : tot_len;
947    
948     /* Copy the packet data into the RX buffer */
949     buf_addr = ((m_uint64_t)rxd.rdes[1] << 32) | rxd.rdes[0];
950    
951     norm_len = normalize_size(cur_len,4,0);
952     mem_bswap32(pkt_ptr,norm_len);
953     physmem_copy_to_vm(d->vm,pkt_ptr,buf_addr,norm_len);
954     tot_len -= cur_len;
955     pkt_ptr += cur_len;
956    
957     /* Set length field */
958     rxd.rdes[2] = cur_len;
959    
960     /* Set the status */
961     rxd.rdes[3] = I8254X_RXDESC_IXSM|I8254X_RXDESC_DD;
962    
963     if (!tot_len) {
964     rxd.rdes[3] |= I8254X_RXDESC_EOP;
965     icr |= I8254X_ICR_RXT0;
966     d->rx_irq_cnt++;
967     rxd.rdes[2] += 4; /* FCS */
968     }
969    
970     /* Write back updated descriptor */
971     physmem_copy_u32_to_vm(d->vm,rxd_addr+0x08,rxd.rdes[2]);
972     physmem_copy_u32_to_vm(d->vm,rxd_addr+0x0c,rxd.rdes[3]);
973    
974     /* Goto to the next descriptor, and wrap if necessary */
975     if (++d->rdh == (d->rdlen / sizeof(struct rx_desc)))
976     d->rdh = 0;
977     }
978    
979     /* Update the interrupt cause register and trigger IRQ if needed */
980     d->icr |= icr;
981     dev_i8254x_update_irq_status(d);
982     LVG_UNLOCK(d);
983     return(TRUE);
984     }
985    
986     /* Handle the RX ring */
987     static int dev_i8254x_handle_rxring(netio_desc_t *nio,
988     u_char *pkt,ssize_t pkt_len,
989     struct i8254x_data *d)
990     {
991     /*
992     * Don't start receive if RX has not been enabled in RCTL register.
993     */
994     if (!(d->rctl & I8254X_RCTL_EN))
995     return(FALSE);
996    
997     #if DEBUG_RECEIVE
998     LVG_LOG(d,"receiving a packet of %d bytes\n",pkt_len);
999     mem_dump(log_file,pkt,pkt_len);
1000     #endif
1001    
1002     /*
1003     * Receive only multicast/broadcast trafic + unicast traffic
1004     * for this virtual machine.
1005     */
1006     //if (dec21140_handle_mac_addr(d,pkt))
1007     return(dev_i8254x_receive_pkt(d,pkt,pkt_len));
1008    
1009     return(FALSE);
1010     }
1011    
1012     /*
1013     * pci_i8254x_read()
1014     *
1015     * Read a PCI register.
1016     */
1017     static m_uint32_t pci_i8254x_read(cpu_gen_t *cpu,struct pci_device *dev,
1018 dpavlin 11 int reg)
1019 dpavlin 7 {
1020     struct i8254x_data *d = dev->priv_data;
1021    
1022     #if DEBUG_PCI_REGS
1023     I8254X_LOG(d,"read PCI register 0x%x\n",reg);
1024     #endif
1025    
1026     switch (reg) {
1027     case 0x00:
1028     return((I8254X_PCI_PRODUCT_ID << 16) | I8254X_PCI_VENDOR_ID);
1029     case 0x08:
1030 dpavlin 8 return(0x02000003);
1031 dpavlin 7 case PCI_REG_BAR0:
1032     return(d->dev->phys_addr);
1033     default:
1034     return(0);
1035     }
1036     }
1037    
1038     /*
1039     * pci_i8254x_write()
1040     *
1041     * Write a PCI register.
1042     */
1043     static void pci_i8254x_write(cpu_gen_t *cpu,struct pci_device *dev,
1044 dpavlin 11 int reg,m_uint32_t value)
1045 dpavlin 7 {
1046     struct i8254x_data *d = dev->priv_data;
1047    
1048     #if DEBUG_PCI_REGS
1049     LVG_LOG(d,"write PCI register 0x%x, value 0x%x\n",reg,value);
1050     #endif
1051    
1052     switch(reg) {
1053     case PCI_REG_BAR0:
1054     vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
1055     LVG_LOG(d,"registers are mapped at 0x%x\n",value);
1056     break;
1057     }
1058     }
1059    
1060     /*
1061     * dev_i8254x_init()
1062     */
1063     struct i8254x_data *
1064     dev_i8254x_init(vm_instance_t *vm,char *name,int interface_type,
1065     struct pci_bus *pci_bus,int pci_device,int irq)
1066     {
1067     struct i8254x_data *d;
1068     struct pci_device *pci_dev;
1069     struct vdevice *dev;
1070    
1071     /* Allocate the private data structure for I8254X */
1072     if (!(d = malloc(sizeof(*d)))) {
1073     fprintf(stderr,"%s (i8254x): out of memory\n",name);
1074     return NULL;
1075     }
1076    
1077     memset(d,0,sizeof(*d));
1078     pthread_mutex_init(&d->lock,NULL);
1079    
1080     /* Add as PCI device */
1081     pci_dev = pci_dev_add(pci_bus,name,
1082     I8254X_PCI_VENDOR_ID,I8254X_PCI_PRODUCT_ID,
1083     pci_device,0,irq,
1084     d,NULL,pci_i8254x_read,pci_i8254x_write);
1085    
1086     if (!pci_dev) {
1087     fprintf(stderr,"%s (i8254x): unable to create PCI device.\n",name);
1088     goto err_pci_dev;
1089     }
1090    
1091     /* Create the device itself */
1092     if (!(dev = dev_create(name))) {
1093     fprintf(stderr,"%s (i8254x): unable to create device.\n",name);
1094     goto err_dev;
1095     }
1096    
1097     d->name = name;
1098     d->vm = vm;
1099     d->pci_dev = pci_dev;
1100     d->dev = dev;
1101    
1102     dev->phys_addr = 0;
1103     dev->phys_len = 0x10000;
1104     dev->handler = dev_i8254x_access;
1105     dev->priv_data = d;
1106     return(d);
1107    
1108     err_dev:
1109     pci_dev_remove(pci_dev);
1110     err_pci_dev:
1111     free(d);
1112     return NULL;
1113     }
1114    
1115     /* Remove an Intel i8254x device */
1116     void dev_i8254x_remove(struct i8254x_data *d)
1117     {
1118     if (d != NULL) {
1119     pci_dev_remove(d->pci_dev);
1120     vm_unbind_device(d->vm,d->dev);
1121     cpu_group_rebuild_mts(d->vm->cpu_group);
1122     free(d->dev);
1123     free(d);
1124     }
1125     }
1126    
1127     /* Bind a NIO to an Intel i8254x device */
1128     int dev_i8254x_set_nio(struct i8254x_data *d,netio_desc_t *nio)
1129     {
1130     /* check that a NIO is not already bound */
1131     if (d->nio != NULL)
1132     return(-1);
1133    
1134     d->nio = nio;
1135     d->tx_tid = ptask_add((ptask_callback)dev_i8254x_handle_txring,d,NULL);
1136     netio_rxl_add(nio,(netio_rx_handler_t)dev_i8254x_handle_rxring,d,NULL);
1137     return(0);
1138     }
1139    
1140     /* Unbind a NIO from an Intel i8254x device */
1141     void dev_i8254x_unset_nio(struct i8254x_data *d)
1142     {
1143     if (d->nio != NULL) {
1144     ptask_remove(d->tx_tid);
1145     netio_rxl_remove(d->nio);
1146     d->nio = NULL;
1147     }
1148     }

  ViewVC Help
Powered by ViewVC 1.1.26