diff --git a/CMakeLists.txt b/CMakeLists.txt index 3296fb449..ef1af6b70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,10 @@ FetchContent_MakeAvailable ( Corrosion ) corrosion_import_crate ( MANIFEST_PATH "${CMAKE_SOURCE_DIR}/rust/dynamips/Cargo.toml" PROFILE release-with-debug ) corrosion_experimental_cbindgen( MANIFEST_PATH "${CMAKE_SOURCE_DIR}/rust/dynamips/Cargo.toml" TARGET rust-dynamips HEADER_NAME "rust-dynamips.h" ) list ( APPEND DYNAMIPS_LIBRARIES rust-dynamips ) +add_custom_target ( cargo_fmt COMMAND cargo fmt -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_clippy COMMAND cargo clippy -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_doc COMMAND cargo doc -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_test COMMAND cargo test -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) add_subdirectory ( man ) add_subdirectory ( common ) diff --git a/common/dev_lxt970a.c b/common/dev_lxt970a.c deleted file mode 100644 index 706137650..000000000 --- a/common/dev_lxt970a.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 10/100 Mbps Ethernet PHY. - * - * Based on: - * Intel® LXT970A - * Dual-Speed Fast Ethernet Transceiver - * Order Number: 249099-001 - * January 2001 - * Based on: - * IEEE Std 802.3-2008, Section 2 - */ - -#include "dev_lxt970a.h" - diff --git a/common/dev_lxt970a.h b/common/dev_lxt970a.h deleted file mode 100644 index 71f96c5a5..000000000 --- a/common/dev_lxt970a.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 10/100 Mbps Ethernet PHY. - * - * Based on: - * Intel® LXT970A - * Dual-Speed Fast Ethernet Transceiver - * Order Number: 249099-001 - * January 2001 - * Based on: - * IEEE Std 802.3-2008, Section 2 - */ - -#ifndef __DEV_LXT970A_H__ -#define __DEV_LXT970A_H__ - -/* -Abreviations: - RW=x - Read/Write with default value x - RO=x - Read Only with default value x - [xx] - default value determined by pins xx - SC - Self Clearing - LH - Latching High (remains High until read, and then returns to Low) - LL - Latching Low (remains Low until read, and then returns to High) - IGN - IGNored on certain conditions - RTOR - Related To Other Register - -Pin states used for the default values: - MF0 = VMF2 or VMF3 (Enabled) - MF1 = VMF1 or VMF4 (Disabled) - MF2 = VMF2 or VMF3 (Enabled) - MF3 = VMF2 or VMF3 (Enabled) - MF4 = VMF2 or VMF3 (Enabled) - CFG0 = High - CFG1 = High - TRSTE = Low - FDE = High - MDDIS = Low, RESET = High, PWERDWN = Low (2.4.1.2, MDIO Control) -*/ - -/* -Standard MII Registers -*/ - -#define LX970A_CR 0x00 /* Table 45. Control Register (Address 0) */ -#define LX970A_CR_RESET 0x8000 /* Reset (RW=0,SC) */ -#define LX970A_CR_LOOP 0x4000 /* Loopback (RW=0) */ -#define LX970A_CR_SPEEDSELECT 0x2000 /* Speed Selection (RW=1[CFG0],IGN) */ -#define LX970A_CR_ANENABLE 0x1000 /* Auto-Negotiation Enable (RW=1[MF0]) */ -#define LX970A_CR_POWERDOWN 0x0800 /* Power Down (RW=0?) */ -#define LX970A_CR_ISOLATE 0x0400 /* Isolate (RW=0[TRSTE]) */ -#define LX970A_CR_ANRESTART 0x0200 /* Restart Auto-Negotiation (RW=1[CFG0],SC) */ -#define LX970A_CR_DUPLEXMODE 0x0100 /* Duplex Mode (RW=1[FDE],IGN) */ -#define LX970A_CR_COLLISIONTEST 0x0080 /* Collision Test (RW=0,IGN) */ -#define LX970A_CR_TTM 0x0070 /* Transceiver Test Mode (RO=0) */ -#define LX970A_CR_MSENABLE 0x0008 /* Master-Slave Enable (RO=0) */ -#define LX970A_CR_MSVALUE 0x0004 /* Master-Slave Value (RO=0) */ -#define LX970A_CR_RESERVED 0x0003 /* Reserved (RW=0) */ -#define LX970A_CR_RO_MASK 0x007C -#define LX970A_CR_RW_MASK 0xFF83 -#define LX970A_CR_DEFAULT 0x3300 - -#define LX970A_SR 0x01 /* Table 46. Status Register (Address 1) */ -#define LX970A_SR_100T4 0x8000 /* 100BASE-T4 (RO=0) */ -#define LX970A_SR_100TX_FD 0x4000 /* 100BASE-X full-duplex (RO=1) */ -#define LX970A_SR_100TX_HD 0x2000 /* 100BASE-X hald-duplex (RO=1) */ -#define LX970A_SR_10T_FD 0x1000 /* 10 Mb/s full-duplex (RO=1) */ -#define LX970A_SR_10T_HD 0x0800 /* 10 Mb/s half-duplex (RO=1) */ -#define LX970A_SR_100T2_FD 0x0400 /* 100BASE-T2 full-duplex (RO=0) */ -#define LX970A_SR_100T2_HD 0x0200 /* 100BASE-T2 half-duplex (RO=0) */ -#define LX970A_SR_RESERVED 0x0100 /* Reserved (RO=0) */ -#define LX970A_SR_MSCFGFAULT 0x0080 /* Master-Slave Configuration Fault (RO=0) */ -#define LX970A_SR_MFPS 0x0040 /* MF Preamble Suppression (RO=0) */ -#define LX970A_SR_ANCOMPLETE 0x0020 /* Auto-Neg. Complete (RO=0) */ -#define LX970A_SR_REMOTEFAULT 0x0010 /* Remote Fault (RO=0,LH) */ -#define LX970A_SR_ANABILITY 0x0008 /* Auto-Neg. Ability (RO=1) */ -#define LX970A_SR_LINKSTATUS 0x0004 /* Link Status (RO=0,LL) */ -#define LX970A_SR_JABBERDETECT 0x0002 /* Jabber Detect (10BASE-T Only) (RO=0,LH) */ -#define LX970A_SR_EXTCAPABILITY 0x0001 /* Extended Capability (RO=1) */ -#define LX970A_SR_RO_MASK 0xFFFF -#define LX970A_SR_RW_MASK 0x0000 -#define LX970A_SR_DEFAULT 0x7809 - -/* -PHY ID number: - Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) - (ROUI << 10) & FFFFFFFFh = 78100000h -*/ - -#define LX970A_PIR1 0x02 /* Table 47. PHY Identification Register 1 (Address 2) */ -#define LX970A_PIR1_PIN 0xFFFF /* PHY ID Number (RO=7810h) */ -#define LX970A_PIR1_RO_MASK 0xFFFF -#define LX970A_PIR1_RW_MASK 0x0000 -#define LX970A_PIR1_DEFAULT 0x7810 - -#define LX970A_PIR2 0x03 /* Table 48. PHY Identification Register 2 (Address 3) */ -#define LX970A_PIR2_PIN 0xFC00 /* PHY ID number (RO=000000b) */ -#define LX970A_PIR2_MANMODELNUM 0x03F0 /* Manufacturer’s model number (RO=000000b) */ -#define LX970A_PIR2_MANREVNUM 0x000F /* Manufacturer’s revision number (RO=0011b) */ -#define LX970A_PIR2_RO_MASK 0xFFFF -#define LX970A_PIR2_RW_MASK 0x0000 -#define LX970A_PIR2_DEFAULT 0x0003 - -#define LX970A_ANAR 0x04 /* Table 49. Auto Negotiation Advertisement Register (Address 4) */ -#define LX970A_ANAR_NEXTPAGE 0x8000 /* Next Page (RO=0) */ -#define LX970A_ANAR_RESERVED_1 0x4000 /* Reserved (RO=0) */ -#define LX970A_ANAR_REMOTEFAULT 0x2000 /* Remote Fault (RW=0) */ -#define LX970A_ANAR_RESERVED_2 0x1800 /* Reserved (RW=0) */ -#define LX970A_ANAR_PAUSE 0x0400 /* Pause (RW=0) */ -#define LX970A_ANAR_100T4 0x0200 /* 100BASE-T4 (RW=0) */ -#define LX970A_ANAR_100TX_FD 0x0100 /* 100BASE-TX (RW=1[FDE,MF4]) */ -#define LX970A_ANAR_100TX_HD 0x0080 /* 100BASE-TX (RW=1[MF4]) */ -#define LX970A_ANAR_10T_FD 0x0040 /* 10BASE-T full-duplex (RW=1[FDE,CFG1]) */ -#define LX970A_ANAR_10T_HD 0x0020 /* 10BASE-T (RW=1[CFG1]) */ -#define LX970A_ANAR_SF 0x001F /* Selector Field, S<4:0> (RW=00001b) */ -#define LX970A_ANAR_RO_MASK 0xC000 -#define LX970A_ANAR_RW_MASK 0x3FFF -#define LX970A_ANAR_DEFAULT 0x01E1 -/* auxiliary */ -#define LX970A_ANAR_SF_IEEE8023 0x0001 /* <00001> = IEEE 802.3 */ - -#define LX970A_ANLPAR 0x05 /* Table 50. Auto Negotiation Link Partner Ability Register (Address 5) */ -#define LX970A_ANLPAR_NEXTPAGE 0x8000 /* Next Page (RO) */ -#define LX970A_ANLPAR_ACKNOWLEDGE 0x4000 /* Acknowledge (RO) */ -#define LX970A_ANLPAR_REMOTEFAULT 0x2000 /* Remote Fault (RO) */ -#define LX970A_ANLPAR_RESERVED 0x1800 /* Reserved (RO) */ -#define LX970A_ANLPAR_PAUSE 0x0400 /* Pause (RO) */ -#define LX970A_ANLPAR_100T4 0x0200 /* 100BASE-T4 (RO) */ -#define LX970A_ANLPAR_100TX_FD 0x0100 /* 100BASE-TX full-duplex (RO) */ -#define LX970A_ANLPAR_100TX_HD 0x0080 /* 100BASE-TX (RO) */ -#define LX970A_ANLPAR_10T_FD 0x0040 /* 10BASE-T full-duplex (RO) */ -#define LX970A_ANLPAR_10T_HD 0x0020 /* 10BASE-T (RO) */ -#define LX970A_ANLPAR_SF 0x001F /* Selector Field S[4:0] (RO) */ -#define LX970A_ANLPAR_RO_MASK 0xFFFF -#define LX970A_ANLPAR_RW_MASK 0x0000 -#define LX970A_ANLPAR_DEFAULT 0x0000 -/* auxiliary */ -#define LX970A_ANLPAR_SF_IEEE8023 0x0001 /* <00001> = IEEE 802.3 */ - -#define LX970A_ANE 0x06 /* Table 51. Auto Negotiation Expansion (Address 6) */ -#define LX970A_ANE_RESERVED 0xFFE0 /* Reserved (RO=0) */ -#define LX970A_ANE_PDETECTFAULT 0x0010 /* Parallel Detection Fault (RO=0,LH) */ -#define LX970A_ANE_LPNPA 0x0008 /* Link Partner Next Page Able (RO=0) */ -#define LX970A_ANE_NPA 0x0004 /* Next Page Able (RO=0) */ -#define LX970A_ANE_PR 0x0002 /* Page Received (RO=0,LH) */ -#define LX970A_ANE_LPANA 0x0001 /* Link Partner Auto Neg Able (RO=0) */ -#define LX970A_ANE_RO_MASK 0xFFFF -#define LX970A_ANE_RW_MASK 0x0000 -#define LX970A_ANE_DEFAULT 0x0000 - -/* -Vendor Specific MII Registers -*/ - -#define LX970A_MR 0x10 /* Table 52. Mirror Register (Address 16, Hex 10) */ -#define LX970A_MR_USERDEFINED 0xFFFF /* User Defined (RW=0) */ -#define LX970A_MR_RO_MASK 0x0000 -#define LX970A_MR_RW_MASK 0xFFFF -#define LX970A_MR_DEFAULT 0x0000 - -#define LX970A_IER 0x11 /* Table 53. Interrupt Enable Register (Address 17, Hex 11) */ -#define LX970A_IER_RESERVED 0xFFF0 /* Reserved (RO=0) */ -#define LX970A_IER_MIIDRVLVL 0x0008 /* MIIDRVLVL (RW=0) */ -#define LX970A_IER_LNK_CRITERIA 0x0004 /* LNK CRITERIA (RW=0) */ -#define LX970A_IER_INTEN 0x0002 /* INTEN (RW=0) */ -#define LX970A_IER_TINT 0x0001 /* TINT (RW=0,IGN) */ -#define LX970A_IER_RO_MASK 0xFFF0 -#define LX970A_IER_RW_MASK 0x000F -#define LX970A_IER_DEFAULT 0x0000 - -#define LX970A_ISR 0x12 /* Table 54. Interrupt Status Register (Address 18, Hex 12) */ -#define LX970A_ISR_MINT 0x8000 /* MINT (RO=0?) */ -#define LX970A_ISR_XTALOK 0x4000 /* XTALOK (RO=0) */ -#define LX970A_ISR_RESERVED 0x3FFF /* Reserved (RO=0) */ -#define LX970A_ISR_RO_MASK 0xFFFF -#define LX970A_ISR_RW_MASK 0x0000 -#define LX970A_ISR_DEFAULT 0x0000 - -#define LX970A_CFGR 0x13 /* Table 55. Configuration Register (Address 19, Hex 13) */ -#define LX970A_CFGR_RESERVED_1 0x8000 /* Reserved (RO=0) */ -#define LX970A_CFGR_TXMITTEST 0x4000 /* Txmit Test (100BASE-TX) (RW=0,RTOR) */ -#define LX970A_CFGR_REPEATERMODE 0x2000 /* Repeater Mode (RW=0[MF1]) */ -#define LX970A_CFGR_MDIOINT 0x1000 /* MDIO_INT (RW=0,IGN) */ -#define LX970A_CFGR_TPLOOPBACK 0x0800 /* TP Loopback (10BASE-T) (RW=0) */ -#define LX970A_CFGR_SQE 0x0400 /* SQE (10BASE-T) (RW=0) */ -#define LX970A_CFGR_JABBER 0x0200 /* Jabber (10BASE-T) (RW=0) */ -#define LX970A_CFGR_LINKTEST 0x0100 /* Link Test (10BASE-T) (RW=0[CFG1,MF0]) */ -#define LX970A_CFGR_LEDC 0x00C0 /* LEDC Programming bits (RW=0) */ -#define LX970A_CFGR_ATXC 0x0020 /* Advance TX Clock (RW=0) */ -#define LX970A_CFGR_5BS_4BN 0x0010 /* 5B Symbol/(100BASE-X only) 4B Nibble (RW=1[MF2]) */ -#define LX970A_CFGR_SCRAMBLER 0x0008 /* Scrambler (100BASE-X only) (RW=1[MF3]) */ -#define LX970A_CFGR_100FX 0x0004 /* 100BASE-FX (RW=1[MF4,MF0]) */ -#define LX970A_CFGR_RESERVED_2 0x0002 /* Reserved (RO=0) */ -#define LX970A_CFGR_TD 0x0001 /* Transmit Disconnect (RW=0) */ -#define LX970A_CFGR_RO_MASK 0x8002 -#define LX970A_CFGR_RW_MASK 0x7FFD -#define LX970A_CFGR_DEFAULT 0x0014 -/* auxiliary */ -#define LX970A_CFGR_LEDC_COLLISION 0x0000 /* 0 0 LEDC indicates collision */ -#define LX970A_CFGR_LEDC_OFF 0x0040 /* 0 1 LEDC is off */ -#define LX970A_CFGR_LEDC_ACTIVITY 0x0080 /* 1 0 LEDC indicates activity */ -#define LX970A_CFGR_LEDC_ALWAYSON 0x00C0 /* 1 1 LEDC is continuously on (for diagnostic use) */ - -#define LX970A_CSR 0x14 /* Table 56. Chip Status Register (Address 20, Hex 14) */ -#define LX970A_CSR_RESERVED_1 0xC000 /* Reserved (RO=0?) */ -#define LX970A_CSR_LINK 0x2000 /* Link (RO=0,RTOR) */ -#define LX970A_CSR_DUPLEXMODE 0x1000 /* Duplex Mode (RO=1[FDE],RTOR) */ -#define LX970A_CSR_SPEED 0x0800 /* Speed (RO=1[CFG0],RTOR) */ -#define LX970A_CSR_RESERVED_2 0x0400 /* Reserved (RO=0?) */ -#define LX970A_CSR_ANCOMPLETE 0x0200 /* Auto-Negotiation Complete (RO=0,LH,RTOR) */ -#define LX970A_CSR_PAGERECEIVED 0x0100 /* Page Received (RO=0,LH,RTOR) */ -#define LX970A_CSR_RESERVED_3 0x00C0 /* Reserved (RO=0) */ -#define LX970A_CSR_RESERVED_4 0x0038 /* Reserved (RO=0?) */ -#define LX970A_CSR_LOWVOLTAGE 0x0004 /* Low-Voltage (RO=0?) */ -#define LX970A_CSR_RESERVED_5 0x0003 /* Reserved (RO=0?) */ -#define LX970A_CSR_RO_MASK 0xFFFF -#define LX970A_CSR_RW_MASK 0x0000 -#define LX970A_CSR_DEFAULT 0x1800 - -#endif diff --git a/common/dev_mpc860.c b/common/dev_mpc860.c index 2efc0200d..46252b52f 100644 --- a/common/dev_mpc860.c +++ b/common/dev_mpc860.c @@ -17,7 +17,7 @@ #include "memory.h" #include "device.h" #include "net_io.h" -#include "dev_lxt970a.h" +#include "rust-dynamips.h" #include "dev_mpc860.h" /* Debugging flags */ @@ -405,8 +405,7 @@ struct mpc860_data { /* FEC MII registers */ m_uint32_t fec_mii_data; - m_uint16_t fec_mii_regs[32]; - m_uint8_t fec_mii_last_read_reg; + struct Lxt970A *fec_mii_phy; /* Dual-Port RAM */ m_uint8_t dpram[MPC860_DPRAM_SIZE]; @@ -1207,7 +1206,7 @@ static int dev_mpc860_scc_access(struct mpc860_data *d,m_uint32_t offset, /* link status */ static int mpc860_fec_link_is_up(struct mpc860_data *d) { - return(d->fec_nio && !(d->fec_mii_regs[LX970A_CR] & LX970A_CR_POWERDOWN)); + return(d->fec_nio && lxt970a_link_is_up(d->fec_mii_phy)); } /* Trigger interrupt for FEC */ @@ -1423,115 +1422,16 @@ static int mpc860_fec_handle_rx_pkt(netio_desc_t *nio, return(TRUE); } -/* MII update registers */ -static void mpc860_fec_mii_update_regs(struct mpc860_data *d) -{ - m_uint16_t *regs = d->fec_mii_regs; - if (mpc860_fec_link_is_up(d)) { - /* link up, LX970A_SR_LINKSTATUS is latch down */ - regs[LX970A_CSR] |= LX970A_CSR_LINK; - if (!(regs[LX970A_CR] & LX970A_CR_ANENABLE)) { - /* manual selection */ - if ((regs[LX970A_CR] & LX970A_CR_SPEEDSELECT)) { - /* 100Mbps */ - regs[LX970A_CSR] |= LX970A_CSR_SPEED; - } else { - /* 10 Mbps */ - regs[LX970A_CSR] &= ~LX970A_CSR_SPEED; - } - if ((regs[LX970A_CR] & LX970A_CR_DUPLEXMODE)) { - /* full duplex */ - regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE; - } else { - /* half duplex */ - regs[LX970A_CSR] &= ~LX970A_CSR_DUPLEXMODE; - } - } else { - /* auto-negotiation, assume partner is standard 10/100 eth */ - regs[LX970A_ANLPAR] = (LX970A_ANLPAR_ACKNOWLEDGE | - LX970A_ANLPAR_100TX_FD | LX970A_ANLPAR_100TX_HD | - LX970A_ANLPAR_10T_FD | LX970A_ANLPAR_10T_HD); - if ((regs[LX970A_ANAR] & LX970A_ANAR_100TX_FD)) { - /* 100Mbps full duplex */ - regs[LX970A_CSR] |= (LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); - } else if ((regs[LX970A_ANAR] & LX970A_ANAR_100TX_HD)) { - /* 100Mbps half duplex */ - regs[LX970A_CSR] = ((regs[LX970A_CSR] & ~LX970A_CSR_DUPLEXMODE) | LX970A_CSR_SPEED); - } else if ((regs[LX970A_ANAR] & LX970A_ANAR_10T_FD)) { - /* 10Mbps full duplex */ - regs[LX970A_CSR] = (LX970A_CSR_DUPLEXMODE | (regs[LX970A_CSR] & ~LX970A_CSR_SPEED)); - } else { - /* 10Mbps half duplex */ - regs[LX970A_ANAR] |= LX970A_ANAR_10T_HD; - regs[LX970A_CSR] &= ~(LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); - } - d->fec_mii_regs[LX970A_CR] &= ~(LX970A_CR_ANRESTART); - d->fec_mii_regs[LX970A_SR] |= LX970A_SR_ANCOMPLETE; - d->fec_mii_regs[LX970A_CSR] |= LX970A_CSR_ANCOMPLETE; - } - } else { - /* link down or administratively down */ - d->fec_mii_regs[LX970A_SR] &= ~(LX970A_SR_ANCOMPLETE|LX970A_SR_LINKSTATUS); - d->fec_mii_regs[LX970A_CSR] &= ~(LX970A_CSR_LINK|LX970A_CSR_DUPLEXMODE|LX970A_CSR_SPEED|LX970A_CSR_ANCOMPLETE); - } -} - -/* MII register defaults */ -static void mpc860_fec_mii_defaults(struct mpc860_data *d) -{ - /* default is 100Mb/s full duplex and auto-negotiation */ - memset(d->fec_mii_regs, 0, sizeof(d->fec_mii_regs)); - d->fec_mii_regs[LX970A_CR] = LX970A_CR_DEFAULT; - d->fec_mii_regs[LX970A_SR] = LX970A_SR_DEFAULT; - d->fec_mii_regs[LX970A_PIR1] = LX970A_PIR1_DEFAULT; - d->fec_mii_regs[LX970A_PIR2] = LX970A_PIR2_DEFAULT; - d->fec_mii_regs[LX970A_ANAR] = LX970A_ANAR_DEFAULT; - d->fec_mii_regs[LX970A_ANE] = LX970A_ANE_DEFAULT; - d->fec_mii_regs[LX970A_MR] = LX970A_MR_DEFAULT; - d->fec_mii_regs[LX970A_IER] = LX970A_IER_DEFAULT; - d->fec_mii_regs[LX970A_ISR] = LX970A_ISR_DEFAULT; - d->fec_mii_regs[LX970A_CFGR] = LX970A_CFGR_DEFAULT; - d->fec_mii_regs[LX970A_CSR] = LX970A_CSR_DEFAULT; - - /* chip is powered up and stable */ - d->fec_mii_regs[LX970A_ISR] = LX970A_ISR_XTALOK; - - mpc860_fec_mii_update_regs(d); -} - /* MII register read access */ static void mpc860_fec_mii_read_access(struct mpc860_data *d, u_int phy,u_int reg) { - m_uint16_t res; - - res = d->fec_mii_regs[reg]; - - /* update bits */ - switch (reg) { - case LX970A_SR: - /* Latch Low */ - if (mpc860_fec_link_is_up(d)) { - d->fec_mii_regs[reg] &= LX970A_SR_LINKSTATUS; - } - break; - case LX970A_ISR: - if (d->fec_mii_last_read_reg == LX970A_SR) { - d->fec_mii_regs[reg] &= ~LX970A_ISR_MINT; - } - default: - /* XXX Latch High: - LX970A_SR_REMOTEFAULT, LX970A_SR_JABBERDETECT - LX970A_ANE_PDETECTFAULT, LX970A_ANE_PR, - LX970A_CSR_ANC, LX970A_CSR_PAGERECEIVED */ - break; - } + m_uint16_t res = lxt970a_mii_read_access(d->fec_mii_phy, reg); #if DEBUG_FEC - MPC_LOG(d,"FEC: Reading 0x%4.4x (0x%4.4x) from MII phy %d reg %d\n",res,d->fec_mii_regs[reg],phy,reg); + MPC_LOG(d,"FEC: Reading 0x%4.4x from MII phy %d reg %d\n",res,phy,reg); #endif - d->fec_mii_last_read_reg = reg; d->fec_mii_data &= 0xFFFF0000; d->fec_mii_data |= res; } @@ -1540,53 +1440,13 @@ static void mpc860_fec_mii_read_access(struct mpc860_data *d, static void mpc860_fec_mii_write_access(struct mpc860_data *d, u_int phy,u_int reg) { - m_uint16_t data, ro_mask, rw_mask; - int update_regs = FALSE; - - data = d->fec_mii_data & 0xFFFF; + m_uint16_t data = d->fec_mii_data & 0xFFFF; #if DEBUG_FEC MPC_LOG(d,"FEC: Writing 0x%4.4x to MII phy %d reg %d at ia=0x%4.4x,lr=0x%4.4x\n",data,phy,reg,CPU_PPC32(d->vm->boot_cpu)->ia,CPU_PPC32(d->vm->boot_cpu)->lr); #endif - switch (reg) { - case LX970A_CR: - /* reset, self clearing */ - if ((data & LX970A_CR_RESET)) { - mpc860_fec_mii_defaults(d); - return; - } - ro_mask = LX970A_CR_RO_MASK; - rw_mask = LX970A_CR_RW_MASK; - update_regs = TRUE; - break; - case LX970A_ANAR: - ro_mask = LX970A_ANAR_RO_MASK; - rw_mask = LX970A_ANAR_RW_MASK; - break; - case LX970A_MR: - ro_mask = LX970A_MR_RO_MASK; - rw_mask = LX970A_MR_RW_MASK; - break; - case LX970A_IER: - ro_mask = LX970A_IER_RO_MASK; - rw_mask = LX970A_IER_RW_MASK; - break; - case LX970A_CFGR: - ro_mask = LX970A_CFGR_RO_MASK; - rw_mask = LX970A_CFGR_RW_MASK; - break; - default: - /* read-only register */ - ro_mask = 0xFFFF; - rw_mask = 0x0000; - break; - } - - d->fec_mii_regs[reg] = (d->fec_mii_regs[reg] & ro_mask) | (data & rw_mask); - if (update_regs) { - mpc860_fec_mii_update_regs(d); - } + lxt970a_mii_write_access(d->fec_mii_phy, reg, data); } /* MII register access */ @@ -1724,7 +1584,7 @@ int mpc860_fec_set_nio(struct mpc860_data *d,netio_desc_t *nio) d->fec_nio = nio; netio_rxl_add(nio,(netio_rx_handler_t)mpc860_fec_handle_rx_pkt,d,NULL); - mpc860_fec_mii_update_regs(d); + lxt970a_set_link_partner(d->fec_mii_phy, true, LXT907A_AN_LP_ABILITY_ASSUMED); return(0); } @@ -1737,7 +1597,7 @@ int mpc860_fec_unset_nio(struct mpc860_data *d) if (d->fec_nio != NULL) { netio_rxl_remove(d->fec_nio); d->fec_nio = NULL; - mpc860_fec_mii_update_regs(d); + lxt970a_set_link_partner(d->fec_mii_phy, false, 0); } return(0); @@ -2067,6 +1927,8 @@ void mpc860_clear_pending_irq(struct mpc860_data *d,m_uint32_t val) void dev_mpc860_shutdown(vm_instance_t *vm,struct mpc860_data *d) { if (d != NULL) { + lxt970a_drop(d->fec_mii_phy); + /* Remove the device */ dev_remove(vm,&d->dev); @@ -2106,7 +1968,11 @@ int dev_mpc860_init(vm_instance_t *vm,char *name, dpram_w16(d,MPC860_SPI_BASE_ADDR,MPC860_SPI_BASE); /* Set MII register defaults */ - mpc860_fec_mii_defaults(d); + d->fec_mii_phy = lxt970a_new(); + if (d->fec_mii_phy == NULL) { + fprintf(stderr,"mpc860: unable to create fec_mii_phy.\n"); + return(-1); + } /* Map this device to the VM */ vm_bind_device(vm,&d->dev); diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 11798812a..bc34dc25e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -5,3 +5,12 @@ version = 3 [[package]] name = "rust-dynamips" version = "0.2.23" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "tock-registers" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9e2fdb3a1e862c0661768b7ed25390811df1947a8acbfbefe09b47078d93c4" diff --git a/rust/dynamips/Cargo.toml b/rust/dynamips/Cargo.toml index 80e6ec0cc..345f48013 100644 --- a/rust/dynamips/Cargo.toml +++ b/rust/dynamips/Cargo.toml @@ -8,3 +8,6 @@ rust-version = "1.57" # custom profiles need 1.57 [lib] crate-type = ["staticlib"] + +[dependencies] +tock-registers = "0.9.0" diff --git a/rust/dynamips/cbindgen.toml b/rust/dynamips/cbindgen.toml index f6ad24cd3..6c786e2d7 100644 --- a/rust/dynamips/cbindgen.toml +++ b/rust/dynamips/cbindgen.toml @@ -2,3 +2,4 @@ language = "C" include_version = true include_guard = "RUST_DYNAMIPS_H" pragma_once = true +documentation_style = "c++" diff --git a/rust/dynamips/src/c/dev_lxt907a.rs b/rust/dynamips/src/c/dev_lxt907a.rs new file mode 100644 index 000000000..8952c03bf --- /dev/null +++ b/rust/dynamips/src/c/dev_lxt907a.rs @@ -0,0 +1,57 @@ +//! C interface for [`crate::phy::lxt970a::Lxt970A`]. + +use crate::c::prelude::*; +use crate::phy::lxt970a::*; + +/// Allocate a new PHY. +#[no_mangle] +pub extern "C" fn lxt970a_new() -> *mut Lxt970A { + let mut phy = Box::new(Lxt970A::new()); + phy.update_regs(); + Box::into_raw(phy) // memory managed by C +} + +/// Deallocate a PHY. +#[no_mangle] +pub extern "C" fn lxt970a_drop(phy: *mut Lxt970A) { + let phy = NonNull::new(phy).unwrap(); + let _ = unsafe { Box::from_raw(phy.as_ptr()) }; // memory managed by rust +} + +/// Notify PHY about the partner link. +#[no_mangle] +pub extern "C" fn lxt970a_set_link_partner(phy: *mut Lxt970A, link_up: bool, an_lp_ability: u16) { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + if link_up { + phy.set_link_partner(Some(an_lp_ability)); + } else { + phy.set_link_partner(None); + } +} + +/// Check if the link is up. +#[no_mangle] +pub extern "C" fn lxt970a_link_is_up(phy: *mut Lxt970A) -> bool { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + phy.link_is_up() +} + +/// MII register read access. +#[no_mangle] +pub extern "C" fn lxt970a_mii_read_access(phy: *mut Lxt970A, reg: c_uint) -> u16 { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + let reg = usize::try_from(reg).unwrap(); + phy.mii_read_access(reg).unwrap_or(0) +} + +/// MII register write access. +#[no_mangle] +pub extern "C" fn lxt970a_mii_write_access(phy: *mut Lxt970A, reg: c_uint, value: u16) { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + let reg = usize::try_from(reg).unwrap(); + phy.mii_write_access(reg, value).unwrap_or(()) +} diff --git a/rust/dynamips/src/c/mod.rs b/rust/dynamips/src/c/mod.rs new file mode 100644 index 000000000..d66b87e92 --- /dev/null +++ b/rust/dynamips/src/c/mod.rs @@ -0,0 +1,14 @@ +//! Stuff that interacts with C code. + +pub(crate) mod prelude { + #![allow(unused_imports)] + //#![allow(dead_code)] + //#![allow(non_camel_case_types)] + + pub(crate) use crate::macros::opaque_struct; + pub(crate) use std::ffi::*; + pub(crate) use std::ptr::null_mut; + pub(crate) use std::ptr::NonNull; +} + +pub mod dev_lxt907a; diff --git a/rust/dynamips/src/lib.rs b/rust/dynamips/src/lib.rs index e69de29bb..5277ff596 100644 --- a/rust/dynamips/src/lib.rs +++ b/rust/dynamips/src/lib.rs @@ -0,0 +1,6 @@ +//! Crate rust-dynamips +#![allow(clippy::unusual_byte_groupings)] + +pub mod c; +pub mod macros; +pub mod phy; diff --git a/rust/dynamips/src/macros.rs b/rust/dynamips/src/macros.rs new file mode 100644 index 000000000..22cf80ed0 --- /dev/null +++ b/rust/dynamips/src/macros.rs @@ -0,0 +1,14 @@ +//! Macros +#![allow(unused_macros)] + +/// Defines an opaque struct that has unknown data, is pointer aligned(?), and cannot change address. +macro_rules! opaque_struct { + ($name:ident) => { + pub struct $name { + _data: [u8; 0], + _marker: ::std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>, + } + }; +} + +pub(crate) use opaque_struct; diff --git a/rust/dynamips/src/phy/lxt970a.rs b/rust/dynamips/src/phy/lxt970a.rs new file mode 100644 index 000000000..03788ebb4 --- /dev/null +++ b/rust/dynamips/src/phy/lxt970a.rs @@ -0,0 +1,656 @@ +//! 10/100 Mbps PHY +//! +//! # References +//! * [Intel LXT970A Dual-Speed Fast Ethernet Transceiver, January 2001](https://github.com/flaviojs/dynamips-datasheets/blob/master/ethernet/phy/LXT970A.pdf) +//! * IEEE Std 802.3-2008, Section 2 +//! +//! # MISSING +//! * tests +//! * timings +//! * errors (jabber, parallel detection, manual selection) +//! * some register fields + +use std::fmt::Debug; +use tock_registers::interfaces::ReadWriteable; +use tock_registers::interfaces::Readable; +use tock_registers::interfaces::Writeable; +use tock_registers::register_bitfields; +use tock_registers::registers::InMemoryRegister; +use tock_registers::LocalRegisterCopy; +use tock_registers::RegisterLongName; + +/// Assume the link partner is a similar 10/100 Mbps PHY and ack. +pub const LXT907A_AN_LP_ABILITY_ASSUMED: u16 = 0b0100_0001_1110_0001; + +/// 10/100 Mbps PHY +#[derive(Debug)] +pub struct Lxt970A { + pub regs: Regs, + pub pins: Pins, + pub last_read_was_status: bool, + pub link_partner: Option, +} +impl Default for Lxt970A { + fn default() -> Self { + Self::new_with_pins(Pins::default()) + } +} +impl Lxt970A { + /// Creates a new PHY with default values. + pub fn new() -> Self { + Self::default() + } + /// Creates a new PHY with values based on the pins. + pub fn new_with_pins(pins: Pins) -> Self { + Self { regs: Regs::new_with_pins(pins), pins, last_read_was_status: false, link_partner: None } + } + /// Set Link Partner (with an_lp_ability) + pub fn set_link_partner(&mut self, link_partner: Option) { + self.link_partner = link_partner; + self.update_regs(); + } + /// Link status + pub fn link_is_up(&self) -> bool { + self.regs.control.matches_all(Control::POWER_DOWN::No) && self.regs.chip_status.matches_all(ChipStatus::LINK::Up) + } + /// Update registers + pub fn update_regs(&mut self) { + if self.regs.control.matches_all(Control::RESET::Yes) { + // reset + self.regs = Regs::new_with_pins(self.pins); // SC + debug_assert!(self.regs.control.matches_all(Control::RESET::No)); + } + if self.regs.control.matches_all(Control::AN_ENABLE::Yes) { + if self.regs.control.matches_all(Control::AN_RESTART::Yes) { + // restart auto negotiation + self.regs.status.modify(Status::AN_COMPLETE::No); + self.regs.chip_status.modify(ChipStatus::LINK::Down); + self.regs.control.modify(Control::AN_RESTART::No); // SC + } + if self.link_partner.is_some() && self.regs.chip_status.matches_all(ChipStatus::LINK::Down) { + // do auto negotiation + self.regs.an_lp_ability.set(self.link_partner.unwrap()); + //TODO self.regs.an_expansion.modify(AnExpansion::PD_FAULT::Yes); // LH + self.regs.an_expansion.modify(AnExpansion::PAGE_RECEIVED::Yes); // LH + self.regs.chip_status.modify(ChipStatus::PAGE_RECEIVED::Yes); // LH + let mut remote_fault = false; + if self.regs.an_lp_ability.matches_all(AnLpAbility::REMOTE_FAULT::Yes) || !self.regs.an_lp_ability.matches_all(AnLpAbility::SF::Ieee802Dot3) { + remote_fault = true; + } else { + let mut overlap = self.regs.an_advertise.extract(); + overlap.set(overlap.get() & self.regs.an_lp_ability.get()); + if overlap.matches_all(AnAdvertise::ALLOW_100TX_FD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_100TX_HD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_10T_FD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_10T_HD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } else { + remote_fault = true; + } + } + if remote_fault { + self.regs.status.modify(Status::REMOTE_FAULT::Yes); // LH + } else { + // auto negotiation complete + self.regs.status.modify(Status::AN_COMPLETE::Yes); + self.regs.chip_status.modify(ChipStatus::LINK::Up); + } + } + } else if self.link_partner.is_some() { + // do manual selection + let link_partner = LocalRegisterCopy::::new(self.link_partner.unwrap()); + let mut fault = false; + let allow_100tx_fd = link_partner.matches_all(AnLpAbility::ALLOW_100TX_FD::Yes); + let allow_100tx_hd = link_partner.matches_all(AnLpAbility::ALLOW_100TX_HD::Yes); + if (allow_100tx_fd || allow_100tx_hd) && self.regs.control.matches_all(Control::SPEED::Speed100Mbps) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + if allow_100tx_fd && self.regs.control.matches_all(Control::DUPLEX::FullDuplex) { + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else { + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } + } else { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + let allow_10t_fd = link_partner.matches_all(AnLpAbility::ALLOW_10T_FD::Yes); + let allow_10t_hd = link_partner.matches_all(AnLpAbility::ALLOW_10T_HD::Yes); + if allow_10t_fd && self.regs.control.matches_all(Control::DUPLEX::FullDuplex) { + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if allow_10t_hd { + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } else { + fault = true; + } + } + if fault { + //TODO how do I signal an error? + self.regs.chip_status.matches_all(ChipStatus::LINK::Down); + } else { + self.regs.chip_status.matches_all(ChipStatus::LINK::Up); + } + } else { + self.regs.chip_status.matches_all(ChipStatus::LINK::Down); + } + // latches + if self.regs.chip_status.matches_all(ChipStatus::LINK::Down) { + self.regs.status.modify(Status::LINK::Down); // LL + } + //TODO self.regs.status.modify(Status::JABBER_DETECTED::Yes); // LH + if self.regs.status.matches_all(Status::AN_COMPLETE::Yes) { + self.regs.chip_status.modify(ChipStatus::AN_COMPLETE::Yes); // LH + } + // chip is powered up and stable + self.regs.int_status.modify(IntStatus::XTAL::Stable); + } + /// Set register defaults. + pub fn set_defaults(&mut self) { + self.regs = Regs::new_with_pins(self.pins); + self.update_regs(); + } + /// MII register read access + pub fn mii_read_access(&mut self, idx: usize) -> Option { + if self.regs.control.matches_all(Control::ISOLATE::Yes) { + return None; + } + let value = match idx { + Regs::IDX_CONTROL => self.regs.control.get(), + Regs::IDX_STATUS => self.regs.status.get(), + Regs::IDX_ID1 => self.regs.id1.get(), + Regs::IDX_ID2 => self.regs.id2.get(), + Regs::IDX_AN_ADVERTISE => self.regs.an_advertise.get(), + Regs::IDX_AN_LP_ABILITY => self.regs.an_lp_ability.get(), + Regs::IDX_AN_EXPANSION => self.regs.an_expansion.get(), + Regs::IDX_MIRROR => self.regs.mirror.get(), + Regs::IDX_INT_ENABLE => self.regs.int_enable.get(), + Regs::IDX_INT_STATUS => self.regs.int_status.get(), + Regs::IDX_CONFIG => self.regs.config.get(), + Regs::IDX_CHIP_STATUS => self.regs.chip_status.get(), + _ => 0, + }; + match idx { + Regs::IDX_STATUS => { + let mut reg = self.regs.status.extract(); + reg.modify(Status::REMOTE_FAULT::No); // LH + reg.modify(Status::LINK::Up); // LL + reg.modify(Status::JABBER_DETECTED::No); // LH + self.regs.status.set(reg.get()); + } + Regs::IDX_AN_EXPANSION => { + let mut reg = self.regs.an_expansion.extract(); + reg.modify(AnExpansion::PD_FAULT::No); // LH + reg.modify(AnExpansion::PAGE_RECEIVED::No); // LH + self.regs.an_expansion.set(reg.get()); + } + Regs::IDX_INT_STATUS => { + if self.last_read_was_status { + self.regs.int_status.modify(IntStatus::MII_INT::No); // LH+1 + } + } + Regs::IDX_CHIP_STATUS => { + let mut reg = self.regs.chip_status.extract(); + reg.modify(ChipStatus::AN_COMPLETE::No); // LH + reg.modify(ChipStatus::PAGE_RECEIVED::No); // LH + self.regs.chip_status.set(reg.get()); + } + _ => {} + } + self.last_read_was_status = idx == Regs::IDX_STATUS; + self.update_regs(); + Some(value) + } + + /// MII register write access + pub fn mii_write_access(&mut self, idx: usize, value: u16) -> Option<()> { + if self.regs.control.matches_all(Control::ISOLATE::Yes) { + // TODO how are you supposed to clear this bit if you can't write? + return None; + } + fn update(reg: &mut InMemoryRegister, rw_mask: u16, value: u16) { + reg.set((reg.get() & !rw_mask) | (value & rw_mask)); + } + match idx { + Regs::IDX_CONTROL => update(&mut self.regs.control, Regs::RW_CONTROL, value), + Regs::IDX_AN_ADVERTISE => update(&mut self.regs.an_advertise, Regs::RW_AN_ADVERTISE, value), + Regs::IDX_MIRROR => update(&mut self.regs.mirror, Regs::RW_MIRROR, value), + Regs::IDX_INT_ENABLE => update(&mut self.regs.int_enable, Regs::RW_INT_ENABLE, value), + Regs::IDX_CONFIG => update(&mut self.regs.config, Regs::RW_CONFIG, value), + _ => {} + }; + self.update_regs(); + Some(()) + } +} + +/// Pins that affect the chip. +#[derive(Debug, Copy, Clone)] +pub struct Pins { + pub mf0: bool, + pub mf1: bool, + pub mf2: bool, + pub mf3: bool, + pub mf4: bool, + pub cfg0: bool, + pub cfg1: bool, + pub fde: bool, + pub trste: bool, +} +impl Default for Pins { + fn default() -> Self { + Self { + mf0: true, // Auto Negotiate + mf1: false, // DTE Mode + mf2: true, // 5B Symbol + mf3: true, // Bypass Scrambler + mf4: true, // 100 Mbps Capability + cfg0: true, // Auto Negotiate Restart + cfg1: true, // 10 Mbps Capability + fde: true, // Full Duplex + trste: false, // Do Not Isolate + } + } +} +impl Pins { + pub fn new() -> Self { + Self::default() + } +} + +/// In-memory registers. +pub struct Regs { + pub control: InMemoryRegister, + pub status: InMemoryRegister, + pub id1: InMemoryRegister, + pub id2: InMemoryRegister, + pub an_advertise: InMemoryRegister, + pub an_lp_ability: InMemoryRegister, + pub an_expansion: InMemoryRegister, + pub mirror: InMemoryRegister, + pub int_enable: InMemoryRegister, + pub int_status: InMemoryRegister, + pub config: InMemoryRegister, + pub chip_status: InMemoryRegister, +} +impl Regs { + pub const IDX_CONTROL: usize = 0; + pub const IDX_STATUS: usize = 1; + pub const IDX_ID1: usize = 2; + pub const IDX_ID2: usize = 3; + pub const IDX_AN_ADVERTISE: usize = 4; + pub const IDX_AN_LP_ABILITY: usize = 5; + pub const IDX_AN_EXPANSION: usize = 6; + pub const IDX_MIRROR: usize = 16; + pub const IDX_INT_ENABLE: usize = 17; + pub const IDX_INT_STATUS: usize = 18; + pub const IDX_CONFIG: usize = 19; + pub const IDX_CHIP_STATUS: usize = 20; + pub const RW_CONTROL: u16 = 0b1111_1111_1000_0011; + pub const RW_AN_ADVERTISE: u16 = 0b0011_1111_1111_1111; + pub const RW_MIRROR: u16 = 0b1111_1111_1111_1111; + pub const RW_INT_ENABLE: u16 = 0b0000_0000_0000_1111; + pub const RW_CONFIG: u16 = 0b1111_1111_1111_1111; + /// Create registers with default values. + pub fn new() -> Regs { + Regs::default() + } + /// Create registers with values based on the pins. + pub fn new_with_pins(pins: Pins) -> Regs { + let regs = Regs::default(); + regs.control.set({ + let mut reg = regs.control.extract(); + if pins.mf0 { + reg.modify(Control::AN_ENABLE::Yes); + if pins.cfg0 { + reg.modify(Control::AN_RESTART::Yes); + } + } else { + if pins.cfg0 { + reg.modify(Control::SPEED::Speed100Mbps); + } + if pins.fde { + reg.modify(Control::DUPLEX::FullDuplex); + } + } + if pins.trste { + reg.modify(Control::ISOLATE::Yes); + } + reg.into() + }); + regs.an_advertise.set({ + let mut reg = regs.an_advertise.extract(); + if pins.mf4 { + reg.modify(AnAdvertise::ALLOW_100TX_HD::Yes); + if pins.fde { + reg.modify(AnAdvertise::ALLOW_100TX_FD::Yes); + } + } + if pins.cfg1 { + reg.modify(AnAdvertise::ALLOW_10T_HD::Yes); + if pins.fde { + reg.modify(AnAdvertise::ALLOW_10T_FD::Yes); + } + } + reg.into() + }); + regs.config.set({ + let mut reg = regs.config.extract(); + if !pins.mf0 { + if pins.cfg1 { + reg.modify(Config::LINK_TEST::No); + } + if pins.mf4 { + reg.modify(Config::CABLE_100FX::Fiber); + } + } + if pins.mf1 { + reg.modify(Config::MODE::Repeater); + } + if pins.mf2 { + reg.modify(Config::CODER::Symbol5b); + } + if pins.mf3 { + reg.modify(Config::SCRAMBLER::Bypass); + } + reg.into() + }); + regs + } +} +impl Default for Regs { + fn default() -> Regs { + Regs { + control: InMemoryRegister::new(0), + status: InMemoryRegister::new(0b0111_1000_0000_1001), + id1: InMemoryRegister::new(0x7810), + id2: InMemoryRegister::new(0b000000_000000_0001), + an_advertise: InMemoryRegister::new(0b00_0_00_000000_00001), + an_lp_ability: InMemoryRegister::new(0), + an_expansion: InMemoryRegister::new(0), + mirror: InMemoryRegister::new(0), + int_enable: InMemoryRegister::new(0), + int_status: InMemoryRegister::new(0), + config: InMemoryRegister::new(0), + chip_status: InMemoryRegister::new(0), + } + } +} +impl Debug for Regs { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + fmt.debug_struct("Regs") + .field("control", &format_args!("0x{:04x}", self.control.get())) + .field("status", &format_args!("0x{:04x}", self.status.get())) + .field("id1", &format_args!("0x{:04x}", self.id1.get())) + .field("id2", &format_args!("0x{:04x}", self.id2.get())) + .field("an_advertise", &format_args!("0x{:04x}", self.an_advertise.get())) + .field("an_lp_ability", &format_args!("0x{:04x}", self.an_lp_ability.get())) + .field("an_expansion", &format_args!("0x{:04x}", self.an_expansion.get())) + .field("mirror", &format_args!("0x{:04x}", self.mirror.get())) + .field("ier", &format_args!("0x{:04x}", self.int_enable.get())) + .field("isr", &format_args!("0x{:04x}", self.int_status.get())) + .field("config", &format_args!("0x{:04x}", self.config.get())) + .field("chip_status", &format_args!("0x{:04x}", self.chip_status.get())) + .finish() + } +} + +/* +Abreviations: + RW=x - Read/Write with default value x + RO=x - Read Only with default value x + SC - Self Clearing + LH - Latching High (remains High until read, and then returns to Low) + LL - Latching Low (remains Low until read, and then returns to High) +*/ + +register_bitfields! [ + u16, + + /* + Standard MII Registers + */ + + /// Table 45. Control Register (Address 0) + Control [ + /// 0.15 Reset, 1=Yes, 0=No (RW=0,SC) + RESET OFFSET(15) NUMBITS(1) [Yes = 1, No = 0], + /// 0.14 Loopback, 1=Enable, 0=Disable (RW=0) + LOOP OFFSET(14) NUMBITS(1) [], + /// 0.13 Speed Selection, 1=100 Mbps, 0=10 Mbps (RW=?/CFG0&!MF0) + SPEED OFFSET(13) NUMBITS(1) [Speed100Mbps = 1, Speed10Mbps = 0], + /// 0.12 Auto Negotiation, 1=Enable, 0=Disable (RW=MF0) + AN_ENABLE OFFSET(12) NUMBITS(1) [Yes = 1, No = 0], + /// 0.11 Power Down, 1=Yes, 0=No (RW=0) + /// When leaving Power Down, you must wait 500 ns minimum before you can write to registers. + POWER_DOWN OFFSET(11) NUMBITS(1) [Yes = 1, No = 0], + /// 0.10 Electrically Isolate from MII, 1=Enable, 0=Normal (RW=TRSTE) + ISOLATE OFFSET(10) NUMBITS(1) [Yes = 1, No = 0], + /// 0.9 Restart Auto Negotiation, 1=Enable, 0=Normal (RW=0/CFG0&MF0,SC) + AN_RESTART OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 0.8 Duplex Mode, 1=Full Duplex, 0=Half DUplex (RW=0/FDE&!MF0) + DUPLEX OFFSET(8) NUMBITS(1) [FullDuplex = 1, HalfDuplex = 0], + /// 0.7 Collision Test, 1=Enable COL signal test (with loopback), 0=Disable (RW=0) + COLLISION_TEST OFFSET(7) NUMBITS(1) [], + /// 0.6:4 Transceiver Test Mode, 0=Not Supported (RO=0) + TTM OFFSET(4) NUMBITS(3) [], + /// 0.3 Master-Slave Enable, 0=Not Supported (RO=0) + MS_ENABLE OFFSET(3) NUMBITS(1) [], + /// 0.2 Master-Slave Value, 0=Not Supported (RO=0) + MS_VALUE OFFSET(2) NUMBITS(1) [], + /// 0.1:0 Reserved (RW=0) + RESERVED OFFSET(0) NUMBITS(2) [], + ], + /// Table 46. Status Register (Address 1) + Status [ + /// 1.15 100BASE-T4, 0=Not Supported (RO=0) + ABLE_100T4 OFFSET(15) NUMBITS(1) [], + /// 1.14 100BASE-X Full-Duplex, 1=Supported (RO=1) + ABLE_100X_FD OFFSET(14) NUMBITS(1) [], + /// 1.13 100BASE-X Half-Duplex, 1=Supported (RO=1) + ABLE_100X_HD OFFSET(13) NUMBITS(1) [], + /// 1.12 10 Mbps Full-Duplex, 1=Supported (RO=1) + ABLE_10_FD OFFSET(12) NUMBITS(1) [], + /// 1.11 10 Mbps Half-Duplex, 1=Supported (RO=1) + ABLE_10_HD OFFSET(11) NUMBITS(1) [], + /// 1.10 100BASE-T2 Full-Duplex, 0=Not Supported (RO=0) + ABLE_100T2_FD OFFSET(10) NUMBITS(1) [], + /// 1.9 100BASE-T2 Half-Duplex, 0=Not Supported (RO=0) + ABLE_100T2_HD OFFSET(9) NUMBITS(1) [], + /// 1.8 Reserved (RO=0) + RESERVED OFFSET(8) NUMBITS(1) [], + /// 1.7 Master-Slave Configuration Fault, 0=Not Supported (RO=0) + MS_CFG_FAULT OFFSET(7) NUMBITS(1) [], + /// 1.6 MF Preamble Suppression, 0=Not Supported (RO=0) + MF_PS OFFSET(6) NUMBITS(1) [], + /// 1.5 Auto Negotiation Complete, 1=Complete, 0=Not Complete (RO=0) + AN_COMPLETE OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 1.4 Remote Fault in Link Partner, 1=Yes, 0=No (RO=0,LH) + REMOTE_FAULT OFFSET(4) NUMBITS(1) [Yes = 1, No = 0], + /// 1.3 Auto Negotiation Ability, 1=Supported (RO=1) + AN_ABILITY OFFSET(3) NUMBITS(1) [], + /// 1.2 Link Status, 1=Up, 0=Down (RO=0,LL) + LINK OFFSET(2) NUMBITS(1) [Up = 1, Down = 0], + /// 1.1 Jabber Detected (10BASE-T Only), 1=Yes, 0=No (RO=0,LH) + JABBER_DETECTED OFFSET(1) NUMBITS(1) [Yes = 1, No = 0], + /// 1.0 Extended Capability, 1=Extended (RO=1) + EXT_CAPABILITY OFFSET(1) NUMBITS(1) [], + ], + + /* + PHY ID number: + Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) + (ROUI << 10) & FFFFFFFFh = 78100000h + */ + + /// Table 47. PHY Identification Register 1 (Address 2) + Id1 [ + /// 2.15:0 PHY ID Number (RO=0x7810) + ID OFFSET(0) NUMBITS(16) [], + ], + /// Table 48. PHY Identification Register 2 (Address 3) + Id2 [ + /// 3.15:10 PHY ID number (RO=0b000000) + ID OFFSET(10) NUMBITS(6) [], + /// 3.9:4 Manufacturer’s model number (RO=0b000000) + MODEL OFFSET(4) NUMBITS(6) [], + /// 3.3:0 Manufacturer’s revision number (RO=0b0011) + REV OFFSET(0) NUMBITS(4) [], + ], + /// Table 49. Auto Negotiation Advertisement Register (Address 4) + AnAdvertise [ + /// 4.15 Next Page, 0=Not Supported (RO=0) + NEXT_PAGE OFFSET(15) NUMBITS(1) [], + /// 4.14 Reserved (RO=0) + RESERVED_1 OFFSET(14) NUMBITS(1) [], + /// 4.13 Remote Fault, 1=Yes, 0=No (RW=0) + REMOTE_FAULT OFFSET(13) NUMBITS(1) [Yes = 1, No = 0], + /// 4.12:11 Reserved (RW=0) + RESERVED_2 OFFSET(11) NUMBITS(2) [], + /// 4.10 Allow Pause for Full-Duplex, 1=Yes, 0=No (RW=0) + ALLOW_PAUSE_FD OFFSET(10) NUMBITS(1) [Yes = 1, No = 0], + /// 4.9 Allow 100BASE-T4, 1=Yes, 0=No (RW=0) + ALLOW_100T4 OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 4.8 Allow 100BASE-TX 1=Yes, 0=No (RW=FDE&MF4) + ALLOW_100TX_FD OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 4.7 Allow 100BASE-TX 1=Yes, 0=No (RW=MF4) + ALLOW_100TX_HD OFFSET(7) NUMBITS(1) [Yes = 1, No = 0], + /// 4.6 Allow 10BASE-T full-duplex (RW=FDE&CFG1) + ALLOW_10T_FD OFFSET(6) NUMBITS(1) [Yes = 1, No = 0], + /// 4.5 Allow 10BASE-T (RW=CFG1) + ALLOW_10T_HD OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 4.4:0 Selector Field, 0b00001=IEEE 802.3, 0b00010=IEEE 802.9 ISLAN-16T, 0b00000=Reserved, 0b11111=Reserved (RW=0b00001) + SF OFFSET(0) NUMBITS(5) [Ieee802Dot3 = 0b00001], + ], + /// Table 50. Auto Negotiation Link Partner Ability Register (Address 5) + AnLpAbility [ + /// 5.15 Next Page (RO) + NEXT_PAGE OFFSET(15) NUMBITS(1) [], + /// 5.14 Acknowledge (RO) + ACK OFFSET(14) NUMBITS(1) [], + /// 5.13 Remote Fault (RO) + REMOTE_FAULT OFFSET(13) NUMBITS(1) [Yes = 1, No = 0], + /// 5.12:11 Reserved (RO) + RESERVED OFFSET(11) NUMBITS(2) [], + /// 5.10 Allow Pause for Full-Duplex (RO) + ALLOW_PAUSE_FD OFFSET(12) NUMBITS(1) [Yes = 1, No = 0], + /// 5.9 Allow 100BASE-T4 (RO) + ALLOW_100T4 OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 5.8 Allow 100BASE-TX Full-Duplex (RO) + ALLOW_100TX_FD OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 5.7 Allow 100BASE-TX Half-Duplex (RO) + ALLOW_100TX_HD OFFSET(7) NUMBITS(1) [Yes = 1, No = 0], + /// 5.6 Allow 10BASE-T Full-Duplex (RO) + ALLOW_10T_FD OFFSET(6) NUMBITS(1) [Yes = 1, No = 0], + /// 5.5 10 Allow BASE-T Half-Duplex (RO) + ALLOW_10T_HD OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 5.4:0 Selector Field (RO) + SF OFFSET(0) NUMBITS(5) [Ieee802Dot3 = 0b0001], + ], + /// Table 51. Auto Negotiation Expansion (Address 6) + AnExpansion [ + /// 6.15:5 Reserved (RO=0) + RESERVED OFFSET(5) NUMBITS(11) [], + /// 6.4 Parallel Detection Fault, 1=Yes, 0=No (RO=0,LH) + PD_FAULT OFFSET(4) NUMBITS(1) [Yes = 1, No = 0], + /// 6.3 Link Partner Next Page Able, 1=Capable, 0=Incapable (RO=0) + LP_NPA OFFSET(3) NUMBITS(1) [], + /// 6.2 Next Page Able, 0=Not Supported (RO=0) + NPA OFFSET(2) NUMBITS(1) [], + /// 6.1 Page Received (3 consecutive identical), 1=Yes, 0=No (RO=0,LH) + PAGE_RECEIVED OFFSET(1) NUMBITS(1) [Yes = 1, No = 0], + /// 6.0 Link Partner Auto Negotiation Able, 1=Capable, 0=Incapable (RO=0) + LP_ANA OFFSET(0) NUMBITS(1) [], + ], + + /* + Vendor Specific MII Registers + */ + + /// Table 52. Mirror Register (Address 16, Hex 10) + Mirror [ + /// 16.15:0 User Defined (RW=0) + USER_DEFINED OFFSET(0) NUMBITS(16) [], + ], + /// Table 53. Interrupt Enable Register (Address 17, Hex 11) + IntEnable [ + /// 17.15:4 Reserved (RO=0) + RESERVED OFFSET(4) NUMBITS(12) [], + /// 17.3 MII Driver Levels, 1=Reduced, 0=High Strength (RW=0) + MII_DRV_LVL OFFSET(3) NUMBITS(1) [Reduced = 1, HighStrength = 0], + /// 17.2 Link Criteria, 1=Enhanced, 0=Standard (RW=0) + LNK_CRITERIA OFFSET(2) NUMBITS(1) [Enhanced = 1, Standard = 0], + /// 17.1 Enable Interrupts, 1=Enable, 0=Disable (RW=0) + INT_ENABLE OFFSET(1) NUMBITS(1) [], + /// 17.0 Trigger Interrupt, 1=Force, 0=Normal (RW=0) + INT_TRIGGER OFFSET(0) NUMBITS(1) [], + ], + /// Table 54. Interrupt Status Register (Address 18, Hex 12) + IntStatus [ + /// 18.15 MII Interrupt Pending, 1=Yes, 0=No (RO=0,LH+1) + MII_INT OFFSET(15) NUMBITS(1) [Yes = 1, No = 0], + /// 18.14 XTAL OK, 1=Stable, 0=Unstable (RO=0) + XTAL OFFSET(14) NUMBITS(1) [Stable = 1, Unstable = 0], + /// 18.13:0 Reserved (RO=0) + RESERVED OFFSET(0) NUMBITS(14) [], + ], + /// Table 55. Configuration Register (Address 19, Hex 13) + Config [ + /// 19.15 Reserved (RO=0) + RESERVED_1 OFFSET(15) NUMBITS(1) [], + /// 19.14 Txmit Test (100BASE-TX), 1=Enabled, 0=Disabled (RW=0) + TXMIT_TEST OFFSET(14) NUMBITS(1) [], + /// 19.13 Mode, 1=Repeater, 0=Normal (RW=MF1) + MODE OFFSET(13) NUMBITS(1) [Repeater = 1, Normal = 0], + /// 19.12 MDIO Interrupts, 1=Enabled, 0=Normal (RW=0) + MDIO_INT OFFSET(12) NUMBITS(1) [], + /// 19.11 TP Loopback (10BASE-T), 1=Disable, 0=Enable (RW=0) + TP_LOOPBACK OFFSET(11) NUMBITS(1) [], + /// 19.10 SQE (10BASE-T), 1=Enable, 0=Disable (RW=0) + SQE OFFSET(10) NUMBITS(1) [], + /// 19.9 Jabber (10BASE-T), 1=Disable, 0=Enable (RW=0) + NO_JABBER OFFSET(9) NUMBITS(1) [], + /// 19.8 Link Test (10BASE-T), 1=Disable, 0=Enable (RW=CFG1&!MF0) + LINK_TEST OFFSET(8) NUMBITS(1) [No = 1, Yes = 0], + /// 19.7:6 LEDC Programming bits (RW=0b00) + LEDC OFFSET(6) NUMBITS(2) [Collision = 0b00, Off = 0b01, Activity = 0b10, AlwaysOn = 0b11], + /// 19.5 Advance TX Clock, 1=1/2 TX_CLK, 0=Normal (RW=0) + ATXC OFFSET(5) NUMBITS(1) [], + /// 19.4 5B Symbol/(100BASE-X only) 4B Nibble, 1=5B Symbol, 0=4B Nibble (RW=MF2) + CODER OFFSET(4) NUMBITS(1) [Symbol5b = 1, Nibble4b = 0], + /// 19.3 Bypass Scrambler (100BASE-X only), 1=Bypass, 0=Normal (RW=MF3) + SCRAMBLER OFFSET(3) NUMBITS(1) [Bypass = 1, Normal = 0], + /// 19.2 100BASE-FX, 1=Fiber, 0=Twisted Pair (RW=MF4&!MF0)) + CABLE_100FX OFFSET(2) NUMBITS(1) [Fiber = 1, TwistedPair = 0], + /// 19.1 Reserved (RO=0) + RESERVED_2 OFFSET(1) NUMBITS(1) [], + /// 19.0 Transmit Disconnect, 1=Disconnect, 0=Normal (RW=0) + TD OFFSET(0) NUMBITS(1) [], + ], + /// Table 56. Chip Status Register (Address 20, Hex 14) + ChipStatus [ + /// 20.15:14 Reserved (RO=0) + RESERVED_1 OFFSET(14) NUMBITS(2) [], + /// 20.13 Link, 1=Up, 0=Down (RO=0) + LINK OFFSET(13) NUMBITS(1) [Up = 1, Down = 0], + /// 20.12 Duplex Mode, 1=Full Duplex, 0=Half Duplex (RO=?/FDE) + DUPLEX OFFSET(12) NUMBITS(1) [FullDuplex = 1, HalfDuplex = 0], + /// 20.11 Speed, 1=100 Mbps, 0=10Mbps (RO=?/CFG0) + SPEED OFFSET(11) NUMBITS(1) [Speed100Mbps = 1, Speed10Mbps = 0], + /// 20.10 Reserved (RO=0) + RESERVED_2 OFFSET(10) NUMBITS(1) [], + /// 20.9 Auto Negotiation Complete, 1=Yes, 0=No (RO=0,LH) + AN_COMPLETE OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 20.8 Page Received (3 consecutive identical), 1=Yes, 0=No (RO=0,LH) + PAGE_RECEIVED OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 20.7:3 Reserved (RO=0) + RESERVED_3 OFFSET(3) NUMBITS(5) [], + /// 20.2 Low-Voltage, 1=Yes, 0=No (RO=0) + LOW_VOLTAGE_FAULT OFFSET(2) NUMBITS(1) [Yes = 1, No = 0], + /// 20.1:0 Reserved (RO=0) + RESERVED_4 OFFSET(0) NUMBITS(2) [], + ], +]; diff --git a/rust/dynamips/src/phy/mod.rs b/rust/dynamips/src/phy/mod.rs new file mode 100644 index 000000000..940537077 --- /dev/null +++ b/rust/dynamips/src/phy/mod.rs @@ -0,0 +1,8 @@ +//! Physical layer stuff +//! +//! TODO MDIO/MII interface? +//! +//! # [PHY](https://en.wikipedia.org/wiki/Physical_layer): +//! * [Intel LXT970A](crate::phy::lxt970a) + +pub mod lxt970a; diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml new file mode 100644 index 000000000..1e7fbee24 --- /dev/null +++ b/rust/rustfmt.toml @@ -0,0 +1,2 @@ +use_small_heuristics = "Max" +max_width = 300 diff --git a/stable/CMakeLists.txt b/stable/CMakeLists.txt index c907da32c..0dfa87ede 100644 --- a/stable/CMakeLists.txt +++ b/stable/CMakeLists.txt @@ -233,7 +233,6 @@ set ( _files "${COMMON}/fs_fat.c" "${COMMON}/fs_mbr.c" "${COMMON}/fs_nvram.c" - "${COMMON}/dev_lxt970a.c" ) if ( ENABLE_LINUX_ETH ) set ( _files ${_files} "${COMMON}/linux_eth.c" ) diff --git a/unstable/CMakeLists.txt b/unstable/CMakeLists.txt index 76e7ba03d..e0b019614 100644 --- a/unstable/CMakeLists.txt +++ b/unstable/CMakeLists.txt @@ -188,7 +188,6 @@ set ( _files "${COMMON}/fs_fat.c" "${COMMON}/fs_mbr.c" "${COMMON}/fs_nvram.c" - "${COMMON}/dev_lxt970a.c" ) if ( ENABLE_LINUX_ETH ) set ( _files ${_files} "${COMMON}/linux_eth.c" )