/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_i8254x.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.26