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

Contents of /trunk/dev_i8254x.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show 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 /*
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 /* 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 /* Flow Control registers */
285 m_uint32_t fcal,fcah,fct;
286
287 /* RX Delay Timer */
288 m_uint32_t rdtr;
289
290 /* 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 return(0x0001);
358 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 else
479 pci_dev_clear_irq(d->vm,d->pci_dev);
480 }
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 #if 0 /* TODO */
550 case 0x180:
551 if (op_type == MTS_READ)
552 *data = 0xFFFFFFFF; //0xDC004020; //1 << 31;
553 break;
554 #endif
555
556 /* Link is Up and Full Duplex */
557 case I8254X_REG_STATUS:
558 if (op_type == MTS_READ)
559 *data = I8254X_STATUS_LU | I8254X_STATUS_FD;
560 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 case I82542_REG_RDBAL:
668 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 case I82542_REG_RDBAH:
679 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 case I82542_REG_TDBAL:
690 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 case I82542_REG_TDBAH:
701 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 case I82542_REG_RDLEN:
712 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 case I82542_REG_TDLEN:
721 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 /* 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 #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
849 /* 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 //printf("COPYING DATA FROM 0x%8.8llx\n",buf_addr);
863 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 #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 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 int reg)
1019 {
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 return(0x02000003);
1031 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 int reg,m_uint32_t value)
1045 {
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