VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevE1000Phy.cpp@ 62956

最後變更 在這個檔案從62956是 62632,由 vboxsync 提交於 9 年 前

Devices: unused parameter warnings.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 18.3 KB
 
1/** $Id: DevE1000Phy.cpp 62632 2016-07-28 15:58:14Z vboxsync $ */
2/** @file
3 * DevE1000Phy - Intel 82540EM Ethernet Controller Internal PHY Emulation.
4 *
5 * Implemented in accordance with the specification:
6 * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer�s Manual
7 * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
8 *
9 * 317453-002 Revision 3.5
10 */
11
12/*
13 * Copyright (C) 2007-2016 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.alldomusa.eu.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 */
23
24#define LOG_GROUP LOG_GROUP_DEV_E1000
25
26/** @todo Remove me! For now I want asserts to work in release code. */
27// #ifndef RT_STRICT
28// #define RT_STRICT
29#include <iprt/assert.h>
30// #undef RT_STRICT
31// #endif
32
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <VBox/vmm/ssm.h>
36#include "DevE1000Phy.h"
37
38/* Little helpers ************************************************************/
39#ifdef PHY_UNIT_TEST
40# define SSMR3PutMem(a,b,c)
41# define SSMR3GetMem(a,b,c)
42# include <stdio.h>
43# define PhyLog(a) printf a
44#else /* PHY_UNIT_TEST */
45# define PhyLog(a) Log(a)
46#endif /* PHY_UNIT_TEST */
47
48#define REG(x) pPhy->au16Regs[x##_IDX]
49
50
51/* Internals */
52namespace Phy {
53 /** Retrieves state name by id */
54 static const char * getStateName(uint16_t u16State);
55 /** Look up register index by address. */
56 static int lookupRegister(uint32_t u32Address);
57 /** Software-triggered reset. */
58 static void softReset(PPHY pPhy);
59
60 /** @name Generic handlers
61 * @{ */
62 static uint16_t regReadDefault (PPHY pPhy, uint32_t index);
63 static void regWriteDefault (PPHY pPhy, uint32_t index, uint16_t u16Value);
64 static uint16_t regReadForbidden (PPHY pPhy, uint32_t index);
65 static void regWriteForbidden (PPHY pPhy, uint32_t index, uint16_t u16Value);
66 static uint16_t regReadUnimplemented (PPHY pPhy, uint32_t index);
67 static void regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value);
68 /** @} */
69 /** @name Register-specific handlers
70 * @{ */
71 static void regWritePCTRL (PPHY pPhy, uint32_t index, uint16_t u16Value);
72 static uint16_t regReadPSTATUS (PPHY pPhy, uint32_t index);
73 static uint16_t regReadGSTATUS (PPHY pPhy, uint32_t index);
74 /** @} */
75
76 /**
77 * PHY register map table.
78 *
79 * Override pfnRead and pfnWrite to implement register-specific behavior.
80 */
81 static struct RegMap_st
82 {
83 /** PHY register address. */
84 uint32_t u32Address;
85 /** Read callback. */
86 uint16_t (*pfnRead)(PPHY pPhy, uint32_t index);
87 /** Write callback. */
88 void (*pfnWrite)(PPHY pPhy, uint32_t index, uint16_t u16Value);
89 /** Abbreviated name. */
90 const char *pszAbbrev;
91 /** Full name. */
92 const char *pszName;
93 } s_regMap[NUM_OF_PHY_REGS] =
94 {
95 /*ra read callback write callback abbrev full name */
96 /*-- ------------------------- -------------------------- ---------- ------------------------------*/
97 { 0, Phy::regReadDefault , Phy::regWritePCTRL , "PCTRL" , "PHY Control" },
98 { 1, Phy::regReadPSTATUS , Phy::regWriteForbidden , "PSTATUS" , "PHY Status" },
99 { 2, Phy::regReadDefault , Phy::regWriteForbidden , "PID" , "PHY Identifier" },
100 { 3, Phy::regReadDefault , Phy::regWriteForbidden , "EPID" , "Extended PHY Identifier" },
101 { 4, Phy::regReadDefault , Phy::regWriteDefault , "ANA" , "Auto-Negotiation Advertisement" },
102 { 5, Phy::regReadDefault , Phy::regWriteForbidden , "LPA" , "Link Partner Ability" },
103 { 6, Phy::regReadUnimplemented, Phy::regWriteForbidden , "ANE" , "Auto-Negotiation Expansion" },
104 { 7, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "NPT" , "Next Page Transmit" },
105 { 8, Phy::regReadUnimplemented, Phy::regWriteForbidden , "LPN" , "Link Partner Next Page" },
106 { 9, Phy::regReadDefault , Phy::regWriteUnimplemented, "GCON" , "1000BASE-T Control" },
107 { 10, Phy::regReadGSTATUS , Phy::regWriteForbidden , "GSTATUS" , "1000BASE-T Status" },
108 { 15, Phy::regReadUnimplemented, Phy::regWriteForbidden , "EPSTATUS" , "Extended PHY Status" },
109 { 16, Phy::regReadDefault , Phy::regWriteDefault , "PSCON" , "PHY Specific Control" },
110 { 17, Phy::regReadDefault , Phy::regWriteForbidden , "PSSTAT" , "PHY Specific Status" },
111 { 18, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "PINTE" , "PHY Interrupt Enable" },
112 { 19, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PINTS" , "PHY Interrupt Status" },
113 { 20, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON1" , "Extended PHY Specific Control 1" },
114 { 21, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PREC" , "PHY Receive Error Counter" },
115 { 26, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON2" , "Extended PHY Specific Control 2" },
116 { 29, Phy::regReadForbidden , Phy::regWriteUnimplemented, "R30PS" , "MDI Register 30 Page Select" },
117 { 30, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "R30AW" , "MDI Register 30 Access Window" }
118 };
119}
120
121/**
122 * Default read handler.
123 *
124 * Fetches register value from the state structure.
125 *
126 * @returns Register value
127 *
128 * @param index Register index in register array.
129 */
130static uint16_t Phy::regReadDefault(PPHY pPhy, uint32_t index)
131{
132 AssertReturn(index<Phy::NUM_OF_PHY_REGS, 0);
133 return pPhy->au16Regs[index];
134}
135
136/**
137 * Default write handler.
138 *
139 * Writes the specified register value to the state structure.
140 *
141 * @param index Register index in register array.
142 * @param value The value to store (ignored).
143 */
144static void Phy::regWriteDefault(PPHY pPhy, uint32_t index, uint16_t u16Value)
145{
146 AssertReturnVoid(index<NUM_OF_PHY_REGS);
147 pPhy->au16Regs[index] = u16Value;
148}
149
150/**
151 * Read handler for write-only registers.
152 *
153 * Merely reports reads from write-only registers.
154 *
155 * @returns Register value (always 0)
156 *
157 * @param index Register index in register array.
158 */
159static uint16_t Phy::regReadForbidden(PPHY pPhy, uint32_t index)
160{
161 RT_NOREF2(pPhy, index);
162 PhyLog(("PHY#%d At %02d read attempted from write-only '%s'\n",
163 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
164 return 0;
165}
166
167/**
168 * Write handler for read-only registers.
169 *
170 * Merely reports writes to read-only registers.
171 *
172 * @param index Register index in register array.
173 * @param value The value to store (ignored).
174 */
175static void Phy::regWriteForbidden(PPHY pPhy, uint32_t index, uint16_t u16Value)
176{
177 RT_NOREF_PV(pPhy); RT_NOREF_PV(index); RT_NOREF_PV(u16Value);
178 PhyLog(("PHY#%d At %02d write attempted to read-only '%s'\n",
179 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
180}
181
182/**
183 * Read handler for unimplemented registers.
184 *
185 * Merely reports reads from unimplemented registers.
186 *
187 * @returns Register value (always 0)
188 *
189 * @param index Register index in register array.
190 */
191static uint16_t Phy::regReadUnimplemented(PPHY pPhy, uint32_t index)
192{
193 RT_NOREF_PV(pPhy); RT_NOREF_PV(index);
194 PhyLog(("PHY#%d At %02d read attempted from unimplemented '%s'\n",
195 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
196 return 0;
197}
198
199/**
200 * Write handler for unimplemented registers.
201 *
202 * Merely reports writes to unimplemented registers.
203 *
204 * @param index Register index in register array.
205 * @param value The value to store (ignored).
206 */
207static void Phy::regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value)
208{
209 RT_NOREF_PV(pPhy); RT_NOREF_PV(index); RT_NOREF_PV(u16Value);
210 PhyLog(("PHY#%d At %02d write attempted to unimplemented '%s'\n",
211 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
212}
213
214
215/**
216 * Search PHY register table for register with matching address.
217 *
218 * @returns Index in the register table or -1 if not found.
219 *
220 * @param u32Address Register address.
221 */
222static int Phy::lookupRegister(uint32_t u32Address)
223{
224 unsigned int index;
225
226 for (index = 0; index < RT_ELEMENTS(s_regMap); index++)
227 {
228 if (s_regMap[index].u32Address == u32Address)
229 {
230 return index;
231 }
232 }
233
234 return -1;
235}
236
237/**
238 * Read PHY register.
239 *
240 * @returns Value of specified PHY register.
241 *
242 * @param u32Address Register address.
243 */
244uint16_t Phy::readRegister(PPHY pPhy, uint32_t u32Address)
245{
246 int index = Phy::lookupRegister(u32Address);
247 uint16_t u16 = 0;
248
249 if (index != -1)
250 {
251 u16 = s_regMap[index].pfnRead(pPhy, index);
252 PhyLog(("PHY#%d At %02d read %04X from %s (%s)\n",
253 pPhy->iInstance, s_regMap[index].u32Address, u16,
254 s_regMap[index].pszAbbrev, s_regMap[index].pszName));
255 }
256 else
257 {
258 PhyLog(("PHY#%d read attempted from non-existing register %08x\n",
259 pPhy->iInstance, u32Address));
260 }
261 return u16;
262}
263
264/**
265 * Write to PHY register.
266 *
267 * @param u32Address Register address.
268 * @param u16Value Value to store.
269 */
270void Phy::writeRegister(PPHY pPhy, uint32_t u32Address, uint16_t u16Value)
271{
272 int index = Phy::lookupRegister(u32Address);
273
274 if (index != -1)
275 {
276 PhyLog(("PHY#%d At %02d write %04X to %s (%s)\n",
277 pPhy->iInstance, s_regMap[index].u32Address, u16Value,
278 s_regMap[index].pszAbbrev, s_regMap[index].pszName));
279 s_regMap[index].pfnWrite(pPhy, index, u16Value);
280 }
281 else
282 {
283 PhyLog(("PHY#%d write attempted to non-existing register %08x\n",
284 pPhy->iInstance, u32Address));
285 }
286}
287
288/**
289 * PHY constructor.
290 *
291 * Stores E1000 instance internally. Triggers PHY hard reset.
292 *
293 * @param iNICInstance Number of network controller instance this PHY is
294 * attached to.
295 * @param u16EPid Extended PHY Id.
296 */
297void Phy::init(PPHY pPhy, int iNICInstance, uint16_t u16EPid)
298{
299 pPhy->iInstance = iNICInstance;
300 /* Make sure the link is down */
301 REG(PSTATUS) = 0;
302 /* The PHY identifier composed of bits 3 through 18 of the OUI */
303 /* (Organizationally Unique Identifier). OUI is 0x05043. */
304 REG(PID) = 0x0141;
305 /* Extended PHY identifier */
306 REG(EPID) = u16EPid;
307 hardReset(pPhy);
308}
309
310/**
311 * Hardware PHY reset.
312 *
313 * Sets all PHY registers to their initial values.
314 */
315void Phy::hardReset(PPHY pPhy)
316{
317 PhyLog(("PHY#%d Hard reset\n", pPhy->iInstance));
318 REG(PCTRL) = PCTRL_SPDSELM | PCTRL_DUPMOD | PCTRL_ANEG;
319 /*
320 * 100 and 10 FD/HD, MF Preamble Suppression, Auto-Negotiation Complete,
321 * AUTO NEG AB, EXT CAP
322 */
323 REG(PSTATUS) = (REG(PSTATUS) & ~PSTATUS_LNKSTAT) | 0x7969;
324 REG(ANA) = 0x01E1;
325 /* No flow control by our link partner, all speeds */
326 REG(LPA) = 0x01E0;
327 REG(ANE) = 0x0000;
328 REG(NPT) = 0x2001;
329 REG(LPN) = 0x0000;
330 REG(GCON) = 0x1E00;
331 REG(GSTATUS) = 0x0000;
332 REG(EPSTATUS) = 0x3000;
333 REG(PSCON) = 0x0068;
334 REG(PSSTAT) = 0x0000;
335 REG(PINTE) = 0x0000;
336 REG(PINTS) = 0x0000;
337 REG(EPSCON1) = 0x0D60;
338 REG(PREC) = 0x0000;
339 REG(EPSCON2) = 0x000C;
340 REG(R30PS) = 0x0000;
341 REG(R30AW) = 0x0000;
342
343 pPhy->u16State = MDIO_IDLE;
344}
345
346/**
347 * Software PHY reset.
348 */
349static void Phy::softReset(PPHY pPhy)
350{
351 RT_NOREF1(pPhy);
352 PhyLog(("PHY#%d Soft reset is not yet implemented!\n", pPhy->iInstance));
353}
354
355/**
356 * Get the current state of the link.
357 *
358 * @returns true if link is up.
359 */
360bool Phy::isLinkUp(PPHY pPhy)
361{
362 return (REG(PSSTAT) & PSSTAT_LINK) != 0;
363}
364
365/**
366 * Set the current state of the link.
367 *
368 * @remarks Link Status bit in PHY Status register is latched-low and does
369 * not change the state when the link goes up.
370 *
371 * @param fLinkIsUp New state of the link.
372 */
373void Phy::setLinkStatus(PPHY pPhy, bool fLinkIsUp)
374{
375 if (fLinkIsUp)
376 REG(PSSTAT) |= PSSTAT_LINK;
377 else
378 {
379 REG(PSSTAT) &= ~PSSTAT_LINK;
380 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
381 }
382}
383
384#ifdef IN_RING3
385
386/**
387 * Save PHY state.
388 *
389 * @remarks Since PHY is aggregated into E1K it does not currently supports
390 * versioning of its own.
391 *
392 * @returns VBox status code.
393 * @param pSSMHandle The handle to save the state to.
394 * @param pPhy The pointer to this instance.
395 */
396int Phy::saveState(PSSMHANDLE pSSMHandle, PPHY pPhy)
397{
398 SSMR3PutMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
399 return VINF_SUCCESS;
400}
401
402/**
403 * Restore previously saved PHY state.
404 *
405 * @remarks Since PHY is aggregated into E1K it does not currently supports
406 * versioning of its own.
407 *
408 * @returns VBox status code.
409 * @param pSSMHandle The handle to save the state to.
410 * @param pPhy The pointer to this instance.
411 */
412int Phy::loadState(PSSMHANDLE pSSMHandle, PPHY pPhy)
413{
414 return SSMR3GetMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
415}
416
417#endif /* IN_RING3 */
418
419/* Register-specific handlers ************************************************/
420
421/**
422 * Write handler for PHY Control register.
423 *
424 * Handles reset.
425 *
426 * @param index Register index in register array.
427 * @param value The value to store (ignored).
428 */
429static void Phy::regWritePCTRL(PPHY pPhy, uint32_t index, uint16_t u16Value)
430{
431 if (u16Value & PCTRL_RESET)
432 softReset(pPhy);
433 else
434 regWriteDefault(pPhy, index, u16Value);
435}
436
437/**
438 * Read handler for PHY Status register.
439 *
440 * Handles Latched-Low Link Status bit.
441 *
442 * @returns Register value
443 *
444 * @param index Register index in register array.
445 */
446static uint16_t Phy::regReadPSTATUS(PPHY pPhy, uint32_t index)
447{
448 RT_NOREF_PV(pPhy); RT_NOREF_PV(index);
449
450 /* Read latched value */
451 uint16_t u16 = REG(PSTATUS);
452 if (REG(PSSTAT) & PSSTAT_LINK)
453 REG(PSTATUS) |= PSTATUS_LNKSTAT;
454 else
455 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
456 return u16;
457}
458
459/**
460 * Read handler for 1000BASE-T Status register.
461 *
462 * @returns Register value
463 *
464 * @param index Register index in register array.
465 */
466static uint16_t Phy::regReadGSTATUS(PPHY pPhy, uint32_t index)
467{
468 RT_NOREF_PV(pPhy); RT_NOREF_PV(index);
469
470 /*
471 * - Link partner is capable of 1000BASE-T half duplex
472 * - Link partner is capable of 1000BASE-T full duplex
473 * - Remote receiver OK
474 * - Local receiver OK
475 * - Local PHY config resolved to SLAVE
476 */
477 return 0x3C00;
478}
479
480static const char * Phy::getStateName(uint16_t u16State)
481{
482 static const char *pcszState[] =
483 {
484 "MDIO_IDLE",
485 "MDIO_ST",
486 "MDIO_OP_ADR",
487 "MDIO_TA_RD",
488 "MDIO_TA_WR",
489 "MDIO_READ",
490 "MDIO_WRITE"
491 };
492
493 return (u16State < RT_ELEMENTS(pcszState)) ? pcszState[u16State] : "<invalid>";
494}
495
496bool Phy::readMDIO(PPHY pPhy)
497{
498 bool fPin = false;
499
500 switch (pPhy->u16State)
501 {
502 case MDIO_TA_RD:
503 Assert(pPhy->u16Cnt == 1);
504 fPin = false;
505 pPhy->u16State = MDIO_READ;
506 pPhy->u16Cnt = 16;
507 break;
508 case MDIO_READ:
509 /* Bits are shifted out in MSB to LSB order */
510 fPin = (pPhy->u16Acc & 0x8000) != 0;
511 pPhy->u16Acc <<= 1;
512 if (--pPhy->u16Cnt == 0)
513 pPhy->u16State = MDIO_IDLE;
514 break;
515 default:
516 PhyLog(("PHY#%d WARNING! MDIO pin read in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
517 pPhy->u16State = MDIO_IDLE;
518 }
519 return fPin;
520}
521
522/** Set the value of MDIO pin. */
523void Phy::writeMDIO(PPHY pPhy, bool fPin)
524{
525 switch (pPhy->u16State)
526 {
527 case MDIO_IDLE:
528 if (!fPin)
529 pPhy->u16State = MDIO_ST;
530 break;
531 case MDIO_ST:
532 if (fPin)
533 {
534 pPhy->u16State = MDIO_OP_ADR;
535 pPhy->u16Cnt = 12; /* OP + PHYADR + REGADR */
536 pPhy->u16Acc = 0;
537 }
538 break;
539 case MDIO_OP_ADR:
540 Assert(pPhy->u16Cnt);
541 /* Shift in 'u16Cnt' bits into accumulator */
542 pPhy->u16Acc <<= 1;
543 if (fPin)
544 pPhy->u16Acc |= 1;
545 if (--pPhy->u16Cnt == 0)
546 {
547 /* Got OP(2) + PHYADR(5) + REGADR(5) */
548 /* Note: A single PHY is supported, ignore PHYADR */
549 switch (pPhy->u16Acc >> 10)
550 {
551 case MDIO_READ_OP:
552 pPhy->u16Acc = readRegister(pPhy, pPhy->u16Acc & 0x1F);
553 pPhy->u16State = MDIO_TA_RD;
554 pPhy->u16Cnt = 1;
555 break;
556 case MDIO_WRITE_OP:
557 pPhy->u16RegAdr = pPhy->u16Acc & 0x1F;
558 pPhy->u16State = MDIO_TA_WR;
559 pPhy->u16Cnt = 2;
560 break;
561 default:
562 PhyLog(("PHY#%d ERROR! Invalid MDIO op: %d\n", pPhy->iInstance, pPhy->u16Acc >> 10));
563 pPhy->u16State = MDIO_IDLE;
564 break;
565 }
566 }
567 break;
568 case MDIO_TA_WR:
569 Assert(pPhy->u16Cnt <= 2);
570 Assert(pPhy->u16Cnt > 0);
571 if (--pPhy->u16Cnt == 0)
572 {
573 pPhy->u16State = MDIO_WRITE;
574 pPhy->u16Cnt = 16;
575 }
576 break;
577 case MDIO_WRITE:
578 Assert(pPhy->u16Cnt);
579 pPhy->u16Acc <<= 1;
580 if (fPin)
581 pPhy->u16Acc |= 1;
582 if (--pPhy->u16Cnt == 0)
583 {
584 writeRegister(pPhy, pPhy->u16RegAdr, pPhy->u16Acc);
585 pPhy->u16State = MDIO_IDLE;
586 }
587 break;
588 default:
589 PhyLog(("PHY#%d ERROR! MDIO pin write in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
590 pPhy->u16State = MDIO_IDLE;
591 break;
592 }
593}
594
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette