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

Contents of /upstream/dynamips-0.2.7-RC2/dev_i8254x.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Sat Oct 6 16:24:54 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 34676 byte(s)
dynamips-0.2.7-RC2

1 /*
2 * Cisco router simulation platform.
3 * Copyright (C) 2007 Christophe Fillot. All rights reserved.
4 *
5 * Intel i8254x (Wiseman/Livengood) Ethernet 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 0
31 #define DEBUG_TRANSMIT 0
32 #define DEBUG_RECEIVE 0
33 #define DEBUG_UNKNOWN 0
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 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 /* 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
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 /* Flow Control registers */
287 m_uint32_t fcal,fcah,fct;
288
289 /* RX Delay Timer */
290 m_uint32_t rdtr;
291
292 /* 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 return(0x0001);
360 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 else
481 pci_dev_clear_irq(d->vm,d->pci_dev);
482 }
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 #if 0 /* TODO */
552 case 0x180:
553 if (op_type == MTS_READ)
554 *data = 0xDC004020; //1 << 31;
555 break;
556 #endif
557
558 /* Link is Up and Full Duplex */
559 case I8254X_REG_STATUS:
560 if (op_type == MTS_READ)
561 *data = I8254X_STATUS_LU | I8254X_STATUS_FD;
562 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 case I82542_REG_RDBAL:
670 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 case I82542_REG_RDBAH:
681 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 case I82542_REG_TDBAL:
692 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 case I82542_REG_TDBAH:
703 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 case I82542_REG_RDLEN:
714 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 case I82542_REG_TDLEN:
723 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 /* 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 #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 return(0x02000003);
1028 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