VirtualBox

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

Last change on this file since 64733 was 63369, checked in by vboxsync, 8 years ago

warnings (gcc)

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