VirtualBox

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

Last change on this file since 61541 was 56292, checked in by vboxsync, 10 years ago

Devices: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1/** $Id: DevE1000Phy.cpp 56292 2015-06-09 14:20:46Z 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-2015 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.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 PhyLog(("PHY#%d At %02d read attempted from write-only '%s'\n",
162 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
163 return 0;
164}
165
166/**
167 * Write handler for read-only registers.
168 *
169 * Merely reports writes to read-only registers.
170 *
171 * @param index Register index in register array.
172 * @param value The value to store (ignored).
173 */
174static void Phy::regWriteForbidden(PPHY pPhy, uint32_t index, uint16_t u16Value)
175{
176 PhyLog(("PHY#%d At %02d write attempted to read-only '%s'\n",
177 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
178}
179
180/**
181 * Read handler for unimplemented registers.
182 *
183 * Merely reports reads from unimplemented registers.
184 *
185 * @returns Register value (always 0)
186 *
187 * @param index Register index in register array.
188 */
189static uint16_t Phy::regReadUnimplemented(PPHY pPhy, uint32_t index)
190{
191 PhyLog(("PHY#%d At %02d read attempted from unimplemented '%s'\n",
192 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
193 return 0;
194}
195
196/**
197 * Write handler for unimplemented registers.
198 *
199 * Merely reports writes to unimplemented registers.
200 *
201 * @param index Register index in register array.
202 * @param value The value to store (ignored).
203 */
204static void Phy::regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value)
205{
206 PhyLog(("PHY#%d At %02d write attempted to unimplemented '%s'\n",
207 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
208}
209
210
211/**
212 * Search PHY register table for register with matching address.
213 *
214 * @returns Index in the register table or -1 if not found.
215 *
216 * @param u32Address Register address.
217 */
218static int Phy::lookupRegister(uint32_t u32Address)
219{
220 unsigned int index;
221
222 for (index = 0; index < RT_ELEMENTS(s_regMap); index++)
223 {
224 if (s_regMap[index].u32Address == u32Address)
225 {
226 return index;
227 }
228 }
229
230 return -1;
231}
232
233/**
234 * Read PHY register.
235 *
236 * @returns Value of specified PHY register.
237 *
238 * @param u32Address Register address.
239 */
240uint16_t Phy::readRegister(PPHY pPhy, uint32_t u32Address)
241{
242 int index = Phy::lookupRegister(u32Address);
243 uint16_t u16 = 0;
244
245 if (index != -1)
246 {
247 u16 = s_regMap[index].pfnRead(pPhy, index);
248 PhyLog(("PHY#%d At %02d read %04X from %s (%s)\n",
249 pPhy->iInstance, s_regMap[index].u32Address, u16,
250 s_regMap[index].pszAbbrev, s_regMap[index].pszName));
251 }
252 else
253 {
254 PhyLog(("PHY#%d read attempted from non-existing register %08x\n",
255 pPhy->iInstance, u32Address));
256 }
257 return u16;
258}
259
260/**
261 * Write to PHY register.
262 *
263 * @param u32Address Register address.
264 * @param u16Value Value to store.
265 */
266void Phy::writeRegister(PPHY pPhy, uint32_t u32Address, uint16_t u16Value)
267{
268 int index = Phy::lookupRegister(u32Address);
269
270 if (index != -1)
271 {
272 PhyLog(("PHY#%d At %02d write %04X to %s (%s)\n",
273 pPhy->iInstance, s_regMap[index].u32Address, u16Value,
274 s_regMap[index].pszAbbrev, s_regMap[index].pszName));
275 s_regMap[index].pfnWrite(pPhy, index, u16Value);
276 }
277 else
278 {
279 PhyLog(("PHY#%d write attempted to non-existing register %08x\n",
280 pPhy->iInstance, u32Address));
281 }
282}
283
284/**
285 * PHY constructor.
286 *
287 * Stores E1000 instance internally. Triggers PHY hard reset.
288 *
289 * @param iNICInstance Number of network controller instance this PHY is
290 * attached to.
291 * @param u16EPid Extended PHY Id.
292 */
293void Phy::init(PPHY pPhy, int iNICInstance, uint16_t u16EPid)
294{
295 pPhy->iInstance = iNICInstance;
296 /* Make sure the link is down */
297 REG(PSTATUS) = 0;
298 /* The PHY identifier composed of bits 3 through 18 of the OUI */
299 /* (Organizationally Unique Identifier). OUI is 0x05043. */
300 REG(PID) = 0x0141;
301 /* Extended PHY identifier */
302 REG(EPID) = u16EPid;
303 hardReset(pPhy);
304}
305
306/**
307 * Hardware PHY reset.
308 *
309 * Sets all PHY registers to their initial values.
310 */
311void Phy::hardReset(PPHY pPhy)
312{
313 PhyLog(("PHY#%d Hard reset\n", pPhy->iInstance));
314 REG(PCTRL) = PCTRL_SPDSELM | PCTRL_DUPMOD | PCTRL_ANEG;
315 /*
316 * 100 and 10 FD/HD, MF Preamble Suppression, Auto-Negotiation Complete,
317 * AUTO NEG AB, EXT CAP
318 */
319 REG(PSTATUS) = (REG(PSTATUS) & ~PSTATUS_LNKSTAT) | 0x7969;
320 REG(ANA) = 0x01E1;
321 /* No flow control by our link partner, all speeds */
322 REG(LPA) = 0x01E0;
323 REG(ANE) = 0x0000;
324 REG(NPT) = 0x2001;
325 REG(LPN) = 0x0000;
326 REG(GCON) = 0x1E00;
327 REG(GSTATUS) = 0x0000;
328 REG(EPSTATUS) = 0x3000;
329 REG(PSCON) = 0x0068;
330 REG(PSSTAT) = 0x0000;
331 REG(PINTE) = 0x0000;
332 REG(PINTS) = 0x0000;
333 REG(EPSCON1) = 0x0D60;
334 REG(PREC) = 0x0000;
335 REG(EPSCON2) = 0x000C;
336 REG(R30PS) = 0x0000;
337 REG(R30AW) = 0x0000;
338
339 pPhy->u16State = MDIO_IDLE;
340}
341
342/**
343 * Software PHY reset.
344 */
345static void Phy::softReset(PPHY pPhy)
346{
347 PhyLog(("PHY#%d Soft reset is not yet implemented!\n", pPhy->iInstance));
348}
349
350/**
351 * Get the current state of the link.
352 *
353 * @returns true if link is up.
354 */
355bool Phy::isLinkUp(PPHY pPhy)
356{
357 return (REG(PSSTAT) & PSSTAT_LINK) != 0;
358}
359
360/**
361 * Set the current state of the link.
362 *
363 * @remarks Link Status bit in PHY Status register is latched-low and does
364 * not change the state when the link goes up.
365 *
366 * @param fLinkIsUp New state of the link.
367 */
368void Phy::setLinkStatus(PPHY pPhy, bool fLinkIsUp)
369{
370 if (fLinkIsUp)
371 REG(PSSTAT) |= PSSTAT_LINK;
372 else
373 {
374 REG(PSSTAT) &= ~PSSTAT_LINK;
375 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
376 }
377}
378
379#ifdef IN_RING3
380
381/**
382 * Save PHY state.
383 *
384 * @remarks Since PHY is aggregated into E1K it does not currently supports
385 * versioning of its own.
386 *
387 * @returns VBox status code.
388 * @param pSSMHandle The handle to save the state to.
389 * @param pPhy The pointer to this instance.
390 */
391int Phy::saveState(PSSMHANDLE pSSMHandle, PPHY pPhy)
392{
393 SSMR3PutMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
394 return VINF_SUCCESS;
395}
396
397/**
398 * Restore previously saved PHY state.
399 *
400 * @remarks Since PHY is aggregated into E1K it does not currently supports
401 * versioning of its own.
402 *
403 * @returns VBox status code.
404 * @param pSSMHandle The handle to save the state to.
405 * @param pPhy The pointer to this instance.
406 */
407int Phy::loadState(PSSMHANDLE pSSMHandle, PPHY pPhy)
408{
409 return SSMR3GetMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
410}
411
412#endif /* IN_RING3 */
413
414/* Register-specific handlers ************************************************/
415
416/**
417 * Write handler for PHY Control register.
418 *
419 * Handles reset.
420 *
421 * @param index Register index in register array.
422 * @param value The value to store (ignored).
423 */
424static void Phy::regWritePCTRL(PPHY pPhy, uint32_t index, uint16_t u16Value)
425{
426 if (u16Value & PCTRL_RESET)
427 softReset(pPhy);
428 else
429 regWriteDefault(pPhy, index, u16Value);
430}
431
432/**
433 * Read handler for PHY Status register.
434 *
435 * Handles Latched-Low Link Status bit.
436 *
437 * @returns Register value
438 *
439 * @param index Register index in register array.
440 */
441static uint16_t Phy::regReadPSTATUS(PPHY pPhy, uint32_t index)
442{
443 /* Read latched value */
444 uint16_t u16 = REG(PSTATUS);
445 if (REG(PSSTAT) & PSSTAT_LINK)
446 REG(PSTATUS) |= PSTATUS_LNKSTAT;
447 else
448 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
449 return u16;
450}
451
452/**
453 * Read handler for 1000BASE-T Status register.
454 *
455 * @returns Register value
456 *
457 * @param index Register index in register array.
458 */
459static uint16_t Phy::regReadGSTATUS(PPHY pPhy, uint32_t index)
460{
461 /*
462 * - Link partner is capable of 1000BASE-T half duplex
463 * - Link partner is capable of 1000BASE-T full duplex
464 * - Remote receiver OK
465 * - Local receiver OK
466 * - Local PHY config resolved to SLAVE
467 */
468 return 0x3C00;
469}
470
471static const char * Phy::getStateName(uint16_t u16State)
472{
473 static const char *pcszState[] =
474 {
475 "MDIO_IDLE",
476 "MDIO_ST",
477 "MDIO_OP_ADR",
478 "MDIO_TA_RD",
479 "MDIO_TA_WR",
480 "MDIO_READ",
481 "MDIO_WRITE"
482 };
483
484 return (u16State < RT_ELEMENTS(pcszState)) ? pcszState[u16State] : "<invalid>";
485}
486
487bool Phy::readMDIO(PPHY pPhy)
488{
489 bool fPin = false;
490
491 switch (pPhy->u16State)
492 {
493 case MDIO_TA_RD:
494 Assert(pPhy->u16Cnt == 1);
495 fPin = false;
496 pPhy->u16State = MDIO_READ;
497 pPhy->u16Cnt = 16;
498 break;
499 case MDIO_READ:
500 /* Bits are shifted out in MSB to LSB order */
501 fPin = (pPhy->u16Acc & 0x8000) != 0;
502 pPhy->u16Acc <<= 1;
503 if (--pPhy->u16Cnt == 0)
504 pPhy->u16State = MDIO_IDLE;
505 break;
506 default:
507 PhyLog(("PHY#%d WARNING! MDIO pin read in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
508 pPhy->u16State = MDIO_IDLE;
509 }
510 return fPin;
511}
512
513/** Set the value of MDIO pin. */
514void Phy::writeMDIO(PPHY pPhy, bool fPin)
515{
516 switch (pPhy->u16State)
517 {
518 case MDIO_IDLE:
519 if (!fPin)
520 pPhy->u16State = MDIO_ST;
521 break;
522 case MDIO_ST:
523 if (fPin)
524 {
525 pPhy->u16State = MDIO_OP_ADR;
526 pPhy->u16Cnt = 12; /* OP + PHYADR + REGADR */
527 pPhy->u16Acc = 0;
528 }
529 break;
530 case MDIO_OP_ADR:
531 Assert(pPhy->u16Cnt);
532 /* Shift in 'u16Cnt' bits into accumulator */
533 pPhy->u16Acc <<= 1;
534 if (fPin)
535 pPhy->u16Acc |= 1;
536 if (--pPhy->u16Cnt == 0)
537 {
538 /* Got OP(2) + PHYADR(5) + REGADR(5) */
539 /* Note: A single PHY is supported, ignore PHYADR */
540 switch (pPhy->u16Acc >> 10)
541 {
542 case MDIO_READ_OP:
543 pPhy->u16Acc = readRegister(pPhy, pPhy->u16Acc & 0x1F);
544 pPhy->u16State = MDIO_TA_RD;
545 pPhy->u16Cnt = 1;
546 break;
547 case MDIO_WRITE_OP:
548 pPhy->u16RegAdr = pPhy->u16Acc & 0x1F;
549 pPhy->u16State = MDIO_TA_WR;
550 pPhy->u16Cnt = 2;
551 break;
552 default:
553 PhyLog(("PHY#%d ERROR! Invalid MDIO op: %d\n", pPhy->iInstance, pPhy->u16Acc >> 10));
554 pPhy->u16State = MDIO_IDLE;
555 break;
556 }
557 }
558 break;
559 case MDIO_TA_WR:
560 Assert(pPhy->u16Cnt <= 2);
561 Assert(pPhy->u16Cnt > 0);
562 if (--pPhy->u16Cnt == 0)
563 {
564 pPhy->u16State = MDIO_WRITE;
565 pPhy->u16Cnt = 16;
566 }
567 break;
568 case MDIO_WRITE:
569 Assert(pPhy->u16Cnt);
570 pPhy->u16Acc <<= 1;
571 if (fPin)
572 pPhy->u16Acc |= 1;
573 if (--pPhy->u16Cnt == 0)
574 {
575 writeRegister(pPhy, pPhy->u16RegAdr, pPhy->u16Acc);
576 pPhy->u16State = MDIO_IDLE;
577 }
578 break;
579 default:
580 PhyLog(("PHY#%d ERROR! MDIO pin write in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
581 pPhy->u16State = MDIO_IDLE;
582 break;
583 }
584}
585
Note: See TracBrowser for help on using the repository browser.

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