├── .gitignore ├── cleanup ├── Makefile ├── cleanup.sh └── ccmtcnvt.c ├── dkms.conf ├── docs ├── vendor-drop-import.md ├── dkms.md ├── branches.md └── vendor-diffs.md ├── QT2025_phy_Linux.c ├── TLK10232_phy_Linux.c ├── CX4_Linux.c ├── mvidtoh.sh ├── CX4.c ├── AQR105_phy_Linux.c ├── README.md ├── MV88X3310_phy_Linux.c ├── QT2025_phy.c ├── Makefile ├── release_notes ├── MV88X3120_phy_Linux.c ├── MV88X3120_phy.c ├── TLK10232_phy.h ├── TLK10232_phy.c ├── AQR105_phy.c ├── MV88X3310_phy.c └── tn40.h /.gitignore: -------------------------------------------------------------------------------- 1 | tn40xx.ko 2 | tn40xx.mod.c 3 | tn40xx.mod 4 | Module.symvers 5 | modules.order 6 | ._RESUME_ 7 | *~ 8 | *.o 9 | *.o.cmd 10 | *.ko.cmd 11 | *.mod.cmd 12 | *.swp 13 | -------------------------------------------------------------------------------- /cleanup/Makefile: -------------------------------------------------------------------------------- 1 | PROG = ccmtcnvt 2 | CPPFLAGS := -D_POSIX_C_SOURCE=2 $(CPPFLAGS) 3 | CFLAGS := -Wall -std=c99 -pedantic -O2 $(CFLAGS) 4 | 5 | 6 | .PHONY: all 7 | all: $(PROG) Makefile 8 | 9 | %.o: %.c %.h Makefile 10 | $(COMPILE.c) $< -o $@ 11 | 12 | $(PROG): $(PROG).o 13 | $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< 14 | 15 | clean: 16 | rm $(PROG) *.o || true 17 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME=tn40xx 2 | PACKAGE_VERSION=linux-6.7.y-1 3 | BUILT_MODULE_NAME[0]="$PACKAGE_NAME" 4 | MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build KVERSION=${kernelver}" 5 | CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build KVERSION=${kernelver} clean" 6 | DEST_MODULE_LOCATION[0]=/extra 7 | REMAKE_INITRD=no 8 | AUTOINSTALL=yes 9 | -------------------------------------------------------------------------------- /docs/vendor-drop-import.md: -------------------------------------------------------------------------------- 1 | # How to add a vendor drop: 2 | - Check for new tarball on http://www.tehutinetworks.net/?t=drivers&L1=8&L2=12&L3=26 3 | - Download and extract tarball 4 | - Create a new empty branch with `git checkout --orphan vendor-drop/v0.3.XYZ` 5 | - Unstage any changes with `git reset --hard` 6 | - CAREFULLY clean out all left-over files: `git clean -fd` 7 | - Copy the extracted sources to the git repo. 8 | - Add all of it: `git add .` 9 | - Commit 10 | 11 | # How to run cleanup: 12 | - Start from the vendor-drop: `git checkout vendor-drop/v0.3.XYZ` 13 | - Create and Checkout the cleanup branch: `git checkout -b cleanup/v0.3.XYZ` 14 | - Merge master: `git merge --allow-unrelated-histories master` 15 | - Run cleanup: `LINDENT=~/linux/scripts/Lindent ./cleanup/cleanup.sh` 16 | -------------------------------------------------------------------------------- /docs/dkms.md: -------------------------------------------------------------------------------- 1 | introduction 2 | ============ 3 | Dynamic Kernel Module Support (DKMS) builds Linux kernel modules whose sources reside outside the kernel source tree. It automates rebuilding of such modules when a new kernel is installed. 4 | 5 | install 6 | ======= 7 | git clone -b release/linux-6.7.y-1 https://github.com/acooks/tn40xx-driver.git /usr/src/tn40xx-linux-6.7.y-1 8 | dkms add -m tn40xx -v linux-6.7.y-1 9 | 10 | build driver for current kernel 11 | =============================== 12 | dkms install -m tn40xx -v linux-6.7.y-1 13 | 14 | build driver for specific kernel version 15 | ======================================== 16 | dkms install -m tn40xx -v linux-6.7.y-1 -k [kernel_version] 17 | 18 | uninstall 19 | ========= 20 | This will remove module for all kernel versions 21 | 22 | dkms remove -m tn40xx -v linux-6.7.y-1 --all 23 | -------------------------------------------------------------------------------- /QT2025_phy_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int QT2025_get_link_ksettings(struct net_device *netdev, 4 | struct ethtool_link_ksettings *cmd) 5 | { 6 | struct bdx_priv *priv = netdev_priv(netdev); 7 | 8 | cmd->base.speed = 9 | (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT) ? priv->link_speed 10 | : 0; 11 | cmd->base.port = PORT_FIBRE; 12 | cmd->base.autoneg = AUTONEG_DISABLE; 13 | cmd->base.duplex = DUPLEX_FULL; 14 | 15 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 16 | cmd->link_modes.supported); 17 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, cmd->link_modes.supported); 18 | __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, cmd->link_modes.supported);; 19 | memcpy(cmd->link_modes.advertising, cmd->link_modes.supported, 20 | sizeof(cmd->link_modes.advertising)); 21 | 22 | return 0; 23 | } 24 | 25 | int QT2025_set_link_ksettings(struct net_device *netdev, 26 | const struct ethtool_link_ksettings *cmd) 27 | { 28 | netdev_err(netdev, "Does not support ethtool -s option\n"); 29 | return -EPERM; 30 | } 31 | 32 | __init void QT2025_register_settings(struct bdx_priv *priv) 33 | { 34 | priv->phy_ops.get_link_ksettings = QT2025_get_link_ksettings; 35 | priv->phy_ops.set_link_ksettings = QT2025_set_link_ksettings; 36 | } 37 | -------------------------------------------------------------------------------- /TLK10232_phy_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int TLK10232_get_link_ksettings(struct net_device *netdev, 4 | struct ethtool_link_ksettings *cmd) 5 | { 6 | struct bdx_priv *priv = netdev_priv(netdev); 7 | 8 | cmd->base.speed = 9 | (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT) ? priv->link_speed 10 | : 0; 11 | cmd->base.port = PORT_FIBRE; 12 | cmd->base.autoneg = AUTONEG_DISABLE; 13 | cmd->base.duplex = DUPLEX_FULL; 14 | 15 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 16 | cmd->link_modes.supported); 17 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, cmd->link_modes.supported); 18 | __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, cmd->link_modes.supported);; 19 | memcpy(cmd->link_modes.advertising, cmd->link_modes.supported, 20 | sizeof(cmd->link_modes.advertising)); 21 | 22 | return 0; 23 | } 24 | 25 | int TLK10232_set_link_ksettings(struct net_device *netdev, 26 | const struct ethtool_link_ksettings *cmd) 27 | { 28 | netdev_err(netdev, "Does not support ethtool -s option\n"); 29 | 30 | return -EPERM; 31 | } 32 | 33 | __init void TLK10232_register_settings(struct bdx_priv *priv) 34 | { 35 | priv->phy_ops.get_link_ksettings = TLK10232_get_link_ksettings; 36 | priv->phy_ops.set_link_ksettings = TLK10232_set_link_ksettings; 37 | } 38 | -------------------------------------------------------------------------------- /CX4_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int CX4_get_link_ksettings(struct net_device *netdev, 4 | struct ethtool_link_ksettings *cmd) 5 | { 6 | struct bdx_priv *priv = netdev_priv(netdev); 7 | 8 | cmd->base.speed = 9 | (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT) ? priv->link_speed 10 | : 0; 11 | cmd->base.port = PORT_AUI; 12 | cmd->base.autoneg = AUTONEG_DISABLE; 13 | cmd->base.duplex = DUPLEX_FULL; 14 | 15 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 16 | cmd->link_modes.supported); 17 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, cmd->link_modes.supported); 18 | __set_bit(ETHTOOL_LINK_MODE_AUI_BIT, cmd->link_modes.supported);; 19 | 20 | memcpy(cmd->link_modes.advertising, cmd->link_modes.supported, 21 | sizeof(cmd->link_modes.advertising)); 22 | 23 | return 0; 24 | } 25 | 26 | int CX4_set_link_ksettings(struct net_device *netdev, 27 | const struct ethtool_link_ksettings *cmd) 28 | { 29 | pr_err("CX4_set_link_ksettings() not implemented\n"); 30 | 31 | return -EPERM; 32 | } 33 | 34 | __init void CX4_register_settings(struct bdx_priv *priv) 35 | { 36 | priv->phy_ops.get_link_ksettings = CX4_get_link_ksettings; 37 | priv->phy_ops.set_link_ksettings = CX4_set_link_ksettings; 38 | priv->autoneg = AUTONEG_DISABLE; 39 | } 40 | -------------------------------------------------------------------------------- /mvidtoh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Version 0.2, 2017/11/05 4 | # Support for AQR105 FW conversion added 5 | 6 | # Version 0.1, 2017/10/15 7 | # Initial release 8 | 9 | if [ $# -ne 3 ]; then 10 | echo "Usage: mvidtoh.sh " 11 | exit 1 12 | fi 13 | 14 | HDR_FILE=$1 15 | PHY_NAME=$2 16 | H_FILE=$3 17 | 18 | if [ ! -e $HDR_FILE ]; then 19 | echo "mvidtoh: HDR file $HDR_FILE not found" 20 | exit 1 21 | fi 22 | 23 | if [ $PHY_NAME != "MV88X3120" ] && [ $PHY_NAME != "MV88X3310" ] && [ $PHY_NAME != "MV88E2010" ] && [ $PHY_NAME != "AQR105" ]; then 24 | echo "mvidtoh: PHY $PHY_NAME not supported. Expecting one of AQR105, MV88X3120, MV88X3310 or MV88E2010" 25 | exit 1 26 | fi 27 | 28 | len=`xxd -i $HDR_FILE | grep _len | awk '{print $5}'` 29 | 30 | /bin/rm -f $H_FILE 31 | echo "" > $H_FILE 32 | echo "#ifndef _${PHY_NAME}_PHY_H" >> $H_FILE 33 | echo "#define _${PHY_NAME}_PHY_H" >> $H_FILE 34 | echo "" >> $H_FILE 35 | 36 | if [ $PHY_NAME == "AQR105" ]; then 37 | echo "unsigned int ${PHY_NAME}_phy_firmware_len = ${len}" >> $H_FILE 38 | echo "static u8 ${PHY_NAME}_phy_firmware[] __initdata = {" >> $H_FILE 39 | echo "/* $HDR_FILE */" >> $H_FILE 40 | xxd -i -c 8 $HDR_FILE | grep -v "unsigned" >> $H_FILE 41 | echo "#endif" >> $H_FILE 42 | else 43 | echo "static u16 ${PHY_NAME}_phy_initdata[] __initdata = {" >> $H_FILE 44 | echo "/* $HDR_FILE */" >> $H_FILE 45 | xxd -i -c 2 $HDR_FILE | sed 's/, 0x//' | grep -v "unsigned" >> $H_FILE 46 | echo "unsigned int ${PHY_NAME}_phy_initdata_len = ${len}" >> $H_FILE 47 | echo "#endif" >> $H_FILE 48 | fi 49 | 50 | exit 0 51 | -------------------------------------------------------------------------------- /CX4.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | #define LINK_LOOP_MAX (10) 4 | 5 | void CX4_register_settings(struct bdx_priv *priv); 6 | int CX4_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 7 | u32 CX4_link_changed(struct bdx_priv *priv); 8 | void CX4_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 9 | 10 | int CX4_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy) 11 | { 12 | 13 | return 0; 14 | 15 | } 16 | 17 | u32 CX4_link_changed(struct bdx_priv *priv) 18 | { 19 | u32 link = 0; 20 | 21 | if (priv->link_speed != SPEED_10000) { 22 | bdx_speed_changed(priv, SPEED_10000); 23 | } 24 | link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; 25 | if (link) { 26 | link = SPEED_10000; 27 | pr_debug("CX4 link speed is 10G\n"); 28 | } else { 29 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 30 | pr_debug("CX4 MAC reset\n"); 31 | priv->link_speed = 0; 32 | priv->link_loop_cnt = 0; 33 | } 34 | pr_debug("CX4 no link, setting 1/5 sec timer\n"); 35 | WRITE_REG(priv, 0x5150, 1000000); /* 1/5 sec timeout */ 36 | } 37 | 38 | return link; 39 | 40 | } 41 | 42 | void CX4_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 43 | { 44 | switch (op) { 45 | case PHY_LEDS_SAVE: 46 | break; 47 | 48 | case PHY_LEDS_RESTORE: 49 | break; 50 | 51 | case PHY_LEDS_ON: 52 | break; 53 | 54 | case PHY_LEDS_OFF: 55 | break; 56 | 57 | default: 58 | pr_debug("CX4_leds() unknown op 0x%x\n", op); 59 | break; 60 | 61 | } 62 | 63 | } 64 | 65 | __init enum PHY_TYPE CX4_register(struct bdx_priv *priv) 66 | { 67 | priv->phy_ops.mdio_reset = CX4_mdio_reset; 68 | priv->phy_ops.link_changed = CX4_link_changed; 69 | priv->phy_ops.ledset = CX4_leds; 70 | CX4_register_settings(priv); 71 | 72 | return PHY_TYPE_CX4; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /docs/branches.md: -------------------------------------------------------------------------------- 1 | # Branches 2 | 3 | Historically, this repo made extensive use of branches to organise the changes to the vendor driver. For example, 4 | - `vendor-drop/v0.3.6.14.3` 5 | - `cleanup/v0.3.6.14.3` 6 | - `topic/remove-linux-2.6-support` 7 | 8 | A description of the purpose of each type of branch follows. 9 | 10 | ## Develop branch 11 | 12 | Like many git projects, the `develop` branch is the main trunk where most topic branches are based on and merge back to. 13 | 14 | ## Release branches 15 | 16 | The release branch name uses a simple monotonically increasing counter of the release number. 17 | 18 | Releases 001 to 004 were based on a combination of (vendor release + cleanups + topic work). 19 | 20 | Since there is no more vendor to produce further vendor releases, future releases of this driver can follow the more familiar git workflow where releases branch off `develop`. 21 | 22 | ## Topic branches 23 | 24 | Features, bugfixes and improvements towards mainline inclusion are developed on these branches. 25 | 26 | Topic branches used to be based on cleanup branches, and were merged together for a release, but can now follow the usual pattern of branching patterns. Most topic branches will branch from `develop` and merging back to `develop`. 27 | 28 | 29 | ## Vendor drop branches 30 | 31 | Vendor releases were imported from their distributed tarball into `vendor-drop/` branches. These branches provide access to the historical unmodified driver, as well as reference between vendor branches. 32 | 33 | 34 | ## Cleanup branches 35 | 36 | Ignoring the Linux kernel style prevents this driver from being included in the mainline kernel. 37 | 38 | The intention of the `cleanup/` branches is to transform the vendor code into a better format that addresses the problems with the code style used by the vendor. 39 | 40 | Some specific problems are: 41 | - mixed tabs and spaces look horrible unless tab-width is 4 42 | - trailing whitespace 43 | - mixed C-style and C++ style comments 44 | - single lines of commented code smells 45 | - long lines 46 | 47 | 48 | The cleanup transformation MUST: 49 | - be logically equivalent to the vendor code 50 | - follow an automatable, repeatable process 51 | - involve low human effort 52 | - make progress towards an 'upstreamable' driver 53 | 54 | 55 | To apply the cleanup changes, run: `cleanup.sh` 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/vendor-diffs.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes between vendor releases 3 | 4 | The vendor provides [release_notes](release_notes), Sometimes additional information comes to light when comparing the cleaned-up branches - that's where these review notes may help. 5 | 6 | To generate the diff, use something like this: 7 | ``` 8 | git diff -D cleanup/v0.3.6.15 cleanup/v0.3.6.16.1 9 | ``` 10 | 11 | ## vendor-drop/v0.3.6.17.1 12 | - Fix compilation error under RHEL 8 13 | - Change default installation folder as required by RHEL 8 14 | - Fix kernel 4.20 compilation error (deprecated ethtool_ops.[gs]et_settings) 15 | 16 | ## vendor-drop/v0.3.6.17 17 | - AQR105 PHY firmware blob updated from v2.b.e-798 to v2.c.7-880 18 | - Add QNAP's TN9710P SVID/SDID (uses MV88X3310 PHY) 19 | - Add LR-Link LREC6860BT SVID/SDID (uses MV88X3310 PHY) 20 | - Add LR-Link LREC6860AF SVID/SDID (uses TLK10232 PHY) 21 | - QNAP LED support to MV88X3310 PHY driver 22 | - Bump expected MV88E2010 and MV88X3310 firmware blob version from `0_3_3_0_9374` to `0_3_4_0_9445` 23 | - PCI IRQ MSI initialisation changed 24 | - Add device shutdown callback 25 | 26 | ## vendor-drop/v0.3.6.16-startech 27 | - Startech OEM driver contains Marvell firmware files missing from vendor-drop/v0.3.6.16. 28 | 29 | ## vendor-drop/v0.3.6.16 30 | - AQR105 PHY firmware updated from XXX to 2.b.e2 31 | - Add SVID/SDID for [IOI GE10-PCIE4XG202](http://www.ioi.com.tw/products/prodcat_device.aspx?CatID=106&DeviceID=3035&HostID=2069) OEM products. They're using _Marvell MV88X3310 PHYs_, so Linux support may be a challenge. 32 | 33 | ## vendor-drop/v0.3.6.15 34 | - The Marvell PHY control that was removed in 0.3.6.14.3 has reappeared (without the required firmware/initialisation data blobs!) and the 'Marvell' name has been replaced with 'Pele' for what could only be trademark lawyer nonsense. 35 | - Added support for "Mustang-200 10GbE Ethernet Adapter" 36 | - More magical _Mike fix_ copy pasta 37 | - Some timer cruft was removed 38 | 39 | Plus vendor's release_notes: 40 | - New build method for Marvell PHYs. Please consult the Readme file 41 | - Improved startup procudure for "Phyless" CX4 mode 42 | - Dynamic advertising of MACA for RX flow control 43 | - Support for IEI SVID/SDID added 44 | - Improved memory allocation for memory limited or fragmented applications 45 | 46 | ## vendor-drop/v0.3.6.14.3 47 | - Removed support for Marvell PHYs, which removes support for the following NICs: 48 | - "TN9210 10GBase-T Ethernet Adapter" 49 | - "TN9710P 10GBase-T/NBASE-T Ethernet Adapter" 50 | - "TN9710Q 5GBase-T/NBASE-T Ethernet Adapter" 51 | - "Edimax 10 Gigabit Ethernet PCI Express Adapter" 52 | - "Buffalo LGY-PCIE-MG Ethernet Adapter" 53 | 54 | Plus the following claims from the vendors release_notes: 55 | - Fix RX Flow Control 56 | - Fix ethtool mtu on Ubuntu 17.04 57 | - Improve single PHY build code 58 | - Fix compilation error for CentOS 7.4 59 | - Fix missing PCP bits in VLAN tag 60 | 61 | ## vendor-drop/v0.3.6.14.1 62 | - First import; see release_notes for history. 63 | -------------------------------------------------------------------------------- /AQR105_phy_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int AQR105_set_speed(struct bdx_priv *priv, s32 speed); 4 | 5 | #define AQR105_ALL_SPEEDS (__ETHTOOL_LINK_MODE_MASK_NBITS) 6 | 7 | static void AQR105_set_link_mode(unsigned long *bits, u32 speed) 8 | { 9 | bitmap_zero(bits, __ETHTOOL_LINK_MODE_MASK_NBITS); 10 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, bits); 11 | __set_bit(ETHTOOL_LINK_MODE_TP_BIT, bits);; 12 | if (speed == AQR105_ALL_SPEEDS) { 13 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, bits); 14 | __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, bits); 15 | __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, bits); 16 | __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, bits); 17 | __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, bits); 18 | __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, bits); 19 | } else { 20 | __set_bit(speed, bits); 21 | } 22 | 23 | } 24 | 25 | int AQR105_get_link_ksettings(struct net_device *netdev, 26 | struct ethtool_link_ksettings *cmd) 27 | { 28 | struct bdx_priv *priv = netdev_priv(netdev); 29 | 30 | cmd->base.speed = priv->link_speed; 31 | cmd->base.port = PORT_TP; 32 | cmd->base.autoneg = AUTONEG_ENABLE; 33 | cmd->base.duplex = DUPLEX_FULL; 34 | 35 | #if defined(ETH_TP_MDI_AUTO) 36 | cmd->base.eth_tp_mdix = ETH_TP_MDI_AUTO; 37 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; 38 | #else 39 | cmd->base.eth_tp_mdix = ETH_TP_MDI | ETH_TP_MDI_X; 40 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI | ETH_TP_MDI_X; 41 | #endif 42 | AQR105_set_link_mode(cmd->link_modes.supported, AQR105_ALL_SPEEDS); 43 | 44 | if (priv->autoneg == AUTONEG_ENABLE) { 45 | memcpy(priv->link_advertising, cmd->link_modes.supported, 46 | sizeof(priv->link_advertising)); 47 | } 48 | memcpy(cmd->link_modes.advertising, priv->link_advertising, 49 | sizeof(cmd->link_modes.advertising)); 50 | 51 | return 0; 52 | } 53 | 54 | int AQR105_set_link_ksettings(struct net_device *netdev, 55 | const struct ethtool_link_ksettings *cmd) 56 | { 57 | struct bdx_priv *priv = netdev_priv(netdev); 58 | int rVal = 0; 59 | 60 | priv->autoneg = cmd->base.autoneg; 61 | if (priv->autoneg == AUTONEG_ENABLE) { 62 | AQR105_set_link_mode(priv->link_advertising, AQR105_ALL_SPEEDS); 63 | } else { 64 | switch (cmd->base.speed) { 65 | case 10000: /*10G */ 66 | AQR105_set_link_mode(priv->link_advertising, 67 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT); 68 | break; 69 | 70 | case 5000: /*5G */ 71 | AQR105_set_link_mode(priv->link_advertising, 72 | ETHTOOL_LINK_MODE_5000baseT_Full_BIT); 73 | break; 74 | 75 | case 2500: /*2.5G */ 76 | AQR105_set_link_mode(priv->link_advertising, 77 | ETHTOOL_LINK_MODE_2500baseT_Full_BIT); 78 | break; 79 | 80 | case 1000: /*1G */ 81 | AQR105_set_link_mode(priv->link_advertising, 82 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT); 83 | break; 84 | 85 | case 100: /*100m */ 86 | AQR105_set_link_mode(priv->link_advertising, 87 | ETHTOOL_LINK_MODE_100baseT_Full_BIT); 88 | break; 89 | 90 | default: 91 | pr_err("does not support speed %u\n", cmd->base.speed); 92 | rVal = -EINVAL; 93 | break; 94 | } 95 | } 96 | if (rVal == 0) { 97 | rVal = AQR105_set_speed(priv, cmd->base.speed); 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | __init void AQR105_register_settings(struct bdx_priv *priv) 104 | { 105 | priv->phy_ops.get_link_ksettings = AQR105_get_link_ksettings; 106 | priv->phy_ops.set_link_ksettings = AQR105_set_link_ksettings; 107 | priv->autoneg = AUTONEG_ENABLE; 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | This repo contains the tn40xx Linux driver for 10Gbit NICs based on the TN4010 MAC from the (now defunct) Tehuti Networks. 3 | 4 | This driver enables the following 10Gb SFP+ NICs: 5 | - D-Link DXE-810S 6 | - Edimax EN-9320SFP+ 7 | - StarTech PEX10000SFP 8 | - Synology E10G15-F1 9 | 10 | ... as well as the following 10GBase-T/NBASE-T NICs: 11 | - D-Link DXE-810T 12 | - Edimax EN-9320TX-E 13 | - EXSYS EX-6061-2 14 | - Intellinet 507950 15 | - StarTech ST10GSPEXNB 16 | 17 | This repo aims to: 18 | - slowly transform the driver into a potentially upstreamable state 19 | - make it easily downloadable for Linux distributions and build systems 20 | 21 | The older TN3020-D (Luxor) processor has a mainline Linux driver, but that driver doesn't support the TN40xx (Bordeaux) devices. 22 | 23 | # Problematic NICs 24 | 25 | If you have a NIC that combines the tn40xx MAC with a Marvell PHY, you will have to go on a quest to obtain the firmware for the PHY. It cannot be distributed or supported by this driver, because Marvell has not permitted redistribution of the firmware. 26 | 27 | ## How to tell if you have an unsopported PHY 28 | ``` 29 | lspci -vnn 30 | ``` 31 | 32 | will output something like this: 33 | 34 | ``` 35 | 0a:00.0 Ethernet controller [0200]: Tehuti Networks Ltd. TN9210 10GBase-T Ethernet Adapter [1fc9:4024] 36 | Subsystem: Tehuti Networks Ltd. Device [1fc9:3015] 37 | ``` 38 | 39 | In the example above, 0x1fc9 is the Vendor ID and 0x4024 is the Device ID. 0x3015 is the Subsystem Device ID. 40 | 41 | The problematic devices are identified by these combinations of Device ID and Subsystem Device ID: 42 | - 4024, 3015 "TN9210 10GBase-T Ethernet Adapter", 43 | - 4027, 3015 "TN9710P 10GBase-T/NBASE-T Ethernet Adapter", 44 | - 4027, 8104 "Edimax 10 Gigabit Ethernet PCI Express Adapter", 45 | - 4027, 0368 "Buffalo LGY-PCIE-MG Ethernet Adapter", 46 | - 4027, 1546 "IOI GE10-PCIE4XG202P 10Gbase-T/NBASE-T Ethernet Adapter", 47 | - 4027, 1001 "LR-Link LREC6860BT 10 Gigabit Ethernet Adapter", 48 | - 4027, 3310 "QNAP PCIe Expansion Card", 49 | - 4527, 3015 "TN9710Q 5GBase-T/NBASE-T Ethernet Adapter" 50 | 51 | 52 | # Problematic Kernel versions 53 | 54 | Occasionally people ask for help with old kernels, or kernels based on Enterprise Linux distributions. Unfortunately, this is something that is difficult for me (Andrew) to help with. I haven't got the time, and I believe that Enterprise Linux vendors should be providing this support, and be paid for it. Please seek help from the vendor of the Enterprise Linux distribution, or consider whether your needs and interests may be better aligned with an up-to-date community-supported distribution. 55 | 56 | # Install 57 | 58 | While upstreaming is the ultimate goal of this project, some systems already rely on this driver. For such systems, DKMS provides a convenient way to install and update the driver, [See DKMS instructions](docs/dkms.md). 59 | 60 | # Branches 61 | 62 | This repo contains several long-lived branches. You may have to look around for support for the kernel version and PHY that you have. 63 | - `release/linux-6.7.y-1` --> 6.7.x <= Linux 64 | - `release/linux-6.6.y-1` --> 6.6.x <= Linux < 6.8 65 | - `release/tn40xx-006` --> 5.15.x <= Linux < 6.8 66 | - `release/tn40xx-004` --> 5.4 < Linux < 5.15 67 | - `release/tn40xx-003` --> Linux <= 5.4 68 | - `vendor-drop/v0.3.6.17` 69 | 70 | More detail on branching in [described in the documentation](docs/branches.md). 71 | 72 | # Thanks 73 | 74 | To the following people who have contributed to this project - thank you! 75 | - Jean-Christophe Heger 76 | - Nickolai Zeldovich 77 | - Patrick Heffernan 78 | - Carsten Heinz 79 | 80 | # Origin 81 | 82 | A tn40xx driver was distributed by Tehuti Networks under GPLv2 license, as well as various OEM vendors, like those listed above. 83 | 84 | The last release of the driver by Tehuti Networks was version 0.3.6.17.2, imported to this repo in commit 894992c904a6b0e99 on Jan 7 2020. 85 | 86 | On Jan 9 2020 a message was posted to Tehuti Networks' LinkedIn page, announcing that it has ceased operations. 87 | 88 | The original source releases have been preserved in unmodified state in the `vendor-drop/` branches. 89 | 90 | This repo does not claim any copyright over the original Tehuti Networks source code, but it has been significantly modified and continues to evolve and hopefully improve. 91 | -------------------------------------------------------------------------------- /MV88X3310_phy_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int MV88X3310_set_speed(struct bdx_priv *priv, s32 speed); 4 | 5 | #define MV88X3310_ALL_SPEEDS (__ETHTOOL_LINK_MODE_MASK_NBITS) 6 | 7 | static void MV88X3310_set_link_mode(unsigned long *bits, u32 speed) 8 | { 9 | bitmap_zero(bits, __ETHTOOL_LINK_MODE_MASK_NBITS); 10 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, bits); 11 | __set_bit(ETHTOOL_LINK_MODE_TP_BIT, bits);; 12 | if (speed == MV88X3310_ALL_SPEEDS) { 13 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, bits); 14 | __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, bits); 15 | __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, bits); 16 | __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, bits); 17 | __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, bits); 18 | __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, bits); 19 | } else { 20 | __set_bit(speed, bits); 21 | } 22 | 23 | } 24 | 25 | int MV88X3310_get_link_ksettings(struct net_device *netdev, 26 | struct ethtool_link_ksettings *cmd) 27 | { 28 | struct bdx_priv *priv = netdev_priv(netdev); 29 | 30 | cmd->base.speed = priv->link_speed; 31 | cmd->base.port = PORT_TP; 32 | cmd->base.autoneg = AUTONEG_ENABLE; 33 | cmd->base.duplex = DUPLEX_FULL; 34 | #if defined(ETH_TP_MDI_AUTO) 35 | cmd->base.eth_tp_mdix = ETH_TP_MDI_AUTO; 36 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; 37 | #else 38 | cmd->base.eth_tp_mdix = ETH_TP_MDI | ETH_TP_MDI_X; 39 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI | ETH_TP_MDI_X; 40 | #endif 41 | MV88X3310_set_link_mode(cmd->link_modes.supported, 42 | MV88X3310_ALL_SPEEDS); 43 | 44 | if (priv->autoneg == AUTONEG_ENABLE) { 45 | memcpy(priv->link_advertising, cmd->link_modes.supported, 46 | sizeof(priv->link_advertising)); 47 | } 48 | memcpy(cmd->link_modes.advertising, priv->link_advertising, 49 | sizeof(cmd->link_modes.advertising)); 50 | 51 | return 0; 52 | } 53 | 54 | int MV88X3310_set_link_ksettings(struct net_device *netdev, 55 | const struct ethtool_link_ksettings *cmd) 56 | { 57 | struct bdx_priv *priv = netdev_priv(netdev); 58 | int rVal = 0; 59 | 60 | priv->autoneg = cmd->base.autoneg; 61 | if (priv->autoneg == AUTONEG_ENABLE) { 62 | MV88X3310_set_link_mode(priv->link_advertising, 63 | MV88X3310_ALL_SPEEDS); 64 | } else { 65 | switch (cmd->base.speed) { 66 | case 10000: /*10G */ 67 | MV88X3310_set_link_mode(priv->link_advertising, 68 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT); 69 | break; 70 | 71 | case 5000: /*5G */ 72 | MV88X3310_set_link_mode(priv->link_advertising, 73 | ETHTOOL_LINK_MODE_5000baseT_Full_BIT); 74 | break; 75 | 76 | case 2500: /*2.5G */ 77 | MV88X3310_set_link_mode(priv->link_advertising, 78 | ETHTOOL_LINK_MODE_2500baseT_Full_BIT); 79 | break; 80 | 81 | case 1000: /*1G */ 82 | MV88X3310_set_link_mode(priv->link_advertising, 83 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT); 84 | break; 85 | 86 | case 100: /*100m */ 87 | MV88X3310_set_link_mode(priv->link_advertising, 88 | ETHTOOL_LINK_MODE_100baseT_Full_BIT); 89 | break; 90 | 91 | default: 92 | pr_err("does not support speed %u\n", cmd->base.speed); 93 | rVal = -EINVAL; 94 | break; 95 | } 96 | } 97 | if (rVal == 0) { 98 | rVal = MV88X3310_set_speed(priv, cmd->base.speed); 99 | } 100 | 101 | return 0; 102 | } 103 | 104 | /* EEE - IEEEaz */ 105 | 106 | #ifdef _EEE_ 107 | #ifdef ETHTOOL_GEEE 108 | int MV88X3310_get_eee(struct net_device *netdev, struct ethtool_eee *edata) 109 | { 110 | pr_err("EEE is not implemented yet\n"); 111 | return -1; 112 | } 113 | #endif 114 | 115 | #ifdef ETHTOOL_SEEE 116 | int MV88X3310_set_eee(struct bdx_priv *priv) 117 | { 118 | pr_err("EEE is not implemented yet\n"); 119 | return -1; 120 | } 121 | #endif 122 | 123 | int MV88X3310_reset_eee(struct bdx_priv *priv) 124 | { 125 | pr_err("EEE is not implemented yet\n"); 126 | return -1; 127 | } 128 | 129 | #endif 130 | 131 | __init void MV88X3310_register_settings(struct bdx_priv *priv) 132 | { 133 | priv->phy_ops.get_link_ksettings = MV88X3310_get_link_ksettings; 134 | priv->phy_ops.set_link_ksettings = MV88X3310_set_link_ksettings; 135 | priv->autoneg = AUTONEG_ENABLE; 136 | #ifdef _EEE_ 137 | #ifdef ETHTOOL_GEEE 138 | priv->phy_ops.get_eee = MV88X3310_get_eee; 139 | #endif 140 | #ifdef ETHTOOL_SEEE 141 | priv->phy_ops.set_eee = MV88X3310_set_eee; 142 | #endif 143 | priv->phy_ops.reset_eee = MV88X3310_reset_eee; 144 | #endif 145 | } 146 | -------------------------------------------------------------------------------- /cleanup/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Use the kernel's scripts/Lindent utility 6 | if [ -z "$LINDENT" -o ! -x "$LINDENT" ] ; then 7 | echo " You need to set the LINDENT environment variable to specify where the Lindent script is (Hint: in the kernel sources at scripts/Lindent)" 8 | exit 1 9 | fi 10 | 11 | # Run Lindent at the start of cleanup, so that the regexes below are applied to 12 | # a predictable style of code. 13 | # Run Lindent twice, because the operation is unfortunately not idempotent 14 | # after only a single run (but is after two runs). 15 | ${LINDENT} *.c *.h ; ${LINDENT} *.c *.h 16 | 17 | # Trim trailing whitespace 18 | sed -i 's|\s*$||g' *.c *.h 19 | 20 | 21 | # build 'ccmtcnvt' for converting C++ comments into C comments. 22 | # (unfortunately it doesn't fix C++ comments inside C comments) 23 | make -C cleanup 24 | 25 | for f in *.c *.h ; do 26 | mv $f $f~ 27 | cleanup/ccmtcnvt $f~ > $f 28 | done 29 | 30 | 31 | # remove horizontal line breaks like /* ------ */ 32 | sed -i 's|/\*\s*---*---*\s*\*/||g' *.c 33 | 34 | 35 | # remove comments after the closing function brace, like } /* foo() */ 36 | sed -i 's|\s*}\s*/\*.*\*/|}|g' *.c 37 | 38 | 39 | # remove the use of the ENTER macro 40 | sed -i 's|\s*ENTER\s*;||g' *.c 41 | # remove the definition of the ENTER macro 42 | sed -i 's|.*#define\s\+ENTER.*||' *.h 43 | 44 | 45 | # remove the use of the EXIT macro 46 | sed -i 's|\s*EXIT\s*;||g' *.c 47 | # remove the definition of the EXIT macro 48 | sed -i 's|.*#define\s\+EXIT.*||' *.h 49 | 50 | 51 | # remove the use of the RET() macro 52 | sed -i 's|\(\s\+\)RET(\(.*\));|\1return \2;|' *.c 53 | # remove the definition of the RET() macro 54 | sed -i 's|.*#define\s\+RET\(.*\).*||' *.h 55 | 56 | 57 | # remove dead code disguised as comments 58 | # weed out function calls first 59 | sed -i 's|/\*\s*.*(.*);.*\*/||g' *.c *.h 60 | # weed out assignments involving struct members 61 | sed -i 's|/\*\s*.*\..*=.*;.*\*/||g' *.c *.h 62 | sed -i 's|/\*\s*.*->.*=.*;.*\*/||g' *.c *.h 63 | sed -i 's|/\*\s*.*=.*->.*;.*\*/||g' *.c *.h 64 | 65 | 66 | # remove unused g_ftrace variable 67 | sed -i 's|\(.*g_ftrace.*\)||g' *.{c,h} 68 | 69 | 70 | # remove unused DBG1 macro 71 | sed -i 's|\(#define DBG1.*\)||g' tn40.h 72 | # confirm that it really is unsused and gone 73 | (! grep -Iq DBG1 *.{c,h}) || (echo 'unexpected DBG1 macro remaining.' && false) 74 | 75 | 76 | # remove redundant return at end of void functions 77 | # look for one level of tab indentation to determine function scope, instead of 78 | # early returns from block scope. It's ugly, but semantically-important 79 | # whitespace works for python and Lindent ensures that the indentation is 80 | # consistent here. 81 | sed -i 's|^\treturn\s*;.*||g' *.c 82 | 83 | 84 | # remove unused FTRACE_ON and FTRACE_OFF macros 85 | sed -i 's|#define FTRACE_ON$||g' *.c *.h 86 | sed -i 's|#define FTRACE_OFF$||g' *.c *.h 87 | # For these multi-line matches, it's much simpler to use perl... 88 | # remove empty TN40_FTRACE block 89 | perl -0777 -i -pe 's|#if defined\(TN40_FTRACE\)\s*\n*\s*#endif||g' *.c *.h 90 | # remove empty FTRACE block 91 | perl -0777 -i -pe 's|#if defined\(FTRACE\)\s*\n*\s*#endif||g' *.c *.h 92 | # remove empty FTRACE with empty else block 93 | perl -0777 -i -pe 's|#if defined\(FTRACE\)\s*\n*\s*#else\s*\n*\s*#endif||g' *.c *.h 94 | # finally, remove the unused FTRACE definition 95 | sed -i 's|#define FTRACE||g' *.c *.h 96 | # remove the comment 97 | sed -i 's|/\*\s*F T R A C E\s*\*/||g' *.c *.h 98 | 99 | 100 | # remove \r characters. 101 | sed -i 's|\r| |g' *.c *.h 102 | 103 | 104 | # rename DRB_OBJS to DRV_OBJS as in 0.3.16.15 105 | sed -i 's|DRB_OBJS|DRV_OBJS|g' Makefile 106 | 107 | # replace DBG(...) macro with pr_debug(...) 108 | sed -i 's|\(\s\+\)\(DBG(\)|\1pr_debug(|g' *.c 109 | sed -i 's|#define\(.*\)DBG$|#define\1pr_debug|g' *.c *.h 110 | # remove unused DBG macro 111 | sed -i 's|^\(#define\s\+DBG(.*\)||g' tn40.h 112 | 113 | # replace MSG(...) macro with pr_info(...) 114 | sed -i 's|\(\s\+\)\(MSG(\)|\1pr_info(|g' *.c 115 | # remove unused MSG macro 116 | sed -i 's|\(#define\s\+MSG(.*\)||g' tn40.h 117 | 118 | # remove unused ERR macro 119 | sed -i 's|\(#define\s\+ERR(.*\)||g' tn40.h 120 | # replace ERR(...) macro with pr_err(...) 121 | sed -i 's|\(\s\+\)\(ERR(\)|\1pr_err(|g' *.c *.h 122 | 123 | # remove redundant STRING_FMT macro 124 | sed -i 's|\#define\s\+STRING_FMT.*||g' tn40.h 125 | sed -i 's|" STRING_FMT "|%s|g' *.c *.h 126 | sed -i 's|STRING_FMT\s\+"|"%s|g' *.c *.h 127 | perl -0777 -i -pe 's|STRING_FMT\s*\n\s*"|"%s|g' *.c *.h 128 | 129 | # remove single line empty comments 130 | perl -0777 -i -pe 's|/\*\s*\*/\n||g' *.c *.h 131 | # remove inline empty comments 132 | sed -i 's|/\*\s*\*/||g' *.c *.h 133 | 134 | # Insert new cleanup steps above this comment. 135 | # Keep Lindent as the last step. 136 | 137 | # Run Lindent again at the end, because the regexes above affect the format. 138 | # Run Lindent twice, because the operation is unfortunately not idempotent 139 | # after only a single run (but is after two runs). 140 | ${LINDENT} *.c *.h ; ${LINDENT} *.c *.h 141 | 142 | -------------------------------------------------------------------------------- /QT2025_phy.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | #include "QT2025_phy.h" 3 | 4 | #define LINK_LOOP_MAX (10) 5 | 6 | void QT2025_register_settings(struct bdx_priv *priv); 7 | int QT2025_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 8 | u32 QT2025_link_changed(struct bdx_priv *priv); 9 | void QT2025_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 10 | 11 | static int QT2025_get_link_speed(struct bdx_priv *priv) 12 | { 13 | int speed; 14 | u16 module = 15 | (bdx_mdio_read(priv, 3, priv->phy_mdio_port, 0xD70C)) & 0xFF; 16 | 17 | switch (module) { 18 | case 5: 19 | case 6: 20 | case 8: 21 | case 9: 22 | speed = SPEED_1000; 23 | break; 24 | 25 | default: 26 | speed = SPEED_10000; 27 | break; 28 | 29 | } 30 | 31 | return speed; 32 | 33 | } 34 | 35 | __init int QT2025_mdio_reset(struct bdx_priv *priv, int port, 36 | unsigned short phy) 37 | { 38 | struct device *dev = &priv->pdev->dev; 39 | u16 *phy_fw = QT2025_phy_firmware, j, fwVer01, fwVer2, fwVer3, module; 40 | int s_fw, i, a; 41 | int phy_id = 0, rev = 0; 42 | 43 | phy_id = bdx_mdio_read(priv, 1, port, 0xD001); 44 | 45 | switch (0xFF & (phy_id >> 8)) { 46 | case 0xb3: 47 | rev = 0xd; 48 | s_fw = sizeof(QT2025_phy_firmware) / sizeof(u16); 49 | break; 50 | 51 | default: 52 | dev_err(dev, "PHY ID =0x%x, returning\n", 53 | (0xFF & (phy_id >> 8))); 54 | return 1; 55 | break; 56 | } 57 | switch (rev) { 58 | default: 59 | dev_err(dev, "bdx: failed unknown PHY ID %x\n", phy_id); 60 | return 1; 61 | break; 62 | 63 | case 0xD: 64 | BDX_MDIO_WRITE(priv, 1, 0xC300, 0x0000); 65 | BDX_MDIO_WRITE(priv, 1, 0xC302, 0x4); 66 | BDX_MDIO_WRITE(priv, 1, 0xC319, 0x0038); 67 | 68 | BDX_MDIO_WRITE(priv, 1, 0xC31A, 0x0098); 69 | BDX_MDIO_WRITE(priv, 3, 0x0026, 0x0E00); 70 | 71 | BDX_MDIO_WRITE(priv, 3, 0x0027, 0x0893); /*10G */ 72 | 73 | BDX_MDIO_WRITE(priv, 3, 0x0028, 0xA528); 74 | BDX_MDIO_WRITE(priv, 3, 0x0029, 0x03); 75 | BDX_MDIO_WRITE(priv, 1, 0xC30A, 0x06E1); 76 | BDX_MDIO_WRITE(priv, 1, 0xC300, 0x0002); 77 | BDX_MDIO_WRITE(priv, 3, 0xE854, 0x00C0); 78 | 79 | /* Dump firmware starting at address 3.8000 */ 80 | for (i = 0, j = 0x8000, a = 3; i < s_fw; i++, j++) { 81 | if (i == 0x4000) { 82 | a = 4; 83 | j = 0x8000; 84 | } 85 | if (phy_fw[i] < 0x100) { 86 | BDX_MDIO_WRITE(priv, a, j, phy_fw[i]); 87 | } 88 | } 89 | BDX_MDIO_WRITE(priv, 3, 0xE854, 0x0040); 90 | for (i = 60; i; i--) { 91 | msleep(50); 92 | j = bdx_mdio_read(priv, 3, port, 0xD7FD); 93 | if (!(j == 0x10 || j == 0)) { 94 | break; 95 | } 96 | } 97 | if (!i) { 98 | dev_err(dev, "PHY init error\n"); 99 | } 100 | break; 101 | } 102 | fwVer01 = bdx_mdio_read(priv, 3, port, 0xD7F3); 103 | fwVer2 = bdx_mdio_read(priv, 3, port, 0xD7F4); 104 | fwVer3 = bdx_mdio_read(priv, 3, port, 0xD7F5); 105 | module = bdx_mdio_read(priv, 3, port, 0xD70C); 106 | 107 | dev_info(dev, 108 | "QT2025 FW version %d.%d.%d.%d module type 0x%x\n", 109 | ((fwVer01 >> 4) & 0xf), (fwVer01 & 0xf), (fwVer2 & 0xff), 110 | (fwVer3 & 0xff), (u32) (module & 0xff)); 111 | 112 | priv->link_speed = QT2025_get_link_speed(priv); 113 | bdx_speed_set(priv, priv->link_speed); 114 | 115 | return 0; 116 | 117 | } 118 | 119 | /* 120 | * Module types: 121 | * 122 | 1 = 10GBASE-LRM 123 | 2 = 10GBASE-SR 124 | 3 = 10GBASE-LR 125 | 4 = SFP+ passive copper direct attach cable 126 | 5 = 1000BASE-SX 127 | 6 = 1000BASE-LX 128 | 7 = Invalid Module Type 129 | 8 = 1000BASE-CX (1GE copper cable) 130 | 9 = 1000BASE-T 131 | 10 (0xA) = 10GBASE-ER 132 | 11 (0xB) = SFP+ active copper direct attach cable 133 | >11 reserved for future use 134 | */ 135 | 136 | u32 QT2025_link_changed(struct bdx_priv *priv) 137 | { 138 | u32 link = 0; 139 | struct net_device *ndev = priv->ndev; 140 | 141 | priv->link_speed = QT2025_get_link_speed(priv); 142 | link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; 143 | if (link) { 144 | netdev_dbg(ndev, "QT2025 link speed is %s\n", 145 | (priv->link_speed == SPEED_10000) ? "10G" : "1G"); 146 | link = priv->link_speed; 147 | } else { 148 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 149 | netdev_dbg 150 | (ndev, 151 | "QT2025 trying to recover link after %d tries\n", 152 | LINK_LOOP_MAX); 153 | /* MAC reset */ 154 | bdx_speed_set(priv, 0); 155 | bdx_speed_set(priv, priv->link_speed); 156 | priv->link_loop_cnt = 0; 157 | } 158 | netdev_dbg(ndev, "QT2025 no link, setting 1/5 sec timer\n"); 159 | WRITE_REG(priv, 0x5150, 1000000); /* 1/5 sec timeout */ 160 | } 161 | 162 | return link; 163 | 164 | } 165 | 166 | void QT2025_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 167 | { 168 | switch (op) { 169 | case PHY_LEDS_SAVE: 170 | break; 171 | 172 | case PHY_LEDS_RESTORE: 173 | break; 174 | 175 | case PHY_LEDS_ON: 176 | WRITE_REG(priv, regBLNK_LED, 4); 177 | break; 178 | 179 | case PHY_LEDS_OFF: 180 | WRITE_REG(priv, regBLNK_LED, 0); 181 | break; 182 | 183 | default: 184 | netdev_dbg(priv->ndev, "QT2025_leds() unknown op 0x%x\n", op); 185 | break; 186 | 187 | } 188 | 189 | } 190 | 191 | __init enum PHY_TYPE QT2025_register(struct bdx_priv *priv) 192 | { 193 | priv->phy_ops.mdio_reset = QT2025_mdio_reset; 194 | priv->phy_ops.link_changed = QT2025_link_changed; 195 | priv->phy_ops.ledset = QT2025_leds; 196 | priv->phy_ops.mdio_speed = MDIO_SPEED_6MHZ; 197 | QT2025_register_settings(priv); 198 | 199 | return PHY_TYPE_QT2025; 200 | 201 | } 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # tn40xx_ Driver 3 | # 4 | # Makefile for the tx40xx Linux driver 5 | 6 | ####################################### 7 | # Build Configuration: 8 | ####################################### 9 | 10 | PWD := $(shell pwd) 11 | KVERSION ?= $(shell uname -r) 12 | EXPECTED_KDIR := /lib/modules/$(KVERSION)/build 13 | OLDINSTDIR := /lib/modules/$(KVERSION)/kernel/drivers/net 14 | INSTDIR := /lib/modules/$(KVERSION)/kernel/drivers/net/tehuti 15 | PM_DIR := /etc/pm/config.d 16 | RESUME_FILE := ._RESUME_ 17 | MODULE_DIR :=M=$(PWD) 18 | DRV_NAME := tn40xx 19 | JUMBO_OBJS := QT2025_phy.o QT2025_phy_Linux.o TLK10232_phy.o TLK10232_phy_Linux.o \ 20 | AQR105_phy.o AQR105_phy_Linux.o 21 | JUMBO_PHYS := -DPHY_QT2025 -DPHY_TLK10232 -DPHY_AQR105 -DPHY_MUSTANG 22 | 23 | DRV_NAME := tn40xx 24 | DRV_OBJS := tn40.o CX4.o CX4_Linux.o 25 | MV88X3120_HDR := 88X3140-FW-R02-06-03.hdr 26 | MV88X3120_H := MV88X3120_phy.h 27 | MV88X3310_HDR := x3310fw_0_3_4_0_9445.hdr 28 | MV88X3310_H := MV88X3310_phy.h 29 | MV88E2010_HDR := e2010fw_0_3_4_0_9445.hdr 30 | MV88E2010_H := MV88E2010_phy.h 31 | # 32 | # Jumbo options 33 | # 34 | ifneq ($(wildcard $(MV88X3120_HDR) $(MV88X3120_H)),) 35 | export JUMBO_MV88X3120 := YES 36 | endif 37 | ifeq ($(JUMBO_MV88X3120), YES) 38 | JUMBO_OBJS += MV88X3120_phy.o MV88X3120_phy_Linux.o 39 | JUMBO_PHYS += -DPHY_MV88X3120 40 | endif 41 | # 42 | ifneq ($(wildcard $(MV88X3310_HDR) $(MV88X3310_H)),) 43 | export JUMBO_MV88X3310 := YES 44 | endif 45 | ifeq ($(JUMBO_MV88X3310), YES) 46 | JUMBO_OBJS += MV88X3310_phy.o MV88X3310_phy_Linux.o 47 | JUMBO_PHYS += -DPHY_MV88X3310 48 | endif 49 | # 50 | ifneq ($(wildcard $(MV88E2010_HDR) $(MV88E2010_H)),) 51 | export JUMBO_MV88E2010 := YES 52 | endif 53 | ifeq ($(JUMBO_MV88E2010), YES) 54 | ifneq ($(JUMBO_MV88X3310), YES) 55 | JUMBO_OBJS += MV88X3310_phy.o MV88X3310_phy_Linux.o 56 | endif 57 | JUMBO_PHYS += -DPHY_MV88E2010 58 | endif 59 | # 60 | # Command line options 61 | # 62 | ifeq ($(MV88X3120),YES) 63 | DRV_OBJS += MV88X3120_phy.o MV88X3120_phy_Linux.o 64 | OPT_PHYS += -DPHY_MV88X3120 65 | endif 66 | # 67 | ifeq ($(MV88X3310),YES) 68 | DRV_OBJS += MV88X3310_phy.o MV88X3310_phy_Linux.o 69 | OPT_PHYS += -DPHY_MV88X3310 70 | endif 71 | # 72 | ifeq ($(MV88E2010),YES) 73 | DRV_OBJS += MV88X3310_phy.o MV88X3310_phy_Linux.o 74 | OPT_PHYS += -DPHY_MV88E2010 75 | endif 76 | # 77 | ifeq ($(QT),YES) 78 | DRV_OBJS += QT2025_phy.o QT2025_phy_Linux.o 79 | OPT_PHYS += -DPHY_QT2025 80 | endif 81 | # 82 | ifeq ($(TL),YES) 83 | DRV_OBJS += TLK10232_phy.o TLK10232_phy_Linux.o 84 | OPT_PHYS += -DPHY_TLK10232 85 | endif 86 | # 87 | ifeq ($(AQ),YES) 88 | DRV_OBJS += AQR105_phy.o AQR105_phy_Linux.o 89 | OPT_PHYS += -DPHY_AQR105 90 | endif 91 | # 92 | ifeq ($(MUSTANG),YES) 93 | OPT_PHYS += -DPHY_MUSTANG 94 | endif 95 | 96 | ifeq ($(EEE), YES) 97 | EXTRA_CFLAGS += -D_EEE_ 98 | endif 99 | # 100 | # No selected PHYs default to Jumbo driver 101 | # 102 | ifndef OPT_PHYS 103 | DRV_OBJS+= $(JUMBO_OBJS) 104 | EXTRA_CFLAGS += $(JUMBO_PHYS) 105 | else 106 | EXTRA_CFLAGS += $(OPT_PHYS) 107 | endif 108 | 109 | obj-m += $(DRV_NAME).o 110 | $(DRV_NAME)-objs := $(DRV_OBJS) 111 | 112 | # 113 | # Check existance of kernel build directory 114 | # 115 | KDIR=$(shell [ -e $(EXPECTED_KDIR) ] && echo $(EXPECTED_KDIR)) 116 | ifeq (,$(KDIR)) 117 | $(error Aborting the build: Linux kernel $(EXPECTED_KDIR) source not found) 118 | endif 119 | 120 | .PHONY: help clean install uninstall headers 121 | 122 | all: clean headers 123 | @echo Building kernel $(KVERSION) $(MAKE_MSG) 124 | $(MAKE) -C $(KDIR) $(MODULE_DIR) modules 125 | touch $(RESUME_FILE); \ 126 | 127 | headers: $(MV88X3120_H) $(MV88X3310_H) $(MV88E2010_H) 128 | 129 | $(MV88X3120_H): $(wildcard $(MV88X3120_HDR)) 130 | @if [ -f $(MV88X3120_HDR) ]; then \ 131 | echo Generating $(MV88X3120_H); \ 132 | ./mvidtoh.sh $(MV88X3120_HDR) MV88X3120 $(MV88X3120_H); \ 133 | fi 134 | 135 | $(MV88X3310_H): $(wildcard $(MV88X3310_HDR)) 136 | @if [ -f $(MV88X3310_HDR) ]; then \ 137 | echo Generating $(MV88X3310_H); \ 138 | ./mvidtoh.sh $(MV88X3310_HDR) MV88X3310 $(MV88X3310_H); \ 139 | fi 140 | 141 | $(MV88E2010_H): $(wildcard $(MV88E2010_HDR)) 142 | @if [ -f $(MV88E2010_HDR) ]; then \ 143 | echo Generating $(MV88E2010_H); \ 144 | ./mvidtoh.sh $(MV88E2010_HDR) MV88E2010 $(MV88E2010_H); \ 145 | fi 146 | 147 | clean: 148 | $(MAKE) -C $(KDIR) $(MODULE_DIR) clean 149 | 150 | help usage: 151 | @echo " usage:" 152 | @echo " make target [options]" 153 | @echo " Available targets:" 154 | @echo " all - build the driver" 155 | @echo " clean - Clean the driver" 156 | @echo " help - Print this help message" 157 | @echo " install - Install driver to system directory" 158 | @echo " usually, it is /lib/modules/VER/kernel/drivers/net" 159 | @echo " default - all" 160 | @echo 161 | @echo " Available options:" 162 | @echo " MV88X3120=YES - include Pele MV88X3120 phy" 163 | @echo " MV88X3310=YES - include Pele MV88X3310 phy" 164 | @echo " MV88E2010=YES - include Pele MV88E2010 phy" 165 | @echo " QT=YES - include QT2025 phy" 166 | @echo " TL=YES - include TI phy" 167 | @echo " AQ=YES - include Aquantia phy" 168 | @echo " MUSTANG=YES - Mustang-200 10GbE Ethernet Adapter only" 169 | @echo " EEE=YES - support EEE" 170 | @echo " default - phys = all, EEE=NO" 171 | 172 | install: $(DRV_NAME).ko 173 | rm -f $(OLDINSTDIR)/$(DRV_NAME).ko 174 | install -d $(INSTDIR) 175 | install -m 644 $(DRV_NAME).ko $(INSTDIR) 176 | depmod $(KVERSION) 177 | @if [ -f $(RESUME_FILE) ]; then \ 178 | test -f $(PM_DIR)/$(DRV_NAME) && rm -f $(PM_DIR)/$(DRV_NAME) > /dev/null 2>&1 || true; \ 179 | else \ 180 | test ! -d $(PM_DIR) || echo 'SUSPEND_MODULES=$(DRV_NAME)' > $(PM_DIR)/$(DRV_NAME); \ 181 | fi 182 | 183 | uninstall: 184 | rm -f $(OLDINSTDIR)/$(DRV_NAME).ko 185 | rm -f $(INSTDIR)/$(DRV_NAME).ko 186 | test -f $(PM_DIR)/$(DRV_NAME) && rm $(PM_DIR)/$(DRV_NAME) || true 187 | depmod $(KVERSION) 188 | 189 | -------------------------------------------------------------------------------- /release_notes: -------------------------------------------------------------------------------- 1 | Supported Cards: 2 | ================ 3 | 4 | VID /DID /SVID/SDID Interface Print Name 5 | ================================================================== 6 | 1fc9/4020/1fc9/3015 CX4 "TN9030 10GbE CX4 Ethernet Adapter" 7 | 1fc9/4020/180c/2040 CX4 "IEI Mustang-200 10GbE Ethernet Adapter" 8 | 1fc9/4022/1fc9/3015 SFP+ APM QT2025 "TN9310 10GbE SFP+ Ethernet Adapter" 9 | 1fc9/4022/1186/4d00 SFP+ APM QT2025 "D-Link DXE-810S 10GbE SFP+ Ethernet Adapter" 10 | 1fc9/4022/1043/8709 SFP+ APM QT2025 "ASUS XG-C100F 10GbE SFP+ Ethernet Adapter" 11 | 1fc9/4022/1432/8103 SFP+ APM QT2025 "Edimax 10 Gigabit Ethernet SFP+ PCI Express Adapter" 12 | 1fc9/4024/1fc9/3015 10GBASE-T Pele MV88X3110 "TN9210 10GBase-T Ethernet Adapter" 13 | 1fc9/4025/1fc9/3015 NBASE-T Aquantia AQR105 "TN9510 10GBase-T/NBASE-T Ethernet Adapter" 14 | 1fc9/4025/1186/2900 10GBASE-T Aquantia AQ2104 "D-Link DXE-810T 10GBase-T Ethernet Adapter" 15 | 1fc9/4025/1432/8102 NBASE-T Aquantia AQR105 "Edimax 10 Gigabit Ethernet PCI Express Adapter" 16 | 1fc9/4026/1fc9/3015 SFP+ TI TLK10232 "TN9610 10GbE SFP+ Ethernet Adapter" 17 | 1fc9/4026/4c52/1000 SFP+ TI TLK10232 "LR-Link LREC6860AF 10 Gigabit Ethernet Adapter" 18 | 1fc9/4027/1fc9/3015 NBASE-T Pele MV88X3310 "TN9710P 10GBase-T/NBASE-T Ethernet Adapter" 19 | 1fc9/4027/1432/8104 NBASE-T Pele MV88X3310 "Edimax 10 Gigabit Ethernet PCI Express Adapter" 20 | 1fc9/4027/1154/0368 NBASE-T Pele MV88X3310 "Buffalo LGY-PCIE-MG Ethernet Adapter" 21 | 1fc9/4027/1546/4027 NBASE-T Pele MV88X3310 "IOI GE10-PCIE4XG202P 10Gbase-T/NBASE-T Ethernet Adapter" 22 | 1fc9/4027/4c52/1001 NBASE-T Pele MV88X3310 "LR-Link LREC6860BT 10 Gigabit Ethernet Adapter" 23 | 1fc9/4027/1baa/3310 NBASE-T Pele MV88X3310 "QNAP LAN-10G1T-THT 10Gbase-T/NBASE-T Ethernet Adapter" 24 | 1fc9/4527/1fc9/3015 5GBASE-T Pele MV88E2010 "TN9710Q 5GBase-T/NBASE-T Ethernet Adapter" 25 | 26 | - Kernel versions supported: 2.6.32-5.1 27 | 28 | Version 0.3.6.17.2 2019/05/12 29 | ============================= 30 | - Fix compilation error under kernel 5.1.1 31 | 32 | Version 0.3.6.17.1 2019/01/09 33 | ============================= 34 | - Fix compilation error under RHEL 8 35 | - Change default installation folder as required by RHEL 8 36 | - Fix kernel 4.20 compilation error (deprecated ethtool_ops.[gs]et_settings) 37 | 38 | 39 | Version 0.3.6.17 2018/10/10 40 | ============================= 41 | - Update 3310P/E2010P to 0.3.4.0 42 | - Update AQR105 to 2.c.72 43 | - Add support for QNAP's TN9710P SVID/SDID and LED definition 44 | - Add support for LR-Link's TN9610 & TN9710P SVID/SDID 45 | - Power Management improvements 46 | 47 | Version 0.3.6.16.1 2018/05/24 48 | ============================= 49 | - Fixed CentOS compilation errors 50 | 51 | Version 0.3.6.16 2018/03/25 52 | =========================== 53 | - New memory allocation method for certain applications (Beta version, disabled) 54 | - Update AQR105 firmware to 2.b.e2 55 | - Improvement to CX4 over short trace 56 | - Improved 3310P/E2010P startup routine for 10G 57 | - Improved 3310P/E2010P startup routine for XS708E compatability 58 | - Update 3310P/E2010P to 0.3.3.0 59 | - Add IOI SVID/SDID support 60 | - Add ethtool 2.5G/5G support (but ethtool may need a rebuild) 61 | - Software PTP support (Beta version, disabled) 62 | 63 | Version 0.3.6.15 2017/10/18 64 | =========================== 65 | - New build method for Marvell PHYs. Please consult the Readme file 66 | - Improved startup procudure for "Phyless" CX4 mode 67 | - Dynamic advertising of MACA for RX flow control 68 | - Support for IEI SVID/SDID added 69 | - Improved memory allocation for memory limited or fragmented applications 70 | 71 | Version 0.3.6.14.3 2017/09/24 72 | ============================= 73 | - Fix RX Flow Control 74 | - Fix ethtool mtu on Ubuntu 17.04 75 | - Improve single PHY build code 76 | - Fix compilation error for CentOS 7.4 77 | 78 | Version 0.3.6.14.2 2017/07/18 79 | ============================= 80 | - Fix missing PCP bits in VLAN tag 81 | 82 | Version 0.3.6.14.1 2017/06/27 83 | ============================= 84 | - Add CX4 card support (TN9030) 85 | - Fix ethtool speed reporting for SFP+ cards 86 | - Fix Hibernate support 87 | - Support Flow Control for TN9710 cards 88 | - Update PHY firmware to 0.2.8.0 for TN9710 cards 89 | - Support Thunderbolt Surprise Remove 90 | - Fix Compilation failed for kernel 4.11 91 | 92 | Version 0.3.6.14 2017/03/08 93 | =========================== 94 | - Support for Pele 88X3310P and 88E2010P PHYs 95 | 96 | Version 0.3.6.13 2016/09/07 97 | =========================== 98 | - New adapter naming convention 99 | - Driver debugging options 100 | - Support RHEL6.8 101 | - Support kernel 4.7 102 | - Firmware update for AQR105 and MV88X3110 103 | 104 | Version 0.3.6.12 2015/02/19 105 | =========================== 106 | - Support TI TLK10232 phy 107 | - Remove old MDIO interface 108 | - Support Aquantia AQ2104 phy 109 | - Merge D-Link special APM firmware and IDs into Jumbo Driver 110 | - Fix RHEL7 Compilation error 111 | - Support Speed force (100,1000,2500,5000,10000) 112 | - Support ethtool -s 113 | - Support ethtool -p for kernel version < 3.0 & > 3.13 114 | - Known Issues: 115 | - - Ehtool Info does not show support for 2.5GBASE-T & 5GBASE-T, but it could be set for supported devices. 116 | 117 | Version 0.3.6.11 2014/4/10 118 | =========================== 119 | - Makefile checks is /etc/pm exists 120 | - Fixed VLAN bug 121 | - Removed TN8020 PHY support 122 | - Added WARNING compilation flag. 123 | - Work around H/W UDP false checksum error 124 | - Support ethtool -p for kernel version < 3.0 125 | 126 | Version 0.3.6.11 2013/12/8 127 | =========================== 128 | - SFP+ 1G modules support 129 | - Ethtool RX checksum report fix 130 | 131 | Version 0.3.6.10.1 2013/12/25 132 | =========================== 133 | - bdx_skb_rx_add_frag() 134 | - Receive buffer allocation low memory warning 135 | - Makefile checks is /etc/pm exists 136 | 137 | Version 0.3.6.10 2013/11/4 138 | =========================== 139 | - Pele PHY FW 2.4.1.0 140 | - False H/W tcp checksum error work around 141 | - Kernel 3.11 support 142 | - Multiple cards support 143 | - Updated Ethtool support 144 | 145 | Version 0.3.6.9 2013/09/22 146 | =========================== 147 | - Reduced memory foot print by MAC FW size 148 | - Fixed close crash bug 149 | 150 | Version 0.3.6.8 2013/08/12 151 | =========================== 152 | - Initial tn40xx Jumbo Driver release 153 | -------------------------------------------------------------------------------- /MV88X3120_phy_Linux.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | 3 | int MV88X3120_set_speed(struct bdx_priv *priv, s32 speed); 4 | 5 | #define MV88X3120_EEE_10G (0x0008) /*Support EEE for 10GBASE-T */ 6 | #define MV88X3120_EEE_1G (0x0004) /*Support EEE for 1GBASE-T */ 7 | #define MV88X3120_EEE_100M (0x0002) /*Support EEE for 100MBASE-T */ 8 | 9 | #define MV88X3120_ALL_SPEEDS (__ETHTOOL_LINK_MODE_MASK_NBITS) 10 | 11 | static void MV88X3120_set_link_mode(unsigned long *bits, u32 speed) 12 | { 13 | bitmap_zero(bits, __ETHTOOL_LINK_MODE_MASK_NBITS); 14 | __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, bits); 15 | __set_bit(ETHTOOL_LINK_MODE_TP_BIT, bits);; 16 | if (speed == MV88X3120_ALL_SPEEDS) { 17 | __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, bits); 18 | __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, bits); 19 | __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, bits); 20 | __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, bits); 21 | } else { 22 | __set_bit(speed, bits); 23 | } 24 | } 25 | 26 | int MV88X3120_get_link_ksettings(struct net_device *netdev, 27 | struct ethtool_link_ksettings *cmd) 28 | { 29 | struct bdx_priv *priv = netdev_priv(netdev); 30 | 31 | cmd->base.speed = priv->link_speed; 32 | cmd->base.port = PORT_TP; 33 | cmd->base.autoneg = AUTONEG_ENABLE; 34 | cmd->base.duplex = DUPLEX_FULL; 35 | 36 | #if defined(ETH_TP_MDI_AUTO) 37 | cmd->base.eth_tp_mdix = ETH_TP_MDI_AUTO; 38 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; 39 | #else 40 | cmd->base.eth_tp_mdix = ETH_TP_MDI | ETH_TP_MDI_X; 41 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI | ETH_TP_MDI_X; 42 | #endif 43 | MV88X3120_set_link_mode(cmd->link_modes.supported, 44 | MV88X3120_ALL_SPEEDS); 45 | if (priv->autoneg == AUTONEG_ENABLE) { 46 | memcpy(priv->link_advertising, cmd->link_modes.supported, 47 | sizeof(priv->link_advertising)); 48 | } 49 | memcpy(cmd->link_modes.advertising, priv->link_advertising, 50 | sizeof(cmd->link_modes.advertising)); 51 | 52 | return 0; 53 | } 54 | 55 | int MV88X3120_set_link_ksettings(struct net_device *netdev, 56 | const struct ethtool_link_ksettings *cmd) 57 | { 58 | struct bdx_priv *priv = netdev_priv(netdev); 59 | int rVal = 0; 60 | 61 | priv->autoneg = cmd->base.autoneg; 62 | if (priv->autoneg == AUTONEG_ENABLE) { 63 | MV88X3120_set_link_mode(priv->link_advertising, 64 | MV88X3120_ALL_SPEEDS); 65 | } else { 66 | switch (cmd->base.speed) { 67 | case 10000: /*10G */ 68 | MV88X3120_set_link_mode(priv->link_advertising, 69 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT); 70 | break; 71 | 72 | case 1000: /*1G */ 73 | MV88X3120_set_link_mode(priv->link_advertising, 74 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT); 75 | break; 76 | 77 | case 100: /*100m */ 78 | MV88X3120_set_link_mode(priv->link_advertising, 79 | ETHTOOL_LINK_MODE_100baseT_Full_BIT); 80 | break; 81 | 82 | default: 83 | pr_err("does not support speed %u\n", cmd->base.speed); 84 | rVal = -EINVAL; 85 | break; 86 | } 87 | } 88 | if (rVal == 0) { 89 | rVal = MV88X3120_set_speed(priv, cmd->base.speed); 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | /* EEE - IEEEaz */ 96 | #ifdef _EEE_ 97 | #ifdef ETHTOOL_GEEE 98 | 99 | int MV88X3120_get_eee(struct net_device *netdev, struct ethtool_eee *edata) 100 | { 101 | struct bdx_priv *priv = netdev_priv(netdev); 102 | u32 val; 103 | 104 | /* EEE Capability */ 105 | edata->supported = (SUPPORTED_10000baseT_Full); /* | SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full); */ 106 | /* EEE Advertised */ 107 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 60); 108 | edata->advertised = 0; 109 | if (val & MV88X3120_EEE_10G) 110 | edata->advertised |= SUPPORTED_10000baseT_Full; 111 | /*if(val & MV88X3120_EEE_1G) edata->advertised |= SUPPORTED_1000baseT_Full; 112 | if(val & MV88X3120_EEE_100M) edata->advertised |= SUPPORTED_100baseT_Full; */ 113 | 114 | /* EEE Link Partner Advertised */ 115 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 61); 116 | edata->lp_advertised = 0; 117 | if (val & MV88X3120_EEE_10G) 118 | edata->lp_advertised |= SUPPORTED_10000baseT_Full; 119 | 120 | /* EEE Status */ 121 | 122 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49192); 123 | if (val & 0x40) 124 | edata->eee_active = true; /*still need to check that link is up. */ 125 | 126 | edata->eee_enabled = true; 127 | 128 | return 0; 129 | } 130 | #endif 131 | 132 | #ifdef ETHTOOL_SEEE 133 | int MV88X3120_set_eee(struct bdx_priv *priv) 134 | { 135 | u16 val, port = priv->phy_mdio_port; 136 | 137 | /*EEE LPI Buffer Enable */ 138 | BDX_MDIO_WRITE(priv, 1, 49230, 0x0900); 139 | BDX_MDIO_WRITE(priv, 1, 49221, 0x1); 140 | BDX_MDIO_WRITE(priv, 7, 60, 0x8); 141 | /*val = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 20); 142 | val = bdx_mdio_read(priv, 4, priv->phy_mdio_port, 20); 143 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 61); */ 144 | /* restart autoneg */ 145 | val = (1 << 12) | (1 << 9) | (1 << 13); 146 | BDX_MDIO_WRITE(priv, 0x07, 0x0, val); 147 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 1); 148 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 1); 149 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 60); 150 | pr_err("DBG_EEE 7.60=0x%x \n", val); 151 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 61); 152 | pr_err("DBG_EEE 7.61=0x%x \n", val); 153 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49230); 154 | pr_err("DBG_EEE 1.49230=0x%x\n", val); 155 | priv->eee_enabled = true; 156 | 157 | return 0; 158 | } 159 | 160 | #endif 161 | 162 | void MV88X3120_enable_eee(struct bdx_priv *priv) 163 | { 164 | pr_debug("EEE enabled=%d\n", priv->eee_enabled); 165 | if (priv->eee_enabled) { 166 | pr_debug("EEE MTU=%d\n", priv->ndev->mtu); 167 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x809C, 0xFF1); 168 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x809D, 0x0); 169 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x809E, 0x4B); 170 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x809F, 0x0); 171 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8C02, 172 | (priv->ndev->mtu * 2)); 173 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8C03, 0x0); 174 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8E02, 175 | (priv->ndev->mtu * 2)); 176 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8E03, 0x0); 177 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8000, 0x3); 178 | bdx_mdio_write(priv, 9, priv->phy_mdio_port, 0x8001, 0x7E50); 179 | } else { 180 | #if defined(_EEE_) && defined(ETHTOOL_SEEE) 181 | MV88X3120_set_eee(priv /*, edata */ ); 182 | #endif 183 | } 184 | } 185 | 186 | int MV88X3120_reset_eee(struct bdx_priv *priv) 187 | { 188 | 189 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49230, 0); 190 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49221, 0); 191 | bdx_mdio_write(priv, 7, priv->phy_mdio_port, 60, 0); 192 | priv->eee_enabled = false; 193 | 194 | return 0; 195 | } 196 | 197 | #endif 198 | 199 | __init void MV88X3120_register_settings(struct bdx_priv *priv) 200 | { 201 | priv->phy_ops.get_link_ksettings = MV88X3120_get_link_ksettings; 202 | priv->phy_ops.set_link_ksettings = MV88X3120_set_link_ksettings; 203 | priv->autoneg = AUTONEG_ENABLE; 204 | #ifdef _EEE_ 205 | #ifdef ETHTOOL_GEEE 206 | priv->phy_ops.get_eee = MV88X3120_get_eee; 207 | #endif 208 | #ifdef ETHTOOL_SEEE 209 | priv->phy_ops.set_eee = MV88X3120_set_eee; 210 | #endif 211 | priv->phy_ops.reset_eee = MV88X3120_reset_eee; 212 | #endif 213 | } 214 | -------------------------------------------------------------------------------- /cleanup/ccmtcnvt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copied from liwc, a collection of tools for manipulating C source code 3 | * Retrieved from https://github.com/ajkaijanaho/liwc 4 | * 5 | * Copyright (c) 2012 Antti-Juhani Kaijanaho 6 | * Copyright (c) 1994-2003 Lars Wirzenius 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License, 10 | * version 2, as published by the Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 | * 02110-1301 USA. 21 | */ 22 | 23 | /* 24 | * ccmtcnvt.c -- convert C++ comments to C comments 25 | * 26 | * Usage: ccmtcnvt [-hv] [--help] [--version] 27 | * All output is to the standard output. 28 | * 29 | * This program converts the C++ style comments into traditional C style 30 | * comments. 31 | * 32 | * This is written as a finite state machine (FSM), which reads (presumably 33 | * correct) C code, and when it finds a // that is not inside a comment, or 34 | * string or character literal, it converts it to a C start of comment and 35 | * adds a space and a comment delimiter (unreproducible here :-) before the 36 | * next newline. 37 | * 38 | * Known problems: 39 | * 40 | * a) Include file names are not recognized being special, so that 41 | * 42 | * #include 43 | * 44 | * will be mangled. I've never seen such names used in source code, though, 45 | * so I don't think ignoring them will cause too much harm. 46 | * 47 | * b) Does not understand trigraphs or digraphs. 48 | * 49 | * c) Does not understand line continuation (\ at end of line) outside 50 | * string literals and character constants. 51 | * 52 | * Patches for fixing these are welcome. They're not common enough for me 53 | * to worry about them, at least for now. 54 | */ 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | 66 | /* 67 | * Special marks for input characters used in the description of the FSM. 68 | */ 69 | #define DFL (int)UCHAR_MAX+1 /* any character */ 70 | #define NONE (int)UCHAR_MAX+2 /* don't print any character */ 71 | #define SELF (int)UCHAR_MAX+3 /* print last input character */ 72 | 73 | /* 74 | * Possible states for the FSM. 75 | */ 76 | enum state { 77 | code, chr_lit, chr_esc, str_lit, str_esc, 78 | slash, cpp_cmt, cpp_ast, c_cmt, star 79 | }; 80 | 81 | /* 82 | * Rules for describing the state changes and associated actions for the 83 | * FSM. 84 | */ 85 | struct rule { 86 | enum state state; 87 | int c; 88 | enum state new_state; 89 | int print1, print2, print3, print4; 90 | const char *warning; 91 | }; 92 | 93 | /* 94 | * The FSM itself. 95 | */ 96 | static const struct rule fsm[] = { 97 | { code, '"', str_lit, SELF, NONE, NONE, NONE, NULL }, 98 | { code, '\'', chr_lit, SELF, NONE, NONE, NONE, NULL }, 99 | { code, '/', slash, NONE, NONE, NONE, NONE, NULL }, 100 | { code, DFL, code, SELF, NONE, NONE, NONE, NULL }, 101 | 102 | { str_lit, '\\', str_esc, SELF, NONE, NONE, NONE, NULL }, 103 | { str_lit, '"', code, SELF, NONE, NONE, NONE, NULL }, 104 | { str_lit, DFL, str_lit, SELF, NONE, NONE, NONE, NULL }, 105 | 106 | { str_esc, DFL, str_lit, SELF, NONE, NONE, NONE, NULL }, 107 | 108 | { chr_lit, '\\', chr_esc, SELF, NONE, NONE, NONE, NULL }, 109 | { chr_lit, '\'', code, SELF, NONE, NONE, NONE, NULL }, 110 | { chr_lit, DFL, chr_lit, SELF, NONE, NONE, NONE, NULL }, 111 | 112 | { chr_esc, DFL, chr_lit, SELF, NONE, NONE, NONE, NULL }, 113 | 114 | { slash, '/', cpp_cmt, '/', '*', NONE, NONE, NULL }, 115 | { slash, '*', c_cmt, '/', '*', NONE, NONE, NULL }, 116 | { slash, DFL, code, '/', SELF, NONE, NONE, NULL }, 117 | 118 | { cpp_cmt, '\n', code, ' ', '*', '/', SELF, NULL }, 119 | { cpp_cmt, '*', cpp_ast, SELF, NONE, NONE, NONE, NULL }, 120 | { cpp_cmt, DFL, cpp_cmt, SELF, NONE, NONE, NONE, NULL }, 121 | 122 | { cpp_ast, '\n', code, ' ', '*', '/', SELF, NULL }, 123 | { cpp_ast, '*', cpp_ast, SELF, NONE, NONE, NONE, NULL }, 124 | { cpp_ast, '/', cpp_cmt, ' ', SELF, NONE, NONE, 125 | "converted a '*/' inside a C++ comment to '* /'." }, 126 | { cpp_ast, DFL, cpp_cmt, SELF, NONE, NONE, NONE, NULL }, 127 | 128 | { c_cmt, '*', star, SELF, NONE, NONE, NONE, NULL }, 129 | { c_cmt, DFL, c_cmt, SELF, NONE, NONE, NONE, NULL }, 130 | 131 | { star, '/', code, SELF, NONE, NONE, NONE, NULL }, 132 | { star, '*', star, SELF, NONE, NONE, NONE, NULL }, 133 | { star, DFL, c_cmt, SELF, NONE, NONE, NONE, NULL }, 134 | }; 135 | 136 | 137 | static int convert(char *filename); 138 | 139 | static char usage[] = "Usage: %s [-hv] \n"; 140 | static char version[] = "version 1.1-without-publib\n"; 141 | 142 | int main(int argc, char **argv) { 143 | int opt; 144 | 145 | while ((opt = getopt(argc, argv, "hv")) != EOF) { 146 | switch (opt) { 147 | case 'h': 148 | case '?': 149 | fprintf(stderr, usage, argv[0]); 150 | case 'v': 151 | fprintf(stderr, "%s", version); 152 | } 153 | } 154 | 155 | 156 | if (optind != argc-1) { 157 | fprintf(stderr, usage, argv[0]); 158 | return EXIT_FAILURE; 159 | } 160 | 161 | if (convert(argv[optind]) != 0) { 162 | fprintf(stderr, "conversion incomplete.\n"); 163 | return EXIT_FAILURE; 164 | } 165 | 166 | return EXIT_SUCCESS; 167 | } 168 | 169 | #define print(x) (void)((x) != NONE && printf("%c", (x) == SELF ? c : (x))) 170 | static int convert(char *filename) { 171 | enum state state; 172 | const struct rule *p; 173 | int c, i; 174 | FILE *f; 175 | 176 | f = fopen(filename, "r"); 177 | if (!f) { 178 | fprintf(stderr, "couldn't open file %s for reading: %s\n", 179 | filename, strerror(errno)); 180 | return -1; 181 | } 182 | 183 | state = code; 184 | for (;;) { 185 | c = getc(f); 186 | if (c == EOF) { 187 | if (ferror(f)) { 188 | fprintf(stderr, "error reading %s: %s", 189 | filename, strerror(errno)); 190 | return -1; 191 | } 192 | 193 | switch (state) { 194 | case cpp_cmt: 195 | /* need to terminate the last // comment */ 196 | printf(" */"); 197 | break; 198 | case code: 199 | /* do nothing 'cause all's good */ 200 | break; 201 | default: 202 | fprintf(stderr, "%s error, %s ends funnily", 203 | __func__, filename); 204 | return -1; 205 | } 206 | 207 | if (fflush(stdout) == EOF || ferror(stdout)) 208 | return -1; 209 | return 0; /* everything seems to be OK */ 210 | } 211 | 212 | for (i = 0; i < sizeof(fsm) / sizeof(fsm[0]); ++i) { 213 | p = &fsm[i]; 214 | if (p->state == state && (p->c == c || p->c == DFL)) { 215 | state = p->new_state; 216 | print(p->print1); 217 | print(p->print2); 218 | print(p->print3); 219 | print(p->print4); 220 | if (p->warning != NULL) 221 | fprintf(stderr, "%s %s %s", __func__, 222 | filename, p->warning); 223 | break; 224 | } 225 | } 226 | } 227 | /*NOTREACHED*/ 228 | } 229 | -------------------------------------------------------------------------------- /MV88X3120_phy.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | #include "MV88X3120_phy.h" 3 | 4 | #define MANUF_MODEL_NUM_MASK (0x3F) 5 | #define MANUF_MODEL_NUM_BIT_POS (4) 6 | #define MV88X3120_FILE_OFFSET (16) 7 | #define AN_IN_PROGRESS (0x0000) /* Speed not resolved yet, auto-negotiation in progress */ 8 | /* #define SPEED_10BT (0x0001) Not supported */ 9 | #define SPEED_RES_100M_FD (0x0002) /* 100M Full Duplex */ 10 | #define SPEED_RES_1GIG_FD (0x0003) /* 1Gig Full Duplex */ 11 | #define SPEED_RES_10GIG (0x0004) /* 10Gig Full Duplex */ 12 | #define SPEED_RES_100M_HD (0x0005) /* 100M Half Duplex */ 13 | /* #define SPEED_RES_1GIG_HD (0x0006) Not supported for SGMII */ 14 | 15 | #define LINK_LOOP_MAX (25) 16 | 17 | void MV88X3120_register_settings(struct bdx_priv *priv); 18 | int MV88X3120_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 19 | u32 MV88X3120_link_changed(struct bdx_priv *priv); 20 | void MV88X3120_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 21 | #ifdef _EEE_ 22 | void MV88X3120_enable_eee(struct bdx_priv *priv); 23 | #endif 24 | 25 | int MV88X3120_set_speed(struct bdx_priv *priv, signed int speed) 26 | { 27 | u16 val = 0; 28 | u16 port = priv->phy_mdio_port; 29 | int rVal = 0; 30 | 31 | if (priv->autoneg == AUTONEG_ENABLE) { 32 | val = (1 << 3) | (1 << 2) | (1 << 1); 33 | } else { 34 | priv->autoneg = AUTONEG_DISABLE; 35 | switch (speed) { 36 | case 10000: /*10G */ 37 | pr_debug("MV88X3120 speed 10G\n"); 38 | val = (1 << 3); 39 | break; 40 | 41 | case 1000: /*1G */ 42 | pr_debug("MV88X3120 speed 1G\n"); 43 | val = (1 << 2); 44 | break; 45 | 46 | case 100: /*100m */ 47 | pr_debug("MV88X3120 speed 100m\n"); 48 | val = (1 << 1); 49 | break; 50 | 51 | default: 52 | pr_err("does not support speed %u\n", speed); 53 | rVal = -1; 54 | break; 55 | } 56 | } 57 | if (rVal == 0) { 58 | /* set speed */ 59 | BDX_MDIO_WRITE(priv, 0x01, 49192, val); 60 | /* restart autoneg */ 61 | val = (1 << 12) | (1 << 9) | (1 << 13); 62 | BDX_MDIO_WRITE(priv, 0x07, 0x0, val); 63 | } 64 | 65 | return rVal; 66 | 67 | } 68 | 69 | __init int MV88X3120_mdio_reset(struct bdx_priv *priv, int port, 70 | unsigned short phy) 71 | { 72 | unsigned short val, val1; 73 | int rVal = 0; 74 | u32 j, MV88X3120_phy_initdata_size = 75 | sizeof(MV88X3120_phy_initdata) / sizeof(u16); 76 | 77 | val = bdx_mdio_read(priv, 1, port, 3); 78 | val = (val & (MANUF_MODEL_NUM_MASK << MANUF_MODEL_NUM_BIT_POS)) >> MANUF_MODEL_NUM_BIT_POS; /* modelNo */ 79 | val1 = bdx_mdio_read(priv, 3, port, 53249); /* revNo */ 80 | if (val == 8 && val1 < 3) { 81 | val = 9; 82 | } 83 | pr_debug("MV88X3120 modelNo = %d revNo %d\n", val, val1); 84 | do { 85 | val = bdx_mdio_read(priv, 1, port, 49152); 86 | BDX_MDIO_WRITE(priv, 1, 49152, (val | 1 << 15)); 87 | msleep(250); 88 | if ((val = bdx_mdio_read(priv, 3, port, 0xD000)) != 0x000A) { 89 | pr_err 90 | ("MV88X3120 Initialization Error. Expected 0x000A, read 0x%04X\n", 91 | (unsigned)val); 92 | rVal = -1; 93 | break; 94 | } else { 95 | pr_debug("MV88X3120 Initializing data...\n"); 96 | } 97 | BDX_MDIO_WRITE(priv, 3, 0xD004, 0); 98 | BDX_MDIO_WRITE(priv, 3, 0xD005, 0); 99 | for (j = MV88X3120_FILE_OFFSET; j < MV88X3120_phy_initdata_size; 100 | j++) { 101 | val = swab16(MV88X3120_phy_initdata[j]); 102 | BDX_MDIO_WRITE(priv, 3, 0xD006, val); 103 | } 104 | pr_debug("MV88X3120 loaded %d 16bit words\n", 105 | MV88X3120_phy_initdata_size); 106 | 107 | val = bdx_mdio_read(priv, 3, port, 0xD000); 108 | BDX_MDIO_WRITE(priv, 3, 0xD000, (val | (1 << 6))); 109 | msleep(500); 110 | if (!((val = bdx_mdio_read(priv, 3, port, 0xD000)) & (1 << 4))) { 111 | pr_err 112 | ("MV88X3120 initdata not applied. Expected bit 4 to be 1, read 0x%04X\n", 113 | (unsigned)val); 114 | rVal = -1; 115 | break; 116 | } else { 117 | pr_err("MV88X3120 initdata applied\n"); 118 | } 119 | /* verify reset complete */ 120 | for (j = 0; j < 10; j++) { 121 | if (! 122 | ((val = 123 | bdx_mdio_read(priv, 1, port, 0)) & (1 << 15))) { 124 | break; 125 | } 126 | pr_debug("MV88X3120 waiting for reset complete 0x%x\n", 127 | val); 128 | msleep(10); 129 | } 130 | BDX_MDIO_WRITE(priv, 4, 49152, 0x00c2); 131 | 132 | BDX_MDIO_WRITE(priv, 1, 36866, 0x0009); 133 | val = bdx_mdio_read(priv, 1, port, 49190); 134 | val1 = bdx_mdio_read(priv, 1, port, 49191); 135 | pr_err("MV88X3120 I/D version is %d.%d.%d.%d\n", 136 | ((val & 0xff00) >> 8), (val & 0x00ff), 137 | ((val1 & 0xff00) >> 8), (val1 & 0x00ff)); 138 | val = bdx_mdio_read(priv, 7, port, 1); 139 | 140 | val = bdx_mdio_read(priv, 1, port, 49154); 141 | val &= ~(1 << 6); 142 | BDX_MDIO_WRITE(priv, 1, 49154, val); 143 | 144 | } 145 | while (0); 146 | 147 | return rVal; 148 | 149 | } 150 | 151 | static int MV88X3120_get_link_speed(struct bdx_priv *priv) 152 | { 153 | unsigned short val, leds; 154 | int link = 0; 155 | 156 | #ifdef DEBUG 157 | val = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 8); 158 | val = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 8); 159 | pr_debug("MV88X3120 3.8 = 0x%x\n", val); 160 | val = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 1); 161 | val = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 1); 162 | pr_debug("MV88X3120 3.1 = 0x%x\n", val); 163 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49192); 164 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49192); 165 | pr_debug("MV88X3120 1.49192 = 0x%x\n", val); 166 | #endif 167 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 36869); 168 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 36869); 169 | pr_debug("MV88X3120 1.36869 = 0x%x\n", val); 170 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 1); 171 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 1); 172 | pr_debug("MV88X3120 7.1 = 0x%x\n", val); 173 | if (val & (1 << 2)) { /* Link up */ 174 | leds = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49161); 175 | val = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49192); 176 | val = (val & 0x00F0) >> 4; 177 | switch (val) { 178 | case SPEED_RES_10GIG: 179 | link = SPEED_10000; 180 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x0009); /* led_speed0 on */ 181 | pr_debug("MV88X3120 10G link detected\n"); 182 | break; 183 | 184 | case SPEED_RES_1GIG_FD: 185 | link = SPEED_1000; 186 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x0006); /* led_speed1 on */ 187 | pr_debug("MV88X3120 1G link detected\n"); 188 | break; 189 | 190 | case SPEED_RES_100M_FD: 191 | case SPEED_RES_100M_HD: 192 | link = SPEED_100; 193 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x000a); /* led_speeds off */ 194 | pr_debug("MV88X3120 100M %s link detected\n", 195 | (val == 196 | SPEED_RES_100M_HD) ? "Half Duplex" : ""); 197 | break; 198 | 199 | case AN_IN_PROGRESS: 200 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x000a); /* led_speeds off */ 201 | pr_debug("MV88X3120 auto negotiation in progress...\n"); 202 | break; 203 | 204 | default: 205 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x000a); /* led_speeds off */ 206 | pr_debug 207 | ("MV88X3120 internal error - unknown link speed value (0x%x) !\n", 208 | val); 209 | break; 210 | } 211 | priv->errmsg_count = 0; 212 | } else { 213 | if (++priv->errmsg_count < MAX_ERRMSGS) { 214 | pr_debug("MV88X3120 link down.\n"); 215 | } 216 | } 217 | return link; 218 | 219 | } 220 | 221 | u32 MV88X3120_link_changed(struct bdx_priv *priv) 222 | { 223 | u32 link, speed; 224 | 225 | speed = MV88X3120_get_link_speed(priv); 226 | if (speed != (u32) priv->link_speed) { 227 | switch (speed) { 228 | case SPEED_10000: 229 | pr_debug("MV88X3120 10G link detected\n"); 230 | #ifdef _EEE_ 231 | MV88X3120_enable_eee(priv); 232 | #endif 233 | break; 234 | case SPEED_1000: 235 | pr_debug("MV88X3120 1G link detected\n"); 236 | break; 237 | case SPEED_100: 238 | pr_debug("MV88X3120 100M link detected\n"); 239 | break; 240 | default: 241 | pr_debug("MV88X3120 link down.\n"); 242 | break; 243 | } 244 | bdx_speed_changed(priv, speed); 245 | } 246 | link = 0; 247 | if ((!speed) 248 | || (!(link = (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT)))) { 249 | u32 timeout; 250 | u16 leds = bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49161); 251 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, (leds & 0xfff0) | 0x000a); /* led_speeds off */ 252 | if (speed) { 253 | timeout = 1000000; /* 1/5 sec */ 254 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 255 | bdx_speed_changed(priv, 0); 256 | priv->link_loop_cnt = 0; 257 | pr_debug 258 | ("MV88X3120 trying to recover link after %d tries\n", 259 | LINK_LOOP_MAX); 260 | } 261 | } else { 262 | timeout = 5000000; /* 1 sec */ 263 | } 264 | pr_debug 265 | ("MV88X3120 link = 0x%x speed = 0x%x setting %d timer\n", 266 | link, speed, timeout); 267 | WRITE_REG(priv, 0x5150, timeout); 268 | } 269 | 270 | return link; 271 | 272 | } 273 | 274 | void MV88X3120_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 275 | { 276 | switch (op) { 277 | case PHY_LEDS_SAVE: 278 | priv->phy_ops.leds[0] = 279 | bdx_mdio_read(priv, 1, priv->phy_mdio_port, 49161); 280 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, 0xf); 281 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, 0xff); 282 | break; 283 | 284 | case PHY_LEDS_RESTORE: 285 | bdx_mdio_write(priv, 1, priv->phy_mdio_port, 49161, 286 | priv->phy_ops.leds[0]); 287 | break; 288 | 289 | case PHY_LEDS_ON: 290 | break; 291 | 292 | case PHY_LEDS_OFF: 293 | break; 294 | 295 | default: 296 | pr_debug("MV88X3120_leds() unknown op 0x%x\n", op); 297 | break; 298 | 299 | } 300 | 301 | } 302 | 303 | __init enum PHY_TYPE MV88X3120_register(struct bdx_priv *priv) 304 | { 305 | priv->phy_ops.mdio_reset = MV88X3120_mdio_reset; 306 | priv->phy_ops.link_changed = MV88X3120_link_changed; 307 | priv->phy_ops.ledset = MV88X3120_leds; 308 | priv->phy_ops.mdio_speed = MDIO_SPEED_6MHZ; 309 | MV88X3120_register_settings(priv); 310 | 311 | return PHY_TYPE_MV88X3120; 312 | 313 | } 314 | -------------------------------------------------------------------------------- /TLK10232_phy.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _TLK10232_H 3 | #define _TLK10232_H 4 | 5 | #define GLOBAL_CONTROL_1 0 /* 0x1e */ 6 | #define GLOBAL_RESET 0x8000 7 | 8 | #define CHANNEL_CONTROL_1 0x1 /* 0x1e */ 9 | #define HS_SERDES_CONTROL_1 0x2 /* 0x1e */ 10 | #define HS_SERDES_CONTROL_2 0x3 /* 0x1e */ 11 | #define HS_SERDES_CONTROL_3 0x4 /* 0x1e */ 12 | #define HS_SERDES_CONTROL_4 0x5 /* 0x1e */ 13 | #define LS_SERDES_CONTROL_1 0x6 /* 0x1e */ 14 | #define LS_LANE_0 0x1 15 | #define LS_LANE_1 0x2 16 | #define LS_LANE_2 0x4 17 | #define LS_LANE_3 0x8 18 | #define LS_SERDES_CONTROL_2 0x7 /* 0x1e */ 19 | #define LS_SERDES_CONTROL_3 0x8 /* 0x1e */ 20 | #define HS_OVERLAY_CONTROL 0x9 /* 0x1e */ 21 | #define LS_OVERLAY_CONTROL 0xa /* 0x1e */ 22 | #define LOOPBACK_TP_CONTROL 0xb /* 0x1e */ 23 | #define LS_CONFIG_CONTROL 0xc /* 0x1e */ 24 | #define TI_RESERVED_STATUS_7 25 | #define CLK_CONTROL 0xd /* 0x1e */ 26 | #define RESET_CONTROL 0xe /* 0x1e */ 27 | #define CHANNEL_STATUS_1 0xf /* 0x1e */ 28 | #define HS_ERROR_COUNTER 0x10 /* 0x1e */ 29 | #define LS_LN0_ERROR_COUNTER 0x11 /* 0x1e */ 30 | #define LS_LN1_ERROR_COUNTER 0x12 /* 0x1e */ 31 | #define LS_LN2_ERROR_COUNTER 0x13 /* 0x1e */ 32 | #define LS_LN3_ERROR_COUNTER 0x14 /* 0x1e */ 33 | #define LN3_LS_STATUS_1 34 | #define LN2_LS_STATUS_1 35 | #define LN1_LS_STATUS_1 36 | #define LN0_LS_STATUS_1 37 | #define HS_STATUS_1 0x16 /* 0x1e */ 38 | #define DST_CONTROL_1 0x17 /* 0x1e */ 39 | #define DST_CONTROL_2 0x18 /* 0x1e */ 40 | #define DSR_CONTROL_1 0x19 /* 0x1e */ 41 | #define DSR_CONTROL_2 0x1a /* 0x1e */ 42 | #define DATA_SWITCH_STATUS 0x1b /* 0x1e */ 43 | #define LS_CH_CONTROL_1 0x1C /* 0x1e */ 44 | #define HS_CH_CONTROL_1 0x1d /* 0x1e */ 45 | #define EXT_ADDRESS_CONTROL 0x1e /* 0x1e */ 46 | #define EXT_ADDRESS_DATA 0x1f /* 0x1e */ 47 | #define TI_RESERVED_CONTROL_1 48 | #define TI_RESERVED_CONTROL_2 49 | #define TI_RESERVED_CONTROL_3 50 | #define VS_10G_LN_ALIGN_ACODE_P 0x8003 /* 0x1e */ 51 | #define VS_10G_LN_ALIGN_ACODE_N 0x8004 /* 0x1e */ 52 | #define TI_RESERVED_CONTROL_4 53 | #define TI_RESERVED_CONTROL_5 54 | #define TI_RESERVED_CONTROL_6 55 | #define TI_RESERVED_CONTROL_7 56 | #define TI_RESERVED_CONTROL_8 57 | #define TI_RESERVED_CONTROL_9 58 | #define TI_RESERVED_CONTROL_10 59 | #define TI_RESERVED_CONTROL_11 60 | #define TI_RESERVED_CONTROL_12 61 | #define TI_RESERVED_CONTROL_13 62 | #define TI_RESERVED_CONTROL_14 63 | #define TI_RESERVED_CONTROL_15 64 | #define TI_RESERVED_STATUS_1 65 | #define TI_RESERVED_STATUS_2 66 | #define TI_RESERVED_STATUS_3 67 | #define TI_RESERVED_STATUS_4 68 | #define TI_RESERVED_CONTROL_16 69 | #define TI_RESERVED_CONTROL_17 70 | #define TI_RESERVED_CONTROL_18 71 | #define TI_RESERVED_CONTROL_19 72 | #define TI_RESERVED_CONTROL_20 73 | #define TI_RESERVED_CONTROL_21 74 | #define TI_RESERVED_CONTROL_22 75 | #define AUTO_CLKOUT_CONTROL 76 | #define TI_RESERVED_CONTROL_23 77 | #define TI_RESERVED_CONTROL_24 78 | #define TI_RESERVED_CONTROL_25 79 | #define TI_RESERVED_CONTROL_26 80 | #define MC_AUTO_CONTROL 0x8021 /* 0x1e */ 81 | #define DST_ON_CHAR_CONTROL 0x802a /* 0x1e */ 82 | #define DST_OFF_CHAR_CONTROL 0x802b /* 0x1e */ 83 | #define DST_STUFF_CHAR_CONTROL 0x802c /* 0x1e */ 84 | #define DSR_ON_CHAR_CONTROL 0x802d /* 0x1e */ 85 | #define DSR_OFF_CHAR_CONTROL 0x802e /* 0x1e */ 86 | #define DSR_STUFF_CHAR_CONTROL 0x802f /* 0x1e */ 87 | #define TI_RESERVED_STATUS_5 88 | #define TI_RESERVED_STATUS_6 89 | #define TI_RESERVED_STATUS_8 90 | #define TI_RESERVED_STATUS_9 91 | #define TI_RESERVED_STATUS_10 92 | #define LATENCY_MEASURE_CONTROL 0x8040 /* 0x1e */ 93 | #define LATENCY_COUNTER_2 0x8041 /* 0x1e */ 94 | #define LATENCY_COUNTER_1 0x8042 /* 0x1e */ 95 | #define TI_RESERVED_CONTROL_27 96 | #define TRIGGER_LOAD_CONTROL 0x8100 /* 0x1e */ 97 | #define TRIGGER_EN_CONTROL 0x8101 /* 0x1e */ 98 | #define TI_RESERVED_CONTROL_30 99 | #define PMA_CONTROL_1 0x0 /* 0x1 */ 100 | #define PMA_STATUS_1 0x1 /* 0x1 */ 101 | #define PMA_DEV_IDENTIFIER_1 0x2 /* 0x1 */ 102 | #define PMA_DEV_IDENTIFIER_2 0x3 /* 0x1 */ 103 | #define PMA_SPEED_ABILITY 0x4 /* 0x1 */ 104 | #define PMA_DEV_PACKAGE_1 0x5 /* 0x1 */ 105 | #define PMA_DEV_PACKAGE_2 0x6 /* 0x1 */ 106 | #define PMA_STATUS_2 0x8 /* 0x1 */ 107 | #define PMA_RX_SIGNAL_DET_STATUS 0xa /* 0x1 */ 108 | #define PMA_EXTENDED_ABILITY 0xb /* 0x1 */ 109 | #define LT_TRAIN_CONTROL 0x96 /* 0x1 */ 110 | #define LT_TRAIN_STATUS 0x97 /* 0x1 */ 111 | #define LT_LINK_PARTNER_CONTROL 0x98 /* 0x1 */ 112 | #define LT_LINK_PARTNER_STATUS 0x99 /* 0x1 */ 113 | #define LT_LOCAL_DEVICE_CONTROL 0x9a /* 0x1 */ 114 | #define LT_LOCAL_DEVICE_STATUS 0x9b /* 0x1 */ 115 | #define KX_STATUS 0xa1 /* 0x1 */ 116 | #define KR_FEC_ABILITY 0xaa /* 0x1 */ 117 | #define KR_FEC_CONTROL 0xab /* 0x1 */ 118 | #define KR_FEC_C_COUNT_1 0xac /* 0x1 */ 119 | #define KR_FEC_C_COUNT_2 0xad /* 0x1 */ 120 | #define KR_FEC_UC_COUNT_1 0xae /* 0x1 */ 121 | #define KR_FEC_UC_COUNT_2 0xaf /* 0x1 */ 122 | #define TI_RESERVED_CONTROL_34 123 | #define KR_VS_FIFO_CONTROL_1 0x8001 /* 0x1 */ 124 | #define KR_VS_TP_GEN_CONTROL 0x8002 /* 0x1 */ 125 | #define KR_VS_TP_VER_CONTROL 0x8003 /* 0x1 */ 126 | #define KR_VS_CTC_ERR_CODE_LN0 0x8005 /* 0x1 */ 127 | #define KR_VS_CTC_ERR_CODE_LN1 0x8006 /* 0x1 */ 128 | #define KR_VS_CTC_ERR_CODE_LN2 0x8007 /* 0x1 */ 129 | #define KR_VS_CTC_ERR_CODE_LN3 0x8008 /* 0x1 */ 130 | #define KR_VS_LN0_EOP_ERROR_COUNTER 0x8010 /* 0x1 */ 131 | #define KR_VS_LN1_EOP_ERROR_COUNTER 0x8011 /* 0x1 */ 132 | #define KR_VS_LN2_EOP_ERROR_COUNTER 0x8012 /* 0x1 */ 133 | #define KR_VS_LN3_EOP_ERROR_COUNTER 0x8013 /* 0x1 */ 134 | #define KR_VS_TX_CTC_DROP_COUNT 0x8014 /* 0x1 */ 135 | #define KR_VS_TX_CTC_INSERT_COUNT 0x8015 /* 0x1 */ 136 | #define KR_VS_RX_CTC_DROP_COUNT 0x8016 /* 0x1 */ 137 | #define KR_VS_RX_CTC_INSERT_COUNT 0x8017 /* 0x1 */ 138 | #define KR_VS_STATUS_1 0x8018 /* 0x1 */ 139 | #define KR_VS_TX_CRCJ_ERR_COUNT_1 0x8019 /* 0x1 */ 140 | #define KR_VS_TX_CRCJ_ERR_COUNT_2 0x801a /* 0x1 */ 141 | #define KR_VS_TX_LN0_HLM_ERR_COUNT 0x801b /* 0x1 */ 142 | #define KR_VS_TX_LN1_HLM_ERR_COUNT 0x801c /* 0x1 */ 143 | #define KR_VS_TX_LN2_HLM_ERR_COUNT 0x801d /* 0x1 */ 144 | #define KR_VS_TX_LN3_HLM_ERR_COUNT 0x801e /* 0x1 */ 145 | #define TI_RESERVED_STATUS_22 146 | #define TI_RESERVED_STATUS_23 147 | #define TI_RESERVED_STATUS_24 148 | #define TI_RESERVED_STATUS_25 149 | #define TI_RESERVED_STATUS_26 150 | #define TI_RESERVED_STATUS_27 151 | #define TI_RESERVED_CONTROL_35 152 | #define TI_RESERVED_CONTROL_36 153 | #define TI_RESERVED_CONTROL_37 154 | #define TI_RESERVED_CONTROL_38 155 | #define TI_RESERVED_CONTROL_39 156 | #define TI_RESERVED_CONTROL_40 157 | #define TI_RESERVED_CONTROL_41 158 | #define TI_RESERVED_CONTROL_42 159 | #define TI_RESERVED_CONTROL_43 160 | #define TI_RESERVED_CONTROL_44 161 | #define TI_RESERVED_CONTROL_45 162 | #define TI_RESERVED_CONTROL_46 163 | #define TI_RESERVED_CONTROL_47 164 | #define TI_RESERVED_CONTROL_48 165 | #define TI_RESERVED_CONTROL_49 166 | #define TI_RESERVED_CONTROL_50 167 | #define TI_RESERVED_CONTROL_51 168 | #define TI_RESERVED_CONTROL_52 169 | #define TI_RESERVED_STATUS_28 170 | #define TI_RESERVED_STATUS_29 171 | #define TI_RESERVED_STATUS_30 172 | #define TI_RESERVED_STATUS_31 173 | #define TI_RESERVED_STATUS_32 174 | #define TI_RESERVED_STATUS_33 175 | #define TI_RESERVED_STATUS_34 176 | #define TI_RESERVED_STATUS_35 177 | #define TI_RESERVED_STATUS_36 178 | #define TI_RESERVED_STATUS_37 179 | #define PCS_CONTROL 0 /* 0x3 */ 180 | #define PCS_STATUS_1 0x1 /* 0x3 */ 181 | #define PCS_STATUS_2 0x8 /* 0x3 */ 182 | #define KR_PCS_STATUS_1 0x20 /* 0x3 */ 183 | #define KR_PCS_STATUS_2 0x21 /* 0x3 */ 184 | #define PCS_TP_SEED_A0 0x22 /* 0x3 */ 185 | #define PCS_TP_SEED_A1 0x23 /* 0x3 */ 186 | #define PCS_TP_SEED_A2 0x24 /* 0x3 */ 187 | #define PCS_TP_SEED_A3 0x25 /* 0x3 */ 188 | #define PCS_TP_SEED_B0 0x26 /* 0x3 */ 189 | #define PCS_TP_SEED_B1 0x27 /* 0x3 */ 190 | #define PCS_TP_SEED_B2 0x28 /* 0x3 */ 191 | #define PCS_TP_SEED_B3 0x29 /* 0x3 */ 192 | #define PCS_TP_CONTROL 0x2a /* 0x3 */ 193 | #define PCS_TP_ERR_COUNT 0x2b /* 0x3 */ 194 | #define PCS_VS_CONTROL 0x8000 /* 0x3 */ 195 | #define PCS_VS_STATUS 0x8010 /* 0x3 */ 196 | #define AN_CONTROL 0 /* 0x7 */ 197 | #define AN_STATUS 0x1 /* 0x7 */ 198 | #define AN_DEV_PACKAGE 0x5 /* 0x7 */ 199 | #define AN_ADVERTISEMENT_1 0x10 /* 0x7 */ 200 | #define AN_ADVERTISEMENT_2 0x11 /* 0x7 */ 201 | #define AN_ADVERTISEMENT_3 0x12 /* 0x7 */ 202 | #define AN_LP_ADVERTISEMENT_1 0x13 /* 0x7 */ 203 | #define AN_LP_ADVERTISEMENT_2 0x14 /* 0x7 */ 204 | #define AN_LP_ADVERTISEMENT_3 0x15 /* 0x7 */ 205 | #define AN_XNP_TRANSMIT_1 0x16 /* 0x7 */ 206 | #define AN_XNP_TRANSMIT_2 0x17 /* 0x7 */ 207 | #define AN_XNP_TRANSMIT_3 0x18 /* 0x7 */ 208 | #define AN_LP_XNP_ABILITY_1 0x19 /* 0x7 */ 209 | #define AN_LP_XNP_ABILITY_2 0x1a /* 0x7 */ 210 | #define AN_LP_XNP_ABILITY_3 0x1b /* 0x7 */ 211 | #define AN_BP_STATUS 0x30 /* 0x7 */ 212 | #define AN_VS_CONTROL 213 | 214 | #define REGISTER_00 215 | #define REGISTER_01 216 | #define REGISTER_02 217 | #define REGISTER_04 218 | #define REGISTER_05 219 | #define REGISTER_06 220 | #define REGISTER_0C 221 | #define REGISTER_0D 222 | #define REGISTER_0E 223 | 224 | #define GLOBAL_CONTROL_01 225 | #define CHANNEL_CONTROL_01 226 | #define RESERVED_1 227 | #define TX_SWING_CONTROL 228 | #define RESERVED_2 229 | #define TP_CONTROL 230 | #define LANE_CONFIG_CONTROL 231 | #define LAS_BER_TIMER_CONTROL_1 232 | #define CHANNEL_STATUS_01 233 | #define CRPAT_ERROR_COUNTER 234 | #define LN0_ERROR_COUNTER 235 | #define LN1_ERROR_COUNTER 236 | #define LN2_ERROR_COUNTER 237 | #define LN3_ERROR_COUNTER 238 | #define LN0_TRANSCEIVER_STATUS 239 | #define LN1_TRANSCEIVER_STATUS 240 | #define LN2_TRANSCEIVER_STATUS 241 | #define LN3_TRANSCEIVER_STATUS 242 | #define CHANNEL_STATUS_02 243 | 244 | #define CLK_REGISTER_0 245 | #define CLK_REGISTER_1 246 | #define CLK_REGISTER_2 247 | #define CLK_REGISTER_3 248 | #define CLK_REGISTER_4 249 | #define CLK_REGISTER_5 250 | #define CLK_REGISTER_6 251 | #define CLK_REGISTER_7 252 | #define CLK_REGISTER_8 253 | #define CLK_REGISTER_9 254 | #define CLK_REGISTER_10 255 | #define CLK_REGISTER_11 256 | #define CLK_REGISTER_12 257 | #define CLK_REGISTER_13 258 | #define CLK_REGISTER_14 259 | #define CLK_REGISTER_15 260 | #define CLK_REGISTER_16 261 | #define CLK_REGISTER_17 262 | #define CLK_REGISTER_18 263 | #define CLK_REGISTER_19 264 | #define CLK_REGISTER_20 265 | 266 | #endif /* _TLK10232_H */ 267 | -------------------------------------------------------------------------------- /TLK10232_phy.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | #include "TLK10232_phy.h" 3 | int bdx_speed_set(struct bdx_priv *priv, u32 speed); 4 | void sff_reset(struct bdx_priv *priv); 5 | int sff_read_str(struct bdx_priv *priv, unsigned char sfp_adr, 6 | unsigned char addr, int len, char *buf); 7 | int sff_write_str(struct bdx_priv *priv, unsigned char sfp_adr, 8 | unsigned char addr, int len, char *buf); 9 | int i2c_write_byte(struct bdx_priv *priv, int send_start, int send_stop, 10 | unsigned char byte); 11 | unsigned char i2c_read_byte(struct bdx_priv *priv, int nack, int send_stop); 12 | int i2c_read_bit(struct bdx_priv *priv); 13 | int i2c_write_bit(struct bdx_priv *priv, int bit); 14 | int i2c_start_cond(struct bdx_priv *priv, int I2C_started); 15 | int i2c_stop_cond(struct bdx_priv *priv); 16 | int i2c_SCL_stretch(struct bdx_priv *priv); 17 | int read_sfp_id(struct bdx_priv *priv); 18 | void set_GPIO(struct bdx_priv *priv); 19 | void clear_GPIO_N(struct bdx_priv *priv, u32 n); 20 | u32 read_GPIO_N(struct bdx_priv *priv, u32 n); 21 | int TLK10232_phy_config(struct bdx_priv *priv); 22 | int TLK10232_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 23 | u32 TLK10232_get_link_speed(struct bdx_priv *priv); 24 | u32 TLK10232_link_changed(struct bdx_priv *priv); 25 | void TLK10232_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 26 | 27 | #define LINK_LOOP_MAX (80) 28 | 29 | void TLK10232_register_settings(struct bdx_priv *priv); 30 | 31 | enum _SFP_MOD_TYPE { 32 | SFP_ABS = 0, 33 | SFP_NA, 34 | SFP_1G, 35 | SFP_10G, 36 | SFP_10G_DA 37 | }; 38 | 39 | #define TEST_SFP_OM 40 | 41 | #ifdef TEST_SFP_OM 42 | 43 | #define SCL_GPIO 4 44 | #define SDA_GPIO 5 45 | #define TX_DISABLE_GPIO 1 46 | #define MOD_ABS_GPIO 2 47 | 48 | #define I2C_delay(priv) udelay(8) 49 | #define RWDELAY(priv) udelay(1) 50 | 51 | #define WRITE_GPOI_REG(priv,reg,val) do{\ 52 | WRITE_REG(priv, 0x51E0,0x30010000|((reg&0xf)));\ 53 | READ_REG(priv, 0x5030); WRITE_REG(priv, 0x51F0, ( val) );\ 54 | } while(0) 55 | 56 | #define READ_GPOI_REG(priv,reg,val) do{\ 57 | WRITE_REG(priv, 0x51E0,0x30000000|((reg&0xf)));\ 58 | READ_REG(priv, 0x5030); val=READ_REG(priv, 0x51F0);\ 59 | } while(0) 60 | 61 | #define LOG_I2C pr_debug 62 | 63 | u32 read_GPIO_N(struct bdx_priv *priv, u32 n) 64 | { 65 | u32 ret, rw, i, msk = (1 << (n & 0x7)); 66 | /* get current GPIO state */ 67 | READ_GPOI_REG(priv, 6, rw); 68 | /* set to input GPIO N */ 69 | WRITE_GPOI_REG(priv, 6, rw | msk); 70 | RWDELAY(priv); 71 | /* read */ 72 | READ_GPOI_REG(priv, 4, i); 73 | ret = (i & msk) ? 1 : 0; 74 | LOG_I2C("read_GPIO_N(%x) 4= %x 6=(%x | %x) ret=%x) \n", n, i, rw, msk, 75 | ret); 76 | 77 | return ret; 78 | 79 | } 80 | 81 | void clear_GPIO_N(struct bdx_priv *priv, u32 n) 82 | { 83 | u32 rw, msk = ~(1 << (n & 0x7)); 84 | /* get current GPIO state */ 85 | READ_GPOI_REG(priv, 6, rw); 86 | /* set to output GPIO N */ 87 | WRITE_GPOI_REG(priv, 6, (rw & msk)); 88 | RWDELAY(priv); 89 | LOG_I2C("clear_GPIO_N(%x) 6=(%x & %x)\n", n, rw, msk); 90 | 91 | } 92 | 93 | /* Set SCL as input and return current level of line, 0 or 1 */ 94 | #define read_SCL(p) read_GPIO_N((p),SCL_GPIO) 95 | /* Set SDA as input and return current level of line, 0 or 1 */ 96 | #define read_SDA(p) read_GPIO_N((p),SDA_GPIO) 97 | /* Actively drive SCL signal low */ 98 | #define clear_SCL(p) clear_GPIO_N((p),SCL_GPIO) 99 | /* Actively drive SDA signal low */ 100 | #define clear_SDA(p) clear_GPIO_N((p),SDA_GPIO) 101 | 102 | /*return 0-ok 1-CLK==0 */ 103 | 104 | int i2c_SCL_stretch(struct bdx_priv *priv) 105 | { 106 | int i; 107 | for (i = 50; i; i--) { 108 | if (read_SCL(priv)) 109 | break; 110 | udelay(1); 111 | } 112 | 113 | return (i) ? 0 : 1; 114 | 115 | } 116 | 117 | int i2c_start_cond(struct bdx_priv *priv, int I2C_started) 118 | { 119 | int ret = 0; 120 | LOG_I2C("TLK10232 i2c_start_cond start=====================\n"); 121 | I2C_delay(priv); 122 | I2C_delay(priv); 123 | if (I2C_started) { 124 | read_SDA(priv); 125 | I2C_delay(priv); 126 | ret = i2c_SCL_stretch(priv); 127 | if (ret) { 128 | LOG_I2C("TLK10232 i2c_start_cond failed SCL==0\n"); 129 | } 130 | I2C_delay(priv); 131 | } 132 | 133 | if (read_SDA(priv) == 0) { 134 | LOG_I2C("TLK10232 i2c_start_cond failed SDA==0\n"); 135 | ret = 1; 136 | } 137 | /* SCL is high, set SDA from 1 to 0. */ 138 | clear_SDA(priv); 139 | I2C_delay(priv); 140 | clear_SCL(priv); 141 | LOG_I2C("TLK10232 i2c_start_cond " "%s======================\n", 142 | ret ? "Failed " : "OK"); 143 | 144 | return ret; 145 | 146 | } 147 | 148 | int i2c_stop_cond(struct bdx_priv *priv) 149 | { 150 | int ret = 0; 151 | LOG_I2C("TLK10232 i2c_stop_cond start===================\n"); 152 | clear_SCL(priv); 153 | /* set SDA to 0 */ 154 | clear_SDA(priv); 155 | I2C_delay(priv); 156 | /* Clock stretching */ 157 | ret = i2c_SCL_stretch(priv); 158 | if (ret) { 159 | LOG_I2C("TLK10232 i2c_stop_cond failed SCL==0\n"); 160 | ret = 1; 161 | } 162 | /* Stop bit setup time, minimum 4us */ 163 | I2C_delay(priv); 164 | /* SCL is high, set SDA from 0 to 1 */ 165 | if (read_SDA(priv) == 0) { 166 | LOG_I2C("TLK10232 i2c_stop_cond failed SDA==0\n"); 167 | ret = 1; 168 | } 169 | I2C_delay(priv); 170 | LOG_I2C("TLK10232 i2c_stop_cond end===================\n"); 171 | 172 | return ret; 173 | 174 | } 175 | 176 | /* Write a bit to I2C bus */ 177 | int i2c_write_bit(struct bdx_priv *priv, int bit) 178 | { 179 | int ret = 0; 180 | LOG_I2C("TLK10232 i2c_write_bit ==%x start \n", bit); 181 | if (bit) { 182 | read_SDA(priv); 183 | } else { 184 | clear_SDA(priv); 185 | } 186 | i2c_SCL_stretch(priv); 187 | I2C_delay(priv); 188 | /* SCL is high, now data is valid */ 189 | /* If SDA is high, check that nobody else is driving SDA */ 190 | if (bit) 191 | if (read_SDA(priv) == 0) { 192 | 193 | ret = 1; 194 | } 195 | I2C_delay(priv); 196 | clear_SCL(priv); 197 | LOG_I2C("TLK10232 i2c_write_bit %s\n", ret ? "failed" : "OK"); 198 | 199 | return ret; 200 | 201 | } 202 | 203 | /* Read a bit from I2C bus */ 204 | int i2c_read_bit(struct bdx_priv *priv) 205 | { 206 | int bit; 207 | LOG_I2C("TLK10232 i2c_read_bit start \n"); 208 | /* Let the slave drive data */ 209 | read_SDA(priv); 210 | i2c_SCL_stretch(priv); 211 | I2C_delay(priv); 212 | /* SCL is high, now data is valid */ 213 | bit = read_SDA(priv); 214 | I2C_delay(priv); 215 | clear_SCL(priv); 216 | LOG_I2C("TLK10232 i2c_read_bit %x \n", bit); 217 | 218 | return bit ? 1 : 0; 219 | 220 | } 221 | 222 | /* Write a byte to I2C bus. Return 0 if ack by the slave. */ 223 | int i2c_write_byte(struct bdx_priv *priv, int send_start, 224 | int send_stop, unsigned char byte) 225 | { 226 | unsigned bit; 227 | int nack; 228 | LOG_I2C("i2c_write_byte 0x%x start\n", byte); 229 | if (send_start) { 230 | i2c_start_cond(priv, (send_start == 2) ? 1 : 0); 231 | } 232 | for (bit = 0; bit < 8; bit++) { 233 | i2c_write_bit(priv, (byte & 0x80) != 0); 234 | byte <<= 1; 235 | } 236 | nack = i2c_read_bit(priv); 237 | if (send_stop) { 238 | i2c_stop_cond(priv); 239 | } 240 | LOG_I2C("i2c_write_byte end nack=%x\n", nack); 241 | 242 | return nack; 243 | 244 | } 245 | 246 | /* Read a byte from I2C bus */ 247 | unsigned char i2c_read_byte(struct bdx_priv *priv, int nack, int send_stop) 248 | { 249 | unsigned char byte = 0; 250 | unsigned bit; 251 | LOG_I2C("i2c_read_byte start nack=%x\n", nack); 252 | for (bit = 0; bit < 8; bit++) { 253 | byte = (byte << 1); 254 | byte |= i2c_read_bit(priv); 255 | } 256 | i2c_write_bit(priv, nack); 257 | if (send_stop) { 258 | i2c_stop_cond(priv); 259 | } 260 | LOG_I2C("i2c_read_byte stop byte=%x\n", byte); 261 | 262 | return byte; 263 | 264 | } 265 | 266 | void sff_reset(struct bdx_priv *priv) 267 | { 268 | int i; 269 | 270 | for (i = 0; i < 9; i++) { 271 | i2c_read_bit(priv); 272 | } 273 | i2c_start_cond(priv, 0); 274 | I2C_delay(priv); 275 | read_SDA(priv); 276 | 277 | } 278 | 279 | /* 280 | Return len or 0 on error 281 | */ 282 | int sff_read_str(struct bdx_priv *priv, unsigned char sfp_adr, 283 | unsigned char addr, int len, char *buf) 284 | { 285 | unsigned char data; 286 | int i = 0, err = 0; 287 | 288 | if (buf == 0) 289 | return 0; 290 | if (len == 0) 291 | return 0; 292 | if (len & 0xff00) 293 | return 0; 294 | 295 | pr_debug("TLK10232 sff_read_str sfp_adr=%x addr=%x start \n", sfp_adr, 296 | addr); 297 | 298 | do { 299 | err = i2c_write_byte(priv, /*send_start */ 1, /*send_stop */ 0, 300 | sfp_adr & 0xfe); 301 | if (err) { 302 | err = 1; 303 | break; 304 | } 305 | 306 | err = i2c_write_byte(priv, /*send_start */ 0, /*send_stop */ 1, 307 | addr & 0xff); 308 | if (err) { 309 | err = 2; 310 | break; 311 | } 312 | 313 | err = i2c_write_byte(priv, /*send_start */ 1, /*send_stop */ 0, 314 | sfp_adr | 1); 315 | if (err) { 316 | err = 3; 317 | break; 318 | } 319 | 320 | len--; 321 | for (i = 0; i < len; i++) { 322 | data = 323 | i2c_read_byte(priv, /*nack */ 0, /*send_stop */ 0); 324 | buf[i] = data; 325 | } 326 | data = i2c_read_byte(priv, /*nack */ 1, /*send_stop */ 1); 327 | buf[i] = data; 328 | i++; 329 | pr_debug("TLK10232 sff_read_str sfp_adr=%x addr=%x end \n", 330 | sfp_adr, addr); 331 | } while (0); 332 | if (err) { 333 | pr_debug("TLK10232 sff_read step %u failed\n", err); 334 | i = 0; 335 | i2c_stop_cond(priv); 336 | } 337 | 338 | return i; 339 | 340 | } 341 | 342 | int sff_write_str(struct bdx_priv *priv, unsigned char sfp_adr, 343 | unsigned char addr, int len, char *buf) 344 | { 345 | int i = 0, err = 0; 346 | 347 | if (buf == 0) 348 | return 0; 349 | if (len == 0) 350 | return 0; 351 | if (len > 8) 352 | return 0; /* not more then 7 bytes by SFF spec */ 353 | if (len & 0xff00) 354 | return 0; 355 | 356 | pr_debug("TLK10232 sff_write_str sfp_adr=%x addr=%x start \n", sfp_adr, 357 | addr); 358 | 359 | do { 360 | err = i2c_write_byte(priv, /*send_start */ 1, /*send_stop */ 0, 361 | sfp_adr & 0xfe); 362 | if (err) { 363 | err = 1; 364 | break; 365 | } 366 | 367 | err = i2c_write_byte(priv, /*send_start */ 0, /*send_stop */ 0, 368 | addr & 0xff); 369 | if (err) { 370 | err = 2; 371 | break; 372 | } 373 | 374 | len--; 375 | for (i = 0; i < len; i++) { 376 | err = i2c_write_byte(priv, /*send_start */ 0, 377 | /*send_stop */ 0, buf[i]); 378 | if (err) { 379 | err = 4; 380 | break; 381 | } 382 | } 383 | if (err) { 384 | err = 4; 385 | break; 386 | } 387 | err = i2c_write_byte(priv, /*send_start */ 0, /*send_stop */ 1, 388 | buf[i]); 389 | i++; 390 | pr_debug("TLK10232 sff_write_str sfp_adr=%x addr=%x end \n", 391 | sfp_adr, addr); 392 | } while (0); 393 | if (err) { 394 | pr_err("TLK10232 sff_write step %u failed\n", err); 395 | i = 0; 396 | i2c_stop_cond(priv); 397 | } 398 | 399 | return i; 400 | 401 | } 402 | 403 | void set_GPIO(struct bdx_priv *priv) 404 | { 405 | u32 input_msk = 406 | (1 << 11) | (1 << SCL_GPIO) | (1 << SDA_GPIO) | (1 << MOD_ABS_GPIO); 407 | WRITE_GPOI_REG(priv, 4, 0); 408 | WRITE_GPOI_REG(priv, 6, input_msk); 409 | 410 | } 411 | 412 | int read_sfp_id(struct bdx_priv *priv) 413 | { 414 | char buff[10]; 415 | int i, ret; 416 | int sff_addr = 0xa0; 417 | int addr = 0x3; 418 | int len = 6; 419 | 420 | set_GPIO(priv); 421 | i = read_GPIO_N(priv, MOD_ABS_GPIO); 422 | pr_debug("MOD_ABS_GPIO=%u \n", i); 423 | if (i) 424 | return SFP_ABS; 425 | ret = sff_read_str(priv, sff_addr, addr, len, buff); 426 | pr_debug("sff_read_str(0x%x,0x%x,0x%x)=%x \n", sff_addr, addr, len, 427 | ret); 428 | #if 0 429 | for (i = 0; i < ret; i++) { 430 | pr_err("sff_read_str buf[%u]=0x%x \n", i, buff[i] & 0xff); 431 | } 432 | #endif 433 | if (buff[5] & 0xF) 434 | return SFP_10G_DA; 435 | if (buff[0]) 436 | return SFP_10G; 437 | if (buff[3] & 0xF) 438 | return SFP_1G; 439 | 440 | return SFP_10G; 441 | 442 | } 443 | 444 | #else 445 | #define read_sfp_id(p) (SFP_10G) 446 | #endif 447 | 448 | int TLK10232_phy_config(struct bdx_priv *priv) 449 | { 450 | int regVal, j = 0; 451 | int port = priv->phy_mdio_port; 452 | 453 | u32 sfp_mod_type = priv->sfp_mod_type; 454 | if (sfp_mod_type == SFP_ABS) 455 | return 0; 456 | 457 | switch (sfp_mod_type) { 458 | default: 459 | case SFP_10G: 460 | BDX_MDIO_WRITE(priv, 0x1e, CHANNEL_CONTROL_1, 0x0B00); 461 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_2, 0xA848); /*reg 1e.3 */ 462 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_3, 0x9518); /*reg 1e.4 */ 463 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_4, 0x3300); /*reg 1e.5 */ 464 | break; 465 | 466 | case SFP_10G_DA: 467 | BDX_MDIO_WRITE(priv, 0x1e, CHANNEL_CONTROL_1, 0x0B00); 468 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_2, 0xF848); /*reg 1e.3 */ 469 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_3, 0x1500); /*reg 1e.4 */ 470 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_4, 0x2000); /*reg 1e.5 */ 471 | break; 472 | 473 | case SFP_1G: 474 | BDX_MDIO_WRITE(priv, 0x1e, CHANNEL_CONTROL_1, 0x0300); 475 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_2, 0xA848); /*reg 1e.3 */ 476 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_3, 0x9518); /*reg 1e.4 */ 477 | BDX_MDIO_WRITE(priv, 0x1e, HS_SERDES_CONTROL_4, 0x3300); /*reg 1e.5 */ 478 | 479 | break; 480 | } 481 | 482 | /* Datapath reset */ 483 | do { 484 | udelay(25); 485 | BDX_MDIO_WRITE(priv, 0x1e, RESET_CONTROL, 0x8); 486 | BDX_MDIO_WRITE(priv, 0x1e, RESET_CONTROL, 0x0); 487 | udelay(25); 488 | regVal = bdx_mdio_read(priv, 0x1e, port, CHANNEL_STATUS_1); 489 | regVal = bdx_mdio_read(priv, 0x1e, port, CHANNEL_STATUS_1); 490 | pr_debug 491 | ("TLK10232_phy_config() CHANNEL_STATUS_1 = 0x%x Fail:%x loops:%d (Fail mask 0x0100)\n", 492 | regVal, (regVal & 0x0100), j); 493 | } while ((regVal & 0x0100) && (j++ < 100)); 494 | 495 | return 0; 496 | } 497 | 498 | int TLK10232_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy) 499 | { 500 | int regVal; 501 | priv->sfp_mod_type = 0; 502 | 503 | /* Device reset */ 504 | BDX_MDIO_WRITE(priv, 0x1e, GLOBAL_CONTROL_1, 0x8610); 505 | regVal = bdx_mdio_read(priv, 0x1e, port, GLOBAL_CONTROL_1); 506 | pr_debug("TLK10232_mdio_reset() GLOBAL_CONTROL_1 = 0x%x\n", regVal); 507 | msleep(100); 508 | 509 | BDX_MDIO_WRITE(priv, 0x7, AN_CONTROL, 0x2000); 510 | BDX_MDIO_WRITE(priv, 0x1, LT_TRAIN_CONTROL, 0x0); 511 | 512 | priv->link_speed = TLK10232_get_link_speed(priv); 513 | bdx_speed_set(priv, priv->link_speed); 514 | 515 | return 0; 516 | 517 | } 518 | 519 | u32 TLK10232_get_link_speed(struct bdx_priv *priv) 520 | { 521 | u32 sfp_mod_type, speed; 522 | 523 | sfp_mod_type = read_sfp_id(priv); 524 | 525 | if (priv->sfp_mod_type != sfp_mod_type) { 526 | priv->sfp_mod_type = sfp_mod_type; 527 | TLK10232_phy_config(priv); 528 | } 529 | switch (sfp_mod_type) { 530 | case SFP_10G: 531 | case SFP_10G_DA: 532 | speed = SPEED_10000; 533 | break; 534 | case SFP_1G: 535 | /*speed=SPEED_1000; break; */ 536 | default: 537 | speed = 0; 538 | break; 539 | } 540 | 541 | return speed; 542 | 543 | } 544 | 545 | u32 TLK10232_link_changed(struct bdx_priv *priv) 546 | { 547 | u32 link = 0; 548 | 549 | link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; 550 | if (link) { 551 | priv->link_speed = TLK10232_get_link_speed(priv); 552 | link = priv->link_speed; 553 | pr_debug("TLK10232 link speed is %s\n", 554 | (priv->link_speed == SPEED_10000) ? "10G" : "1G"); 555 | WRITE_REG(priv, 0x5150, 0); /* stop timer */ 556 | } else { 557 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 558 | pr_debug 559 | ("TLK10232 trying to recover link after %d tries\n", 560 | LINK_LOOP_MAX); 561 | priv->link_speed = TLK10232_get_link_speed(priv); 562 | /* MAC reset */ 563 | bdx_speed_set(priv, 0); 564 | bdx_speed_set(priv, priv->link_speed); 565 | priv->link_loop_cnt = 0; 566 | priv->sfp_mod_type = SFP_ABS; 567 | } 568 | 569 | WRITE_REG(priv, 0x5150, 1000000); /* 1/5 sec timeout */ 570 | } 571 | 572 | return link; 573 | 574 | } 575 | 576 | void TLK10232_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 577 | { 578 | switch (op) { 579 | case PHY_LEDS_SAVE: 580 | break; 581 | 582 | case PHY_LEDS_RESTORE: 583 | break; 584 | 585 | case PHY_LEDS_ON: 586 | WRITE_REG(priv, regBLNK_LED, 4); 587 | break; 588 | 589 | case PHY_LEDS_OFF: 590 | WRITE_REG(priv, regBLNK_LED, 0); 591 | break; 592 | 593 | default: 594 | pr_debug("TLK10232_leds() unknown op 0x%x\n", op); 595 | break; 596 | 597 | } 598 | 599 | } 600 | 601 | __init enum PHY_TYPE TLK10232_register(struct bdx_priv *priv) 602 | { 603 | priv->phy_ops.mdio_reset = TLK10232_mdio_reset; 604 | priv->phy_ops.link_changed = TLK10232_link_changed; 605 | priv->phy_ops.ledset = TLK10232_leds; 606 | priv->phy_ops.mdio_speed = MDIO_SPEED_1MHZ; 607 | TLK10232_register_settings(priv); 608 | 609 | return PHY_TYPE_TLK10232; 610 | 611 | } 612 | -------------------------------------------------------------------------------- /AQR105_phy.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | #include "AQR105_phy.h" 3 | 4 | #define mailboxWrite (0xC000) 5 | #define phyImageHeaderContentOffset (0x300) 6 | #define r1 (0x1E) 7 | #define LINK_LOOP_MAX (25) 8 | 9 | /*#define AQ_VERBOSE */ 10 | 11 | void AQR105_register_settings(struct bdx_priv *priv); 12 | int AQR105_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 13 | u32 AQR105_link_changed(struct bdx_priv *priv); 14 | void AQR105_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 15 | 16 | int AQR105_set_speed(struct bdx_priv *priv, signed int speed) 17 | { 18 | u16 val, port = priv->phy_mdio_port; 19 | int rVal = 0; 20 | 21 | if (priv->autoneg == AUTONEG_ENABLE) { 22 | pr_debug("AQR105 speed %d Autoneg\n", speed); 23 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x9101); 24 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x9C5A); 25 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1001); 26 | } else { 27 | switch (speed) { 28 | case 10000: /*10G */ 29 | pr_debug("AQR105 speed 10G\n"); 30 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x9001); 31 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x40); 32 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1001); 33 | break; 34 | 35 | case 5000: /*5G */ 36 | pr_debug("AQR105 speed 5G\n"); 37 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x9001); 38 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x840); 39 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1); 40 | break; 41 | 42 | case 2500: /*2.5G */ 43 | pr_debug("AQR105 speed 10G\n"); 44 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x9001); 45 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x440); 46 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1); 47 | break; 48 | 49 | case 1000: /*1G */ 50 | pr_debug("AQR105 speed 1G\n"); 51 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x8001); 52 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x8040); 53 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1); 54 | break; 55 | 56 | case 100: /*100m */ 57 | pr_debug("AQR105 speed 100m\n"); 58 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x101); 59 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x40); 60 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1); 61 | break; 62 | 63 | default: 64 | pr_err("does not support speed %u\n", speed); 65 | rVal = -1; 66 | break; 67 | } 68 | } 69 | if (rVal == 0) { 70 | /* restart autoneg */ 71 | val = (1 << 12) | (1 << 9) | (1 << 13); 72 | BDX_MDIO_WRITE(priv, 0x07, 0x0, val); 73 | } 74 | 75 | return rVal; 76 | 77 | } 78 | 79 | __init int AQR105_mdio_reset(struct bdx_priv *priv, int port, 80 | unsigned short phy) 81 | { 82 | u16 val, val1, val2; 83 | int rVal = 0; 84 | u32 i; 85 | u8 *image = AQR105_phy_firmware; 86 | u32 primaryHeaderPtr; 87 | u32 primaryIramPtr, primaryIramSize, primaryDramPtr, primaryDramSize; 88 | u32 byteSize, dWordSize, bytePointer; 89 | u16 msw = 0, lsw = 0, sd, sv; 90 | 91 | BDX_MDIO_WRITE(priv, 0x1E, 0, 1 << 0xF); /* Soft Reset */ 92 | msleep(10); 93 | BDX_MDIO_WRITE(priv, 0x1E, 0, 0); 94 | BDX_MDIO_WRITE(priv, 0x1E, 0xC001, 1 << 0xF); /* uP Reset */ 95 | msleep(10); 96 | BDX_MDIO_WRITE(priv, 0x1E, 0xC001, 0); 97 | msleep(1); 98 | 99 | val1 = bdx_mdio_read(priv, r1, port, 0xC441); 100 | 101 | /*Reset start */ 102 | BDX_MDIO_WRITE(priv, 4, 0xC440, 1); /*Reset XAUI SerDes */ 103 | for (i = 3; i--;) { /*Wait until XAUI Serdes reset done and clear */ 104 | val = bdx_mdio_read(priv, 4, port, 0xC440); 105 | 106 | if (!val) 107 | break; 108 | msleep(1); 109 | } 110 | BDX_MDIO_WRITE(priv, 4, 0xC440, 0); /*clear Reset XAUI SerDes (probably needed) */ 111 | 112 | val = bdx_mdio_read(priv, 4, port, 0x0); 113 | BDX_MDIO_WRITE(priv, 4, 0x0, 0xA040); /*Reset PHY XS core */ 114 | bdx_mdio_get(priv); /*Wait until MDIO transaction finished */ 115 | 116 | msleep(2); 117 | BDX_MDIO_WRITE(priv, 4, 0x0, 0x2040); /*Reset PHY XS core */ 118 | for (i = 10; i--;) { /*Wait until PHy XS register read correctly */ 119 | val = bdx_mdio_read(priv, 4, port, 0x0); 120 | if (!(val == 0xFFFF)) 121 | break; 122 | msleep(1); 123 | } 124 | /*Reset End */ 125 | 126 | BDX_MDIO_WRITE(priv, r1, 0xC452, 1); /*NVR Daisy Chain Disable */ 127 | BDX_MDIO_WRITE(priv, r1, 0xC441, 0); 128 | 129 | val = 0; 130 | val |= 1; /*upRunStall */ 131 | val |= 1 << 6; /*upRunStallOverride */ 132 | BDX_MDIO_WRITE(priv, r1, 0xC001, val); 133 | 134 | /*--- Read the segment addresses and sizes -----------------*/ 135 | primaryHeaderPtr = (((image[0x9] & 0x0F) << 8) | image[0x8]) << 12; 136 | 137 | primaryIramPtr = 138 | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x4 + 2] << 139 | 16) | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x4 + 140 | 1] << 8) | image[primaryHeaderPtr + 141 | phyImageHeaderContentOffset + 0x4]; 142 | primaryIramSize = 143 | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x7 + 2] << 144 | 16) | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x7 + 145 | 1] << 8) | image[primaryHeaderPtr + 146 | phyImageHeaderContentOffset + 0x7]; 147 | primaryDramPtr = 148 | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xA + 2] << 149 | 16) | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xA + 150 | 1] << 8) | image[primaryHeaderPtr + 151 | phyImageHeaderContentOffset + 0xA]; 152 | primaryDramSize = 153 | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xD + 2] << 154 | 16) | (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xD + 155 | 1] << 8) | image[primaryHeaderPtr + 156 | phyImageHeaderContentOffset + 0xD]; 157 | 158 | if (1 /*AQ_DEVICE_HHD == port->device */ ) { 159 | primaryIramPtr += primaryHeaderPtr; 160 | primaryDramPtr += primaryHeaderPtr; 161 | } 162 | #ifdef AQ_VERBOSE 163 | pr_info 164 | ("Segment Addresses and Sizes as read from the PHY ROM image header:\n\n"); 165 | pr_info("Primary Iram Address: 0x%x\n", primaryIramPtr); 166 | pr_info("Primary Iram Size: 0x%x\n", primaryIramSize); 167 | pr_info("Primary Dram Address: 0x%x\n", primaryDramPtr); 168 | pr_info("Primary Dram Size: 0x%x\n\n", primaryDramSize); 169 | #endif 170 | 171 | /*-- Load IRAM and DRAM ----------------------*/ 172 | 173 | /* clear the mailbox CRC */ 174 | BDX_MDIO_WRITE(priv, r1, 0x200, 0x1000); /*resetUpMailboxCrc */ 175 | BDX_MDIO_WRITE(priv, r1, 0x200, 0x0000); /*resetUpMailboxCrc */ 176 | 177 | /* load the IRAM */ 178 | #ifdef AQ_VERBOSE 179 | pr_info("Loading IRAM:\n"); 180 | #endif 181 | 182 | /*#define AQ_IRAM_BASE_ADDRESS 0x40000000 */ 183 | 184 | BDX_MDIO_WRITE(priv, r1, 0x202, 0x4000); /*msw */ 185 | BDX_MDIO_WRITE(priv, r1, 0x203, 0x0000); /*lsw */ 186 | 187 | /* set block size so that there are from 0-3 bytes remaining */ 188 | byteSize = primaryIramSize; 189 | dWordSize = byteSize >> 2; 190 | 191 | bytePointer = primaryIramPtr; 192 | for (i = 0; i < dWordSize; i++) { 193 | /* write 4 bytes of data */ 194 | lsw = (image[bytePointer + 1] << 8) | image[bytePointer]; 195 | bytePointer += 2; 196 | msw = (image[bytePointer + 1] << 8) | image[bytePointer]; 197 | bytePointer += 2; 198 | 199 | BDX_MDIO_WRITE(priv, r1, 0x204, msw); 200 | BDX_MDIO_WRITE(priv, r1, 0x205, lsw); 201 | val = bdx_mdio_read(priv, r1, port, 0x200); 202 | if (val & (1 << 8)) { 203 | pr_err("Mailbox Busy !!!\n"); 204 | return -1; 205 | } 206 | BDX_MDIO_WRITE(priv, r1, 0x200, mailboxWrite); 207 | } 208 | /* Note: this final write right-justifies non-dWord data in the final dWord */ 209 | if (byteSize & 0x3) { 210 | switch (byteSize & 0x3) { 211 | case 0x1: 212 | /* write 1 byte of data */ 213 | lsw = image[bytePointer++]; 214 | msw = 0x0000; 215 | break; 216 | 217 | case 0x2: 218 | /* write 2 bytes of data */ 219 | lsw = 220 | (image[bytePointer + 1] << 8) | image[bytePointer]; 221 | bytePointer += 2; 222 | msw = 0x0000; 223 | break; 224 | 225 | case 0x3: 226 | /* write 3 bytes of data */ 227 | lsw = 228 | (image[bytePointer + 1] << 8) | image[bytePointer]; 229 | bytePointer += 2; 230 | msw = image[bytePointer++]; 231 | break; 232 | } 233 | BDX_MDIO_WRITE(priv, r1, 0x204, msw); 234 | BDX_MDIO_WRITE(priv, r1, 0x205, lsw); 235 | BDX_MDIO_WRITE(priv, r1, 0x200, mailboxWrite); 236 | } 237 | 238 | /* load the DRAM */ 239 | #ifdef AQ_VERBOSE 240 | pr_info("Last IRAM data lsw=0x%x msw=0x%x \n", lsw, msw); 241 | msw = bdx_mdio_read(priv, r1, port, 0x202); 242 | lsw = bdx_mdio_read(priv, r1, port, 0x203); 243 | pr_info("Last+1 IRAM address lsw=0x%x msw=0x%x \n", lsw, msw); 244 | pr_info("Loading DRAM:\n"); 245 | #endif 246 | 247 | /*#define AQ_DRAM_BASE_ADDRESS 0x3FFE0000 */ 248 | BDX_MDIO_WRITE(priv, r1, 0x202, 0x3FFE); /*msw */ 249 | BDX_MDIO_WRITE(priv, r1, 0x203, 0x0000); /*lsw */ 250 | 251 | /* set block size so that there are from 0-3 bytes remaining */ 252 | byteSize = primaryDramSize; 253 | dWordSize = byteSize >> 2; 254 | 255 | bytePointer = primaryDramPtr; 256 | for (i = 0; i < dWordSize; i++) { 257 | /* write 4 bytes of data */ 258 | lsw = (image[bytePointer + 1] << 8) | image[bytePointer]; 259 | bytePointer += 2; 260 | msw = (image[bytePointer + 1] << 8) | image[bytePointer]; 261 | bytePointer += 2; 262 | BDX_MDIO_WRITE(priv, r1, 0x204, msw); 263 | BDX_MDIO_WRITE(priv, r1, 0x205, lsw); 264 | BDX_MDIO_WRITE(priv, r1, 0x200, mailboxWrite); 265 | } 266 | 267 | /* Note: this final write right-justifies non-dWord data in the final dWord */ 268 | if (byteSize & 0x3) { 269 | switch (byteSize & 0x3) { 270 | case 0x1: 271 | /* write 1 byte of data */ 272 | lsw = image[bytePointer++]; 273 | msw = 0x0000; 274 | break; 275 | 276 | case 0x2: 277 | /* write 2 bytes of data */ 278 | lsw = 279 | (image[bytePointer + 1] << 8) | image[bytePointer]; 280 | bytePointer += 2; 281 | msw = 0x0000; 282 | break; 283 | 284 | case 0x3: 285 | /* write 3 bytes of data */ 286 | lsw = 287 | (image[bytePointer + 1] << 8) | image[bytePointer]; 288 | bytePointer += 2; 289 | msw = image[bytePointer++]; 290 | break; 291 | } 292 | BDX_MDIO_WRITE(priv, r1, 0x204, msw); 293 | BDX_MDIO_WRITE(priv, r1, 0x205, lsw); 294 | BDX_MDIO_WRITE(priv, r1, 0x200, mailboxWrite); 295 | } 296 | #ifdef AQ_VERBOSE 297 | pr_info("Last DRAM data lsw=0x%x msw=0x%x \n", lsw, msw); 298 | msw = bdx_mdio_read(priv, r1, port, 0x202); 299 | lsw = bdx_mdio_read(priv, r1, port, 0x203); 300 | pr_info("Last+1 DRAM address lsw=0x%x msw=0x%x \n", lsw, msw); 301 | #endif 302 | 303 | /*-- Clear any resets -----------------------------------*/ 304 | BDX_MDIO_WRITE(priv, r1, 0, 0); 305 | 306 | /*-- Release the uP --------------------------------------*/ 307 | 308 | val = 1; /*upRunStall */ 309 | val |= 1 << 6; /*upRunStallOverride */ 310 | BDX_MDIO_WRITE(priv, r1, 0xC001, val); 311 | val |= 1 << 15; /*upReset */ 312 | BDX_MDIO_WRITE(priv, r1, 0xC001, val); 313 | 314 | /* Need to wait at least 100us. */ 315 | msleep(200); 316 | BDX_MDIO_WRITE(priv, r1, 0xC001, 0x40); 317 | for (i = 100; i--;) { 318 | msleep(20); 319 | val = bdx_mdio_read(priv, r1, port, 0xCC00); 320 | if (val & (1 << 6)) 321 | break; 322 | 323 | }; 324 | /*if(!(val&(1<<6))){ // Reset timeout 325 | pr_err("AQR105 FW reset timeout 1E.CC00=%x\n",val); 326 | }; */ 327 | 328 | val = bdx_mdio_read(priv, r1, port, 0x20); 329 | val2 = bdx_mdio_read(priv, r1, port, 0xC885); 330 | val1 = val >> 8; 331 | val &= 0xFF; 332 | val2 &= 0xFF; 333 | pr_info("AQR105 FW ver: %x.%x.%x\n", val1, val, val2); 334 | /*Enable AQRate speeds */ 335 | msleep(20); 336 | BDX_MDIO_WRITE(priv, 0x07, 0x10, 0x9101); 337 | BDX_MDIO_WRITE(priv, 0x07, 0xC400, 0x9C5A); 338 | BDX_MDIO_WRITE(priv, 0x07, 0x20, 0x1001); 339 | /* restart autoneg */ 340 | val = (1 << 12) | (1 << 9) | (1 << 13); 341 | BDX_MDIO_WRITE(priv, 0x07, 0x0, val); 342 | 343 | #if 1 /* led setup */ 344 | /* 345 | 0xC430=f // Act led (right) black-no link or no act; green-link blink on act 346 | 0xC431=80 // Speed led Amber -on on 10G 347 | Tehuti settings 348 | 0xC432=C040 // Speed led Green -on on 5G/2.5G/1G (black on 100M) 349 | D-link settings 350 | 0xC432=C060 // Speed led Green -on on 5G/2.5/1G/100M 351 | */ 352 | { 353 | /*ACT Led - off on no link */ 354 | sv = priv->subsystem_vendor; 355 | sd = priv->subsystem_device; 356 | 357 | if ((sv == 0x105A) && (sd == 0x7203)) { /* Promise */ 358 | BDX_MDIO_WRITE(priv, r1, 0xC430, 0xc0ef); 359 | BDX_MDIO_WRITE(priv, r1, 0xC431, 0xC080); 360 | BDX_MDIO_WRITE(priv, r1, 0xC432, 0xC040); 361 | } else { 362 | BDX_MDIO_WRITE(priv, r1, 0xC430, 0x00); 363 | BDX_MDIO_WRITE(priv, r1, 0xC431, 0x80); 364 | if ((sv == 0x1186) && (sd == 0x2900)) { /*isDlink */ 365 | BDX_MDIO_WRITE(priv, r1, 0xC432, 0xC060); 366 | } else { 367 | BDX_MDIO_WRITE(priv, r1, 0xC432, 0xC040); 368 | } 369 | } 370 | } 371 | #endif 372 | 373 | return rVal; 374 | 375 | } 376 | 377 | static int AQR105_get_link_speed(struct bdx_priv *priv) 378 | { 379 | unsigned short val; /*, leds; */ 380 | int link = 0; 381 | u16 ActLnk_MSK = 0; 382 | u16 sd, sv; 383 | 384 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 0xC810); 385 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 0xC810); 386 | 387 | val = val >> 9; 388 | val &= 0x1f; 389 | if (val == 4) { /* Link up */ 390 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 0xC800); 391 | val = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 0xC800); 392 | 393 | val &= 0xF; 394 | if ((val >> 1) > 0) { 395 | sv = priv->subsystem_vendor; 396 | sd = priv->subsystem_device; 397 | if (!((sv == 0x1186) && (sd == 0x2900))) { /*isNotDlink */ 398 | ActLnk_MSK = 0xC0E0; 399 | } 400 | bdx_mdio_write(priv, 0x1E, priv->phy_mdio_port, 0xC430, 401 | 0x0f | ActLnk_MSK); 402 | } 403 | switch (val >> 1) { 404 | case 5: /*SPEED_RES_5GIG */ 405 | link = SPEED_5000; 406 | pr_debug("AQR105 5G link detected\n"); 407 | break; 408 | 409 | case 4: /*SPEED_RES_2.5GIG */ 410 | link = SPEED_2500; 411 | pr_debug("AQR105 2.5G link detected\n"); 412 | break; 413 | 414 | case 3: /*SPEED_RES_10GIG */ 415 | link = SPEED_10000; 416 | pr_debug("AQR105 10G link detected\n"); 417 | break; 418 | 419 | case 2: /* SPEED_RES_1GIG */ 420 | link = SPEED_1000; 421 | pr_debug("AQR105 1G link detected\n"); 422 | break; 423 | 424 | case 1: /* SPEED_RES_100M */ 425 | link = SPEED_100; 426 | pr_debug("AQR105 100M %s link detected\n", 427 | (val & 1) ? "" : "Half Duplex"); 428 | break; 429 | 430 | case 0: /* SPEED_RES_10M */ 431 | link = 0; 432 | bdx_mdio_write(priv, 0x1E, priv->phy_mdio_port, 0xC430, 433 | 0x0); 434 | pr_debug("AQR105 10M %s link detected. Not Supported\n", 435 | (val & 1) ? "" : "Half Duplex"); 436 | break; 437 | 438 | } 439 | priv->errmsg_count = 0; 440 | } else { 441 | bdx_mdio_write(priv, 0x1E, priv->phy_mdio_port, 0xC430, 0x0); 442 | if (++priv->errmsg_count < MAX_ERRMSGS) { 443 | pr_debug("AQR105 link down.\n"); 444 | } 445 | } 446 | 447 | return link; 448 | 449 | } 450 | 451 | u32 AQR105_link_changed(struct bdx_priv *priv) 452 | { 453 | u32 link, speed; 454 | 455 | speed = AQR105_get_link_speed(priv); 456 | pr_debug("AQR105_link_changed speed=%u priv->link_speed=%u\n", speed, 457 | priv->link_speed); 458 | if (speed != (u32) priv->link_speed) { 459 | switch (speed) { 460 | case SPEED_10000: 461 | pr_debug("AQR105 10G link detected\n"); 462 | break; 463 | case SPEED_5000: 464 | pr_debug("AQR105 5G link detected\n"); 465 | break; 466 | case SPEED_2500: 467 | pr_debug("AQR105 2.5G link detected\n"); 468 | break; 469 | case SPEED_1000: 470 | pr_debug("AQR105 1G link detected\n"); 471 | break; 472 | case SPEED_100: 473 | pr_debug("AQR105 100M link detected\n"); 474 | break; 475 | case SPEED_10: 476 | pr_debug("AQR105 10M link detected\n"); 477 | break; 478 | default: 479 | pr_debug("AQR105 link down.\n"); 480 | break; 481 | } 482 | bdx_speed_changed(priv, speed); 483 | } 484 | link = 0; 485 | if ((!speed) || (!(link = (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT)))) { /* // XAUI link */ 486 | u32 timeout; 487 | if (speed) { 488 | timeout = 1000000; /* 1/5 sec */ 489 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 490 | bdx_speed_changed(priv, 0); 491 | priv->link_loop_cnt = 0; 492 | pr_debug 493 | ("AQR105 trying to recover link after %d tries\n", 494 | LINK_LOOP_MAX); 495 | } 496 | } else { 497 | timeout = 5000000; /* 1 sec */ 498 | } 499 | pr_debug("AQR105 link = 0x%x speed = 0x%x setting %d timer\n", 500 | link, speed, timeout); 501 | WRITE_REG(priv, 0x5150, timeout); 502 | } 503 | 504 | return link; 505 | 506 | } 507 | 508 | void AQR105_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 509 | { 510 | u16 dev = 0x1e, led = 0xC430, led_off = 0, led_on = (1 << 8); 511 | 512 | switch (op) { 513 | case PHY_LEDS_SAVE: 514 | priv->phy_ops.leds[0] = 515 | bdx_mdio_read(priv, dev, priv->phy_mdio_port, led); 516 | bdx_mdio_write(priv, dev, priv->phy_mdio_port, led, led_off); 517 | break; 518 | 519 | case PHY_LEDS_RESTORE: 520 | bdx_mdio_write(priv, dev, priv->phy_mdio_port, led, 521 | priv->phy_ops.leds[0]); 522 | 523 | break; 524 | 525 | case PHY_LEDS_ON: 526 | bdx_mdio_write(priv, dev, priv->phy_mdio_port, led, led_on); 527 | 528 | break; 529 | 530 | case PHY_LEDS_OFF: 531 | bdx_mdio_write(priv, dev, priv->phy_mdio_port, led, led_off); 532 | 533 | break; 534 | 535 | default: 536 | pr_debug("AQR105_leds() unknown op 0x%x\n", op); 537 | break; 538 | 539 | } 540 | 541 | } 542 | 543 | __init enum PHY_TYPE AQR105_register(struct bdx_priv *priv) 544 | { 545 | priv->phy_ops.mdio_reset = AQR105_mdio_reset; 546 | priv->phy_ops.link_changed = AQR105_link_changed; 547 | priv->phy_ops.ledset = AQR105_leds; 548 | priv->phy_ops.mdio_speed = MDIO_SPEED_6MHZ; 549 | AQR105_register_settings(priv); 550 | 551 | return PHY_TYPE_AQR105; 552 | 553 | } 554 | -------------------------------------------------------------------------------- /MV88X3310_phy.c: -------------------------------------------------------------------------------- 1 | #include "tn40.h" 2 | #ifdef PHY_MV88X3310 3 | #include "MV88X3310_phy.h" 4 | #endif 5 | #ifdef PHY_MV88E2010 6 | #include "MV88E2010_phy.h" 7 | #endif 8 | #define MACTYPE (0x1) 9 | #define MV88X3310_FILE_OFFSET (16) 10 | #define MANUF_MODEL_NUM_MASK (0x3F) 11 | #define MANUF_MODEL_NUM_BIT_POS (4) 12 | #define MV88X3120_FILE_OFFSET (16) 13 | /*#define SPEED_RES_10M (0x0000) // Not supported */ 14 | #define SPEED_RES_100M (0x0001) 15 | #define SPEED_RES_1GIG (0x0002) 16 | #define SPEED_RES_NBASE (0x0003) 17 | #define SPEED_RES_10GIG (0x0000) 18 | #define SPEED_RES_5GIG (0x0002) 19 | #define SPEED_RES_2P5GIG (0x0001) 20 | #define MV88X3310_10M_MASK ((1 << 5) | (1 << 6)) /* reg7_0010 */ 21 | #define MV88X3310_100M_MASK (1 << 8) /* " */ 22 | #define MV88X3310_1G_MASK (1 << 9) /* reg7_8000 */ 23 | #define MV88X3310_2_5G_MASK ((1 << 5) | (1 << 7)) /* reg7_0020 */ 24 | #define MV88X3310_5G_MASK ((1 << 6) | (1 << 8)) /* " */ 25 | #define MV88X3310_10G_MASK (1 << 12) /* " */ 26 | #define MV88X3310_LED_0 (0xf020) 27 | #define MV88X3310_LED_1 (0xf021) 28 | #define MV88X3310_LED_2 (0xf022) 29 | #define MV88X3310_LED_3 (0xf023) 30 | 31 | #define SW_RESET_COUNT (100) 32 | #define LINK_LOOP_MAX (25) 33 | #define PHY_NAME ((priv->deviceId == 0x4027) ? "MV88X3310" : "MV88E2010") 34 | enum PHY_LED_COLOR { 35 | PHY_LED_OFF, 36 | PHY_LED_GREEN, 37 | PHY_LED_AMBER, 38 | }; 39 | enum PHY_SPEED { 40 | PHY_SPEED_LOW, 41 | PHY_SPEED_NBASET, 42 | PHY_SPEED_HIGH, 43 | }; 44 | 45 | void MV88X3310_register_settings(struct bdx_priv *priv); 46 | int MV88X3310_mdio_reset(struct bdx_priv *priv, int port, unsigned short phy); 47 | u32 MV88X3310_link_changed(struct bdx_priv *priv); 48 | void MV88X3310_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op); 49 | 50 | int MV88X3310_set_speed(struct bdx_priv *priv, signed int speed) 51 | { 52 | 53 | u16 val, port = priv->phy_mdio_port; 54 | u16 reg7_0010 = PHY_MDIO_READ(priv, 7, 0x0010); 55 | u16 reg7_0020 = PHY_MDIO_READ(priv, 7, 0x0020); 56 | u16 reg7_8000 = PHY_MDIO_READ(priv, 7, 0x8000); 57 | int rVal = 0; 58 | 59 | if (priv->autoneg == AUTONEG_ENABLE) { 60 | pr_debug("MV88X3310 speed 10G/1G/100m Autoneg\n"); 61 | reg7_0010 = 62 | (reg7_0010 & ~MV88X3310_10M_MASK) | MV88X3310_100M_MASK; 63 | reg7_0020 = 64 | reg7_0020 | MV88X3310_2_5G_MASK | MV88X3310_5G_MASK | 65 | MV88X3310_10G_MASK; 66 | reg7_8000 = reg7_8000 | MV88X3310_1G_MASK; 67 | } else { 68 | switch (speed) { 69 | case 10000: /*10G */ 70 | pr_debug("MV88X3310 speed 10G\n"); 71 | reg7_0010 = 72 | reg7_0010 & ~MV88X3310_10M_MASK & 73 | ~MV88X3310_100M_MASK; 74 | reg7_0020 = 75 | (reg7_0020 & ~MV88X3310_2_5G_MASK & 76 | ~MV88X3310_5G_MASK) | MV88X3310_10G_MASK; 77 | reg7_8000 = reg7_8000 & ~MV88X3310_1G_MASK; 78 | break; 79 | 80 | case 5000: /*5G */ 81 | pr_debug("MV88X3310 speed 5G\n"); 82 | reg7_0010 = 83 | reg7_0010 & ~MV88X3310_10M_MASK & 84 | ~MV88X3310_100M_MASK; 85 | reg7_0020 = 86 | (reg7_0020 & ~MV88X3310_2_5G_MASK & 87 | ~MV88X3310_10G_MASK) | MV88X3310_5G_MASK; 88 | reg7_8000 = reg7_8000 & ~MV88X3310_1G_MASK; 89 | break; 90 | 91 | case 2500: /*2.5G */ 92 | pr_debug("MV88X3310 speed 2.5G\n"); 93 | reg7_0010 = 94 | reg7_0010 & ~MV88X3310_10M_MASK & 95 | ~MV88X3310_100M_MASK; 96 | reg7_0020 = 97 | (reg7_0020 & ~MV88X3310_5G_MASK & 98 | ~MV88X3310_10G_MASK) | MV88X3310_2_5G_MASK; 99 | reg7_8000 = reg7_0020 & ~MV88X3310_1G_MASK; 100 | break; 101 | 102 | case 1000: /*1G */ 103 | pr_debug("MV88X3310 speed 1G\n"); 104 | reg7_0010 = 105 | reg7_0010 & ~MV88X3310_10M_MASK & 106 | ~MV88X3310_100M_MASK; 107 | reg7_0020 = 108 | reg7_0020 & ~MV88X3310_2_5G_MASK & 109 | ~MV88X3310_10G_MASK & ~MV88X3310_5G_MASK; 110 | reg7_8000 = reg7_8000 | MV88X3310_1G_MASK; 111 | break; 112 | 113 | case 100: /*100m */ 114 | pr_debug("MV88X3310 speed 100m\n"); 115 | reg7_0010 = 116 | (reg7_0010 & ~MV88X3310_10M_MASK) | 117 | MV88X3310_100M_MASK; 118 | reg7_0020 = 119 | reg7_0020 & ~MV88X3310_2_5G_MASK & 120 | ~MV88X3310_10G_MASK & ~MV88X3310_5G_MASK; 121 | reg7_8000 = reg7_8000 & ~MV88X3310_1G_MASK; 122 | break; 123 | 124 | default: 125 | pr_err("does not support speed %u\n", speed); 126 | rVal = -1; 127 | break; 128 | } 129 | } 130 | if (rVal == 0) { 131 | /* set speed */ 132 | pr_debug 133 | ("writing 7,0x0010 0x%04x 7,0x0020 0x%04x 7,0x8000 0x%04x\n", 134 | (u32) reg7_0010, (u32) reg7_0020, (u32) reg7_8000); 135 | BDX_MDIO_WRITE(priv, 7, 0x0010, reg7_0010); 136 | BDX_MDIO_WRITE(priv, 7, 0x0020, reg7_0020); 137 | BDX_MDIO_WRITE(priv, 7, 0x8000, reg7_8000); 138 | /* restart autoneg */ 139 | val = PHY_MDIO_READ(priv, 7, 0); 140 | val = val | 0x1200; 141 | BDX_MDIO_WRITE(priv, 0x07, 0x0, val); 142 | } 143 | 144 | return rVal; 145 | 146 | } 147 | 148 | static int MV88X3310_set_Reset_values(struct bdx_priv *priv) 149 | { 150 | u16 val; 151 | u16 port = priv->phy_mdio_port; 152 | u16 port_ctrl = PHY_MDIO_READ(priv, 31, 0xF001); 153 | u16 reg7_0010 = PHY_MDIO_READ(priv, 7, 0x0010); 154 | u16 reg7_0020 = PHY_MDIO_READ(priv, 7, 0x0020); 155 | u16 reg7_8000 = PHY_MDIO_READ(priv, 7, 0x8000); 156 | 157 | reg7_0010 = (reg7_0010 & ~MV88X3310_10M_MASK) | MV88X3310_100M_MASK; 158 | reg7_0020 = 159 | reg7_0020 | MV88X3310_2_5G_MASK | MV88X3310_5G_MASK | 160 | MV88X3310_10G_MASK; 161 | reg7_8000 = reg7_8000 | MV88X3310_1G_MASK; 162 | 163 | pr_debug("writing 7,0x0010 0x%04x 7,0x0020 0x%04x 7,0x8000 0x%04x\n", 164 | (u32) reg7_0010, (u32) reg7_0020, (u32) reg7_8000); 165 | BDX_MDIO_WRITE(priv, 7, 0x0010, reg7_0010); 166 | BDX_MDIO_WRITE(priv, 7, 0x0020, reg7_0020); 167 | BDX_MDIO_WRITE(priv, 7, 0x8000, reg7_8000); 168 | 169 | port_ctrl |= MACTYPE; 170 | port_ctrl |= (1 << 15); 171 | BDX_MDIO_WRITE(priv, 31, 0xF001, port_ctrl); 172 | 173 | val = PHY_MDIO_READ(priv, 7, 0); 174 | val |= ((1 << 9) | (1 << 12)); 175 | BDX_MDIO_WRITE(priv, 7, 0, val); 176 | pr_debug("MACTYPE = 0x%x\n", 177 | bdx_mdio_read(priv, 31, port, 0xF001) & 0x0007); 178 | 179 | BDX_MDIO_WRITE(priv, 1, 0xC034, 0x0017); 180 | 181 | return 0; 182 | 183 | } 184 | 185 | static int MV88X3310_set_rate_adapt(struct bdx_priv *priv, 186 | enum PHY_SPEED phy_speed) 187 | { 188 | u16 port = priv->phy_mdio_port; 189 | 190 | if (phy_speed == PHY_SPEED_HIGH) { 191 | pr_debug("Rate Adapt: off\n"); 192 | 193 | BDX_MDIO_WRITE(priv, 31, 0xF000, 0x10C8); 194 | bdx_mdio_read(priv, 31, port, 0xF001); 195 | bdx_mdio_read(priv, 31, port, 0xF001); 196 | BDX_MDIO_WRITE(priv, 31, 0xF000, 0x20C8); 197 | bdx_mdio_read(priv, 31, port, 0xF001); 198 | bdx_mdio_read(priv, 31, port, 0xF001); 199 | } else { 200 | pr_debug("Rate Adapt: on\n"); 201 | BDX_MDIO_WRITE(priv, 31, 0xF000, 0x30C8); 202 | bdx_mdio_read(priv, 31, port, 0xF001); 203 | bdx_mdio_read(priv, 31, port, 0xF001); 204 | 205 | BDX_MDIO_WRITE(priv, 31, 0x8000, 0x0F3F); 206 | BDX_MDIO_WRITE(priv, 31, 0x8001, 0x41D0); 207 | bdx_mdio_read(priv, 31, port, 0xF001); 208 | bdx_mdio_read(priv, 31, port, 0xF001); 209 | bdx_mdio_read(priv, 31, port, 0xF001); 210 | bdx_mdio_read(priv, 31, port, 0xF001); 211 | bdx_mdio_read(priv, 31, port, 0xF001); 212 | 213 | BDX_MDIO_WRITE(priv, 31, 0x8C04, 0x1C00); 214 | BDX_MDIO_WRITE(priv, 31, 0x8C05, 0x0000); 215 | BDX_MDIO_WRITE(priv, 31, 0x800E, 0x1B0A); 216 | BDX_MDIO_WRITE(priv, 31, 0x800F, 0x0000); 217 | 218 | if (phy_speed == PHY_SPEED_NBASET) { 219 | pr_debug("Rate Adapt: nbaset_speeds\n"); 220 | 221 | BDX_MDIO_WRITE(priv, 31, 0x8C00, 0x1383); 222 | BDX_MDIO_WRITE(priv, 31, 0x8C01, 0x0000); 223 | BDX_MDIO_WRITE(priv, 31, 0x8E00, 0x1383); 224 | BDX_MDIO_WRITE(priv, 31, 0x8E01, 0x0000); 225 | BDX_MDIO_WRITE(priv, 31, 0x8C02, 0x1FFF); 226 | BDX_MDIO_WRITE(priv, 31, 0x8C03, 0x0000); 227 | BDX_MDIO_WRITE(priv, 31, 0x8E02, 0x1FFF); 228 | BDX_MDIO_WRITE(priv, 31, 0x8E03, 0x0000); 229 | 230 | BDX_MDIO_WRITE(priv, 31, 0x80A2, 0x0001); 231 | BDX_MDIO_WRITE(priv, 31, 0x80A3, 0x0000); 232 | } else { 233 | pr_debug("Rate Adapt: lower Speeds\n"); 234 | 235 | BDX_MDIO_WRITE(priv, 31, 0x8C00, 0xFFFF); 236 | BDX_MDIO_WRITE(priv, 31, 0x8E01, 0x0000); 237 | BDX_MDIO_WRITE(priv, 31, 0x8E00, 0xFFFF); 238 | BDX_MDIO_WRITE(priv, 31, 0x8E01, 0x0000); 239 | BDX_MDIO_WRITE(priv, 31, 0x8C06, 0x0189); 240 | BDX_MDIO_WRITE(priv, 31, 0x8C07, 0x0000); 241 | BDX_MDIO_WRITE(priv, 31, 0x8E06, 0xB1E8); 242 | BDX_MDIO_WRITE(priv, 31, 0x8E07, 0x0000); 243 | 244 | BDX_MDIO_WRITE(priv, 31, 0x80A2, 0x0000); 245 | BDX_MDIO_WRITE(priv, 31, 0x80A3, 0x0000); 246 | } 247 | } 248 | 249 | return 0; 250 | 251 | } 252 | 253 | #ifdef _ 254 | #ifdef ETHTOOL_SEEE_ 255 | int MV88X3310_set_eee(struct bdx_priv *priv /*, struct ethtool_eee *edata */ ); 256 | #endif 257 | #endif 258 | __init int MV88X3310_mdio_reset(struct bdx_priv *priv, int port, 259 | unsigned short phy) 260 | { 261 | unsigned short val, val1; 262 | int rVal = 0; 263 | u32 j; 264 | u32 phy_initdata_size = 0; 265 | u16 *phy_initdata = NULL; 266 | u16 expected_value = 0; 267 | 268 | #ifdef PHY_MV88X3310 269 | if (priv->deviceId == 0x4027) { 270 | phy_initdata = MV88X3310_phy_initdata; 271 | phy_initdata_size = 272 | sizeof(MV88X3310_phy_initdata) / sizeof(u16); 273 | } 274 | #endif 275 | #ifdef PHY_MV88E2010 276 | if (priv->deviceId == 0x4527) { 277 | phy_initdata = MV88E2010_phy_initdata; 278 | phy_initdata_size = 279 | sizeof(MV88E2010_phy_initdata) / sizeof(u16); 280 | 281 | } 282 | #endif 283 | val = bdx_mdio_read(priv, 1, port, 3); 284 | val1 = val & 0x000F; /* revNo */ 285 | val = (val & (MANUF_MODEL_NUM_MASK << MANUF_MODEL_NUM_BIT_POS)) >> MANUF_MODEL_NUM_BIT_POS; /* modelNo */ 286 | pr_debug("%s modelNo = %d revNo %d\n", PHY_NAME, val, val1); 287 | do { 288 | val = bdx_mdio_read(priv, 31, port, 0xF008); 289 | BDX_MDIO_WRITE(priv, 31, 0xF008, (val | 1 << 5)); 290 | val = bdx_mdio_read(priv, 31, port, 0xF001); 291 | BDX_MDIO_WRITE(priv, 31, 0xF001, (val | 1 << 12)); 292 | msleep(250); 293 | if ((val = bdx_mdio_read(priv, 1, port, 0xC050)) != 0x000A) { 294 | pr_err 295 | ("%s Initialization Error. Expected 0x000A, read 0x%04X\n", 296 | PHY_NAME, (unsigned)val); 297 | rVal = -1; 298 | break; 299 | } else { 300 | pr_debug("%s Initializing data...\n", PHY_NAME); 301 | } 302 | val = bdx_mdio_read(priv, 3, port, 0xD0F3); 303 | BDX_MDIO_WRITE(priv, 3, 0xD0F0, 0); 304 | BDX_MDIO_WRITE(priv, 3, 0xD0F1, 0x0010); 305 | for (j = MV88X3310_FILE_OFFSET; j < phy_initdata_size; j++) { 306 | val = swab16(phy_initdata[j]); 307 | expected_value += 308 | (val & 0x00ff) + ((val & 0xff00) >> 8); 309 | BDX_MDIO_WRITE(priv, 3, 0xD0F2, val); 310 | } 311 | pr_debug("%s loaded %d 16bit words\n", PHY_NAME, 312 | phy_initdata_size); 313 | val = bdx_mdio_read(priv, 1, port, 0xC050); 314 | BDX_MDIO_WRITE(priv, 1, 0xC050, (val | (1 << 6))); 315 | msleep(500); 316 | if (!((val = bdx_mdio_read(priv, 1, port, 0xC050)) & (1 << 4))) { 317 | pr_err 318 | ("%s initdata not applied. Expected bit 4 to be 1, read 0x%04X\n", 319 | PHY_NAME, (unsigned)val); 320 | rVal = -1; 321 | break; 322 | } else { 323 | pr_info("%s initdata applied\n", PHY_NAME); 324 | } 325 | val = bdx_mdio_read(priv, 3, port, 0xD0F3); 326 | if ((phy_initdata[4] != swab16(~expected_value)) 327 | || (swab16(~val) != swab16(~expected_value))) { 328 | pr_err 329 | ("Initdata error ! file value is 0x%04x , I/D value is 0x%04x , expected value is 0x%04x\n", 330 | phy_initdata[4], swab16(~val), 331 | swab16(~expected_value)); 332 | rVal = -1; 333 | break; 334 | } 335 | val = bdx_mdio_read(priv, 1, port, 0xc011); 336 | val1 = bdx_mdio_read(priv, 1, port, 0xc012); 337 | pr_info("%s I/D version is %d.%d.%d.%d\n", PHY_NAME, 338 | ((val & 0xff00) >> 8), (val & 0x00ff), 339 | ((val1 & 0xff00) >> 8), (val1 & 0x00ff)); 340 | val = bdx_mdio_read(priv, 1, port, 0); 341 | BDX_MDIO_WRITE(priv, 1, 0, val | (1 << 15)); 342 | /* verify reset complete */ 343 | for (j = 0; j < SW_RESET_COUNT; j++) { 344 | if (! 345 | ((val = 346 | bdx_mdio_read(priv, 1, port, 0)) & (1 << 15))) { 347 | break; 348 | } 349 | pr_debug("%s waiting for reset complete 0x%x\n", 350 | PHY_NAME, val); 351 | msleep(10); 352 | } 353 | if (j == SW_RESET_COUNT) { 354 | pr_err("%s SW reset was not completed 0x%x\n", 355 | PHY_NAME, val); 356 | } 357 | MV88X3310_set_Reset_values(priv); 358 | BDX_MDIO_WRITE(priv, 3, 0x8010, (1 << 10) | (1 << 11)); /* Enable LASI auto negotiation complete */ 359 | 360 | } while (0); 361 | 362 | return rVal; 363 | 364 | } 365 | 366 | static void MV88X3310_led(struct bdx_priv *priv, enum PHY_LED_COLOR color) 367 | { 368 | u16 led1val, led2val; 369 | 370 | if (color == PHY_LED_GREEN) { 371 | led1val = 0; 372 | led2val = 0xb8; 373 | } else if (color == PHY_LED_AMBER) { 374 | led1val = 0xb8; 375 | led2val = 0; 376 | } else { 377 | led1val = led2val = 0; 378 | } 379 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_1, led1val); 380 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_2, led2val); 381 | 382 | } 383 | 384 | static int MV88X3310_get_link_speed(struct bdx_priv *priv) 385 | { 386 | unsigned short status; 387 | int resolved, duplex, speed, link = 0; 388 | u16 sd, sv; 389 | int qnap_led = 0; 390 | 391 | status = bdx_mdio_read(priv, 7, priv->phy_mdio_port, 1); 392 | pr_debug("%s 7.1 = 0x%x\n", PHY_NAME, status); 393 | 394 | sv = priv->subsystem_vendor; 395 | sd = priv->subsystem_device; 396 | if ((sv == 0x1BAA) && (sd == 0x3310)) 397 | qnap_led = 1; 398 | 399 | PHY_MDIO_READ(priv, 3, 0x8011); 400 | PHY_MDIO_READ(priv, 3, 0x8011); 401 | 402 | if (status & (1 << 2)) { /* Link up */ 403 | status = bdx_mdio_read(priv, 3, priv->phy_mdio_port, 0x8008); 404 | resolved = status & (1 << 11); 405 | duplex = status & (1 << 13); 406 | speed = (status & 0xc000) >> 14; 407 | if (resolved) { 408 | pr_debug("%s speed %d %s duplex\n", 409 | PHY_NAME, speed, duplex ? "full" : "half"); 410 | switch (speed) { 411 | case SPEED_RES_NBASE: 412 | speed = (status & 0x000c) >> 2; 413 | switch (speed) { 414 | case SPEED_RES_10GIG: 415 | link = SPEED_10000; 416 | MV88X3310_set_rate_adapt(priv, 417 | PHY_SPEED_HIGH); 418 | if (qnap_led == 1) 419 | MV88X3310_led(priv, 420 | PHY_LED_GREEN); 421 | else 422 | MV88X3310_led(priv, 423 | PHY_LED_AMBER); 424 | pr_debug("%s 10G link detected\n", 425 | PHY_NAME); 426 | break; 427 | 428 | case SPEED_RES_5GIG: 429 | link = SPEED_5000; 430 | MV88X3310_set_rate_adapt(priv, 431 | PHY_SPEED_NBASET); 432 | if (qnap_led == 1) 433 | MV88X3310_led(priv, 434 | PHY_LED_AMBER); 435 | else 436 | MV88X3310_led(priv, 437 | PHY_LED_GREEN); 438 | pr_debug("%s 5G link detected\n", 439 | PHY_NAME); 440 | break; 441 | 442 | case SPEED_RES_2P5GIG: 443 | link = SPEED_2500; 444 | MV88X3310_set_rate_adapt(priv, 445 | PHY_SPEED_NBASET); 446 | if (qnap_led == 1) 447 | MV88X3310_led(priv, 448 | PHY_LED_AMBER); 449 | else 450 | MV88X3310_led(priv, 451 | PHY_LED_GREEN); 452 | pr_debug("%s 2.5G link detected\n", 453 | PHY_NAME); 454 | break; 455 | 456 | default: 457 | pr_debug 458 | ("%s internal error - unknown link speed value (0x%x) !\n", 459 | PHY_NAME, status); 460 | break; 461 | } 462 | break; 463 | 464 | case SPEED_RES_1GIG: 465 | link = SPEED_1000X; 466 | MV88X3310_set_rate_adapt(priv, PHY_SPEED_LOW); 467 | if (qnap_led == 1) 468 | MV88X3310_led(priv, PHY_LED_AMBER); 469 | else 470 | MV88X3310_led(priv, PHY_LED_GREEN); 471 | pr_debug("%s 1G link detected\n", PHY_NAME); 472 | break; 473 | 474 | case SPEED_RES_100M: 475 | link = SPEED_100X; 476 | MV88X3310_set_rate_adapt(priv, PHY_SPEED_LOW); 477 | if (qnap_led == 1) 478 | MV88X3310_led(priv, PHY_LED_AMBER); 479 | else 480 | MV88X3310_led(priv, PHY_LED_OFF); 481 | pr_debug("%s 100M link detected\n", PHY_NAME); 482 | break; 483 | 484 | default: 485 | pr_debug 486 | ("%s internal error - unknown link speed value (0x%x) !\n", 487 | PHY_NAME, status); 488 | MV88X3310_led(priv, PHY_LED_OFF); 489 | break; 490 | } 491 | } else { 492 | pr_debug("%s auto negotiation in progress...\n", 493 | PHY_NAME); 494 | MV88X3310_led(priv, PHY_LED_OFF); 495 | 496 | } 497 | priv->errmsg_count = 0; 498 | } else { 499 | if (++priv->errmsg_count < MAX_ERRMSGS) { 500 | MV88X3310_led(priv, PHY_LED_OFF); 501 | pr_debug("%s link down.\n", PHY_NAME); 502 | } 503 | } 504 | 505 | return link; 506 | 507 | } 508 | 509 | u32 MV88X3310_link_changed(struct bdx_priv *priv) 510 | { 511 | u32 link, speed; 512 | 513 | speed = MV88X3310_get_link_speed(priv); 514 | pr_debug("speed %d priv->link_speed %d\n", speed, priv->link_speed); 515 | if (speed != (u32) priv->link_speed) { 516 | switch (speed) { 517 | case SPEED_10000: 518 | pr_debug("%s 10G link detected\n", PHY_NAME); 519 | #ifdef _EEE_ 520 | pr_err("DBG_EEE eee_enabled=%d\n", priv->eee_enabled); 521 | if (priv->eee_enabled) { 522 | } 523 | 524 | else { 525 | #if defined(_EEE) && defined(ETHTOOL_SEEE) 526 | MV88X3310_set_eee(priv /*, edata */ ); 527 | #endif 528 | } 529 | #endif 530 | break; 531 | case SPEED_1000: 532 | pr_debug("%s 1G link detected\n", PHY_NAME); 533 | break; 534 | case SPEED_1000X: 535 | pr_debug("%s 1GX link detected\n", PHY_NAME); 536 | break; 537 | case SPEED_5000: 538 | pr_debug("%s 5G link detected\n", PHY_NAME); 539 | break; 540 | case SPEED_2500: 541 | pr_debug("%s 2.5G link detected\n", PHY_NAME); 542 | break; 543 | case SPEED_100: 544 | pr_debug("%s 100M link detected\n", PHY_NAME); 545 | break; 546 | case SPEED_100X: 547 | pr_debug("%s 100MX link detected\n", PHY_NAME); 548 | break; 549 | default: 550 | pr_debug("%s link down.\n", PHY_NAME); 551 | break; 552 | } 553 | bdx_speed_changed(priv, speed); 554 | } 555 | link = 0; 556 | if ((!speed) 557 | || (!(link = (READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT)))) { 558 | u32 timeout; 559 | if (speed) { 560 | timeout = 1000000; /* 1/5 sec */ 561 | if (priv->link_loop_cnt++ > LINK_LOOP_MAX) { 562 | bdx_speed_changed(priv, 0); 563 | priv->link_loop_cnt = 0; 564 | pr_debug 565 | ("%s trying to recover link after %d tries\n", 566 | PHY_NAME, LINK_LOOP_MAX); 567 | } 568 | } else { 569 | timeout = 5000000; /* 1 sec */ 570 | } 571 | pr_debug("%s link = 0x%x speed = 0x%x setting %d timer\n", 572 | PHY_NAME, link, speed, timeout); 573 | WRITE_REG(priv, 0x5150, timeout); 574 | } 575 | 576 | return link; 577 | 578 | } 579 | 580 | void MV88X3310_leds(struct bdx_priv *priv, enum PHY_LEDS_OP op) 581 | { 582 | switch (op) { 583 | case PHY_LEDS_SAVE: 584 | priv->phy_ops.leds[0] = 585 | bdx_mdio_read(priv, 31, priv->phy_mdio_port, 586 | MV88X3310_LED_0); 587 | priv->phy_ops.leds[1] = 588 | bdx_mdio_read(priv, 31, priv->phy_mdio_port, 589 | MV88X3310_LED_1); 590 | priv->phy_ops.leds[2] = 591 | bdx_mdio_read(priv, 31, priv->phy_mdio_port, 592 | MV88X3310_LED_2); 593 | priv->phy_ops.leds[3] = 594 | bdx_mdio_read(priv, 31, priv->phy_mdio_port, 595 | MV88X3310_LED_3); 596 | break; 597 | 598 | case PHY_LEDS_RESTORE: 599 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_0, 600 | priv->phy_ops.leds[0]); 601 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_1, 602 | priv->phy_ops.leds[1]); 603 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_2, 604 | priv->phy_ops.leds[2]); 605 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_3, 606 | priv->phy_ops.leds[3]); 607 | break; 608 | 609 | case PHY_LEDS_ON: 610 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_0, 611 | 0xb8); 612 | 613 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_2, 614 | 0xb8); 615 | 616 | break; 617 | 618 | case PHY_LEDS_OFF: 619 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_0, 620 | 0); 621 | 622 | bdx_mdio_write(priv, 31, priv->phy_mdio_port, MV88X3310_LED_2, 623 | 0); 624 | 625 | break; 626 | 627 | default: 628 | pr_debug("unknown op 0x%x\n", op); 629 | break; 630 | 631 | } 632 | 633 | } 634 | 635 | __init enum PHY_TYPE MV88X3310_register(struct bdx_priv *priv) 636 | { 637 | enum PHY_TYPE phyType; 638 | 639 | priv->phy_ops.mdio_reset = MV88X3310_mdio_reset; 640 | priv->phy_ops.link_changed = MV88X3310_link_changed; 641 | priv->phy_ops.ledset = MV88X3310_leds; 642 | priv->phy_ops.mdio_speed = MDIO_SPEED_6MHZ; 643 | MV88X3310_register_settings(priv); 644 | 645 | phyType = 646 | (priv->deviceId == 647 | 0x4027) ? PHY_TYPE_MV88X3310 : PHY_TYPE_MV88E2010; 648 | 649 | return phyType; 650 | 651 | } 652 | -------------------------------------------------------------------------------- /tn40.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * tn40xx_ Driver 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | *******************************************************************************/ 11 | #ifndef _TN40XX_H 12 | #define _TN40XX_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define BDX_DRV_VERSION "linux-6.7.y-1" 40 | #define DRIVER_AUTHOR "Tehuti networks" 41 | #define BDX_DRV_DESC "Tehuti Network Driver from https://github.com/acooks/tn40xx-driver" 42 | #define BDX_NIC_NAME "tn40xx" 43 | #define BDX_DRV_NAME "tn40xx" 44 | 45 | /*#define _EEE_ */ 46 | #define TN40_THUNDERBOLT 47 | /*#define TN40_PTP */ 48 | 49 | #define TEHUTI_VID 0x1FC9 50 | #define DLINK_VID 0x1186 51 | #define ASUS_VID 0x1043 52 | #define EDIMAX_VID 0x1432 53 | #define PROMISE_VID 0x105a 54 | #define BUFFALO_VID 0x1154 55 | 56 | #define MDIO_SPEED_1MHZ (1) 57 | #define MDIO_SPEED_6MHZ (6) 58 | 59 | struct bdx_priv; 60 | u32 tbReadReg(struct bdx_priv *priv, u32 reg); 61 | #define READ_REG(pp, reg) tbReadReg(pp, reg) 62 | #define WRITE_REG(pp, reg, val) writel(val, pp->pBdxRegs + reg) 63 | 64 | enum LOAD_FW { 65 | NO_FW_LOAD = 0, 66 | FW_LOAD, 67 | }; 68 | 69 | /* Supported PHYs */ 70 | 71 | enum PHY_TYPE { 72 | PHY_TYPE_NA, /* Port not exists or unknown PHY */ 73 | PHY_TYPE_CX4, /* PHY works without initialization */ 74 | PHY_TYPE_QT2025, /* QT2025 10 Gbps SFP+ */ 75 | PHY_TYPE_MV88X3120, /* MV88X3120 10baseT */ 76 | PHY_TYPE_MV88X3310, /* MV88X3310 10NbaseT */ 77 | PHY_TYPE_MV88E2010, /* MV88E2010 5NbaseT */ 78 | PHY_TYPE_TLK10232, /* TI TLK10232 SFP+ */ 79 | PHY_TYPE_AQR105, /* AQR105 10baseT */ 80 | PHY_TYPE_CNT 81 | }; 82 | 83 | enum PHY_LEDS_OP { 84 | PHY_LEDS_SAVE, 85 | PHY_LEDS_RESTORE, 86 | PHY_LEDS_ON, 87 | PHY_LEDS_OFF, 88 | PHY_LEDS_CNT 89 | }; 90 | 91 | /* Supported devices */ 92 | struct bdx_device_descr { 93 | short vid; 94 | short pid; 95 | short subdev; 96 | enum PHY_TYPE phy_type; 97 | char *name; 98 | }; 99 | 100 | /* RX copy break size */ 101 | #define BDX_COPYBREAK 257 102 | 103 | /* 104 | * netdev tx queue len for Luxor. The default value is 1000. 105 | * ifconfig eth1 txqueuelen 3000 - to change it at runtime. 106 | */ 107 | #define BDX_NDEV_TXQ_LEN 3000 108 | 109 | #define FIFO_SIZE 4096 110 | #define FIFO_EXTRA_SPACE 1024 111 | 112 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 113 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 114 | 115 | #if BITS_PER_LONG == 64 116 | #define H32_64(x) (u32) ((u64)(x) >> 32) 117 | #define L32_64(x) (u32) ((u64)(x) & 0xffffffff) 118 | #elif BITS_PER_LONG == 32 119 | #define H32_64(x) 0 120 | #define L32_64(x) ((u32) (x)) 121 | #else /* BITS_PER_LONG == ?? */ 122 | #error BITS_PER_LONG is undefined. Must be 64 or 32 123 | #endif /* BITS_PER_LONG */ 124 | 125 | #ifdef __BIG_ENDIAN 126 | #define CPU_CHIP_SWAP32(x) (swab32(x)) 127 | #define CPU_CHIP_SWAP16(x) (swab16(x)) 128 | #else 129 | #define CPU_CHIP_SWAP32(x) (x) 130 | #define CPU_CHIP_SWAP16(x) (x) 131 | #endif 132 | 133 | #ifndef DMA_64BIT_MASK 134 | #define DMA_64BIT_MASK 0xffffffffffffffffULL 135 | #endif 136 | 137 | #ifndef DMA_32BIT_MASK 138 | #define DMA_32BIT_MASK 0x00000000ffffffffULL 139 | #endif 140 | 141 | #ifndef NET_IP_ALIGN 142 | #define NET_IP_ALIGN 2 143 | #endif 144 | 145 | #ifndef NETDEV_TX_OK 146 | #define NETDEV_TX_OK 0 147 | #endif 148 | 149 | #define LUXOR_MAX_PORT 2 150 | #define BDX_MAX_RX_DONE 150 151 | #define BDX_TXF_DESC_SZ 16 152 | #define BDX_MAX_TX_LEVEL (priv->txd_fifo0.memsz - 16) 153 | #define BDX_MIN_TX_LEVEL 256 154 | #define BDX_NO_UPD_PACKETS 40 155 | #define BDX_MAX_MTU (1 << 14) 156 | struct pci_nic { 157 | void __iomem *regs; 158 | struct bdx_priv *priv; 159 | }; 160 | 161 | #define PCK_TH_MULT 128 162 | #define INT_COAL_MULT 2 163 | 164 | #define BITS_MASK(nbits) ((1 << nbits)-1) 165 | #define GET_BITS_SHIFT(x, nbits, nshift) (((x) >> nshift)&BITS_MASK(nbits)) 166 | #define BITS_SHIFT_MASK(nbits, nshift) (BITS_MASK(nbits) << nshift) 167 | #define BITS_SHIFT_VAL(x, nbits, nshift) (((x) & BITS_MASK(nbits)) << nshift) 168 | #define BITS_SHIFT_CLEAR(x, nbits, nshift) \ 169 | ((x)&(~BITS_SHIFT_MASK(nbits, nshift))) 170 | 171 | #define GET_INT_COAL(x) GET_BITS_SHIFT(x, 15, 0) 172 | #define GET_INT_COAL_RC(x) GET_BITS_SHIFT(x, 1, 15) 173 | #define GET_RXF_TH(x) GET_BITS_SHIFT(x, 4, 16) 174 | #define GET_PCK_TH(x) GET_BITS_SHIFT(x, 4, 20) 175 | 176 | #define INT_REG_VAL(coal, coal_rc, rxf_th, pck_th) \ 177 | ((coal) | ((coal_rc) << 15) | ((rxf_th) << 16) | ((pck_th) << 20)) 178 | 179 | struct fifo { 180 | dma_addr_t da; /* Physical address of fifo (used by HW) */ 181 | char *va; /* Virtual address of fifo (used by SW) */ 182 | u32 rptr, wptr; /* Cached values of RPTR and WPTR registers, 183 | they're 32 bits on both 32 and 64 archs */ 184 | u16 reg_CFG0, reg_CFG1; 185 | u16 reg_RPTR, reg_WPTR; 186 | u16 memsz; /* Memory size allocated for fifo */ 187 | u16 size_mask; 188 | u16 pktsz; /* Skb packet size to allocate */ 189 | u16 rcvno; /* Number of buffers that come from this RXF */ 190 | }; 191 | 192 | struct bdx_page { 193 | struct list_head free; 194 | int ref_count; 195 | int reuse_tries; 196 | int page_index; 197 | struct page *page; 198 | u64 dma; 199 | }; 200 | struct rx_map { 201 | struct bdx_page *bdx_page; 202 | u64 dma; 203 | struct sk_buff *skb; 204 | u32 off; 205 | u32 size; /* Mapped area (i.e. page) size */ 206 | }; 207 | 208 | struct rxdb { 209 | int *stack; 210 | struct rx_map *elems; 211 | int nelem; 212 | int top; 213 | void *pkt; 214 | }; 215 | 216 | union bdx_dma_addr { 217 | dma_addr_t dma; 218 | struct sk_buff *skb; 219 | }; 220 | 221 | /* 222 | * Entry in the db. 223 | * if len == 0 addr is dma 224 | * if len != 0 addr is skb 225 | */ 226 | struct tx_map { 227 | union bdx_dma_addr addr; 228 | int len; 229 | }; 230 | 231 | /* tx database - implemented as circular fifo buffer*/ 232 | struct txdb { 233 | struct tx_map *start; /* Points to the first element */ 234 | struct tx_map *end; /* Points just AFTER the last element */ 235 | struct tx_map *rptr; /* Points to the next element to read */ 236 | struct tx_map *wptr; /* Points to the next element to write */ 237 | int size; /* Number of elements in the db */ 238 | }; 239 | 240 | /*Internal stats structure*/ 241 | struct bdx_stats { 242 | u64 InUCast; /* 0x7200 */ 243 | u64 InMCast; /* 0x7210 */ 244 | u64 InBCast; /* 0x7220 */ 245 | u64 InPkts; /* 0x7230 */ 246 | u64 InErrors; /* 0x7240 */ 247 | u64 InDropped; /* 0x7250 */ 248 | u64 FrameTooLong; /* 0x7260 */ 249 | u64 FrameSequenceErrors; /* 0x7270 */ 250 | u64 InVLAN; /* 0x7280 */ 251 | u64 InDroppedDFE; /* 0x7290 */ 252 | u64 InDroppedIntFull; /* 0x72A0 */ 253 | u64 InFrameAlignErrors; /* 0x72B0 */ 254 | 255 | /* 0x72C0-0x72E0 RSRV */ 256 | 257 | u64 OutUCast; /* 0x72F0 */ 258 | u64 OutMCast; /* 0x7300 */ 259 | u64 OutBCast; /* 0x7310 */ 260 | u64 OutPkts; /* 0x7320 */ 261 | 262 | /* 0x7330-0x7360 RSRV */ 263 | 264 | u64 OutVLAN; /* 0x7370 */ 265 | u64 InUCastOctects; /* 0x7380 */ 266 | u64 OutUCastOctects; /* 0x7390 */ 267 | 268 | /* 0x73A0-0x73B0 RSRV */ 269 | 270 | u64 InBCastOctects; /* 0x73C0 */ 271 | u64 OutBCastOctects; /* 0x73D0 */ 272 | u64 InOctects; /* 0x73E0 */ 273 | u64 OutOctects; /* 0x73F0 */ 274 | }; 275 | #define PHY_LEDS (4) 276 | struct bdx_phy_operations { 277 | unsigned short leds[PHY_LEDS]; 278 | int (*mdio_reset)(struct bdx_priv *, int, unsigned short); 279 | u32(*link_changed) (struct bdx_priv *); 280 | void (*ledset)(struct bdx_priv *, enum PHY_LEDS_OP); 281 | int (*get_link_ksettings)(struct net_device *, 282 | struct ethtool_link_ksettings *); 283 | int (*set_link_ksettings)(struct net_device *, 284 | const struct ethtool_link_ksettings *); 285 | #ifdef _EEE_ 286 | #ifdef ETHTOOL_GEEE 287 | int (*get_eee)(struct net_device *, struct ethtool_eee *); 288 | #endif 289 | #ifdef ETHTOOL_SEEE 290 | int (*set_eee)(struct bdx_priv *); 291 | #endif 292 | int (*reset_eee)(struct bdx_priv *); 293 | #endif 294 | u32 mdio_speed; 295 | }; 296 | 297 | struct bdx_rx_page_table { 298 | int page_size; 299 | int buf_size; 300 | struct bdx_page *bdx_pages; 301 | int nPages; 302 | int nFrees; 303 | int max_frees; 304 | int page_order; 305 | gfp_t gfp_mask; 306 | int nBufInPage; 307 | struct list_head free_list; 308 | }; 309 | 310 | struct bdx_priv { 311 | void __iomem *pBdxRegs; 312 | struct net_device *ndev; 313 | struct napi_struct napi; 314 | /* RX FIFOs: 1 for data (full) descs, and 2 for free descs */ 315 | struct fifo rxd_fifo0; 316 | struct fifo rxf_fifo0; 317 | struct rxdb *rxdb0; /* Rx dbs to store skb pointers */ 318 | struct vlan_group *vlgrp; 319 | /* Tx FIFOs: 1 for data desc, 1 for empty (acks) desc */ 320 | struct fifo txd_fifo0; 321 | struct fifo txf_fifo0; 322 | struct txdb txdb; 323 | int tx_level; 324 | int tx_update_mark; 325 | int tx_noupd; 326 | 327 | /* Rarely used */ 328 | u8 phy_mdio_port; 329 | enum PHY_TYPE phy_type; 330 | int stats_flag; 331 | struct bdx_stats hw_stats; 332 | struct net_device_stats net_stats; 333 | struct pci_dev *pdev; 334 | struct pci_nic *nic; 335 | u8 txd_size; 336 | u8 txf_size; 337 | u8 rxd_size; 338 | u8 rxf_size; 339 | u32 rdintcm; 340 | u32 tdintcm; 341 | u16 id; 342 | u32 isr_mask; 343 | int link_speed; /* 0- no link or SPEED_100 SPEED_1000 SPEED_10000 */ 344 | u32 link_loop_cnt; 345 | u32 sfp_mod_type; 346 | struct bdx_phy_operations phy_ops; 347 | /* SHORT_PKT_FIX */ 348 | u32 b0_len; 349 | dma_addr_t b0_dma; /* Physical address of buffer */ 350 | char *b0_va; /* Virtual address of buffer */ 351 | u32 errmsg_count; 352 | /* SHORT_PKT_FIX end */ 353 | u16 deviceId; 354 | u16 subsystem_vendor; 355 | u16 subsystem_device; 356 | u32 advertising, autoneg; 357 | #ifdef __ETHTOOL_DECLARE_LINK_MODE_MASK 358 | __ETHTOOL_DECLARE_LINK_MODE_MASK(link_advertising); 359 | #endif 360 | u32 eee_enabled; 361 | struct bdx_rx_page_table rx_page_table; 362 | #ifdef TN40_THUNDERBOLT 363 | int bDeviceRemoved; 364 | #endif 365 | }; 366 | #if !defined(SPEED_5000) 367 | #define SPEED_5000 (5000) 368 | #endif 369 | #if !defined(SPEED_2500) 370 | #define SPEED_2500 (2500) 371 | #endif 372 | #define SPEED_1000X (1001) 373 | #define SPEED_100X (101) 374 | 375 | #define MAX_ERRMSGS (3) 376 | /* RX FREE descriptor - 64bit*/ 377 | struct rxf_desc { 378 | u32 info; /* Buffer Count + Info - described below */ 379 | u32 va_lo; /* VAdr[31:0] */ 380 | u32 va_hi; /* VAdr[63:32] */ 381 | u32 pa_lo; /* PAdr[31:0] */ 382 | u32 pa_hi; /* PAdr[63:32] */ 383 | u32 len; /* Buffer Length */ 384 | }; 385 | 386 | #define GET_RXD_BC(x) GET_BITS_SHIFT((x), 5, 0) 387 | #define GET_RXD_RXFQ(x) GET_BITS_SHIFT((x), 2, 8) 388 | #define GET_RXD_TO(x) GET_BITS_SHIFT((x), 1, 15) 389 | #define GET_RXD_TYPE(x) GET_BITS_SHIFT((x), 4, 16) 390 | #define GET_RXD_ERR(x) GET_BITS_SHIFT((x), 6, 21) 391 | #define GET_RXD_RXP(x) GET_BITS_SHIFT((x), 1, 27) 392 | #define GET_RXD_PKT_ID(x) GET_BITS_SHIFT((x), 3, 28) 393 | #define GET_RXD_VTAG(x) GET_BITS_SHIFT((x), 1, 31) 394 | #define GET_RXD_VLAN_ID(x) GET_BITS_SHIFT((x), 12, 0) 395 | #define GET_RXD_VLAN_TCI(x) GET_BITS_SHIFT((x), 16, 0) 396 | #define GET_RXD_CFI(x) GET_BITS_SHIFT((x), 1, 12) 397 | #define GET_RXD_PRIO(x) GET_BITS_SHIFT((x), 3, 13) 398 | 399 | #define GET_RSS_FUNC(x) GET_BITS_SHIFT((x), 2, 0) 400 | #define GET_RSS_TYPE(x) GET_BITS_SHIFT((x), 8, 8) 401 | #define GET_RSS_TCPU(x) GET_BITS_SHIFT((x), 8, 16) 402 | 403 | /* GET_RXD_ERR(x) error types: */ 404 | #define IS_FCS_ERR(x) ((x) & 0x4) /* Frame Check Sequence Error */ 405 | #define RXD_ERR_UDP_CSUM 0x8 406 | #define RXD_ERR_TCP_CSUM 0x10 407 | 408 | /* GET_RXD_PKT_ID(x) can return these known values: */ 409 | #define PKT_ID_TCP 1 410 | #define PKT_ID_UDP 2 411 | 412 | struct rxd_desc { 413 | u32 rxd_val1; 414 | u16 len; 415 | u16 rxd_vlan; 416 | u32 va_lo; 417 | u32 va_hi; 418 | u32 rss_lo; 419 | u32 rss_hash; 420 | }; 421 | 422 | #define MAX_PBL (19) 423 | /* PBL describes each virtual buffer to be transmitted from the host. */ 424 | struct pbl { 425 | u32 pa_lo; 426 | u32 pa_hi; 427 | u32 len; 428 | }; 429 | 430 | /* 431 | * First word for TXD descriptor. It means: type = 3 for regular Tx packet, 432 | * hw_csum = 7 for IP+UDP+TCP HW checksums. 433 | */ 434 | #define TXD_W1_VAL(bc, checksum, vtag, lgsnd, vlan_id) \ 435 | ((bc) | ((checksum) << 5) | ((vtag) << 8) | \ 436 | ((lgsnd) << 9) | (0x30000) | ((vlan_id & 0x0fff) << 20) | (((vlan_id >> 13) & 7) << 13)) 437 | 438 | struct txd_desc { 439 | u32 txd_val1; 440 | u16 mss; 441 | u16 length; 442 | u32 va_lo; 443 | u32 va_hi; 444 | struct pbl pbl[0]; /* Fragments */ 445 | } __attribute__((packed)); 446 | 447 | struct txf_desc { 448 | u32 status; 449 | u32 va_lo; /* VAdr[31:0] */ 450 | u32 va_hi; /* VAdr[63:32] */ 451 | u32 pad; 452 | } __attribute__((packed)); 453 | 454 | /* Register region size */ 455 | #define BDX_REGS_SIZE 0x10000 456 | 457 | /* Registers from 0x0000-0x00fc were remapped to 0x4000-0x40fc */ 458 | #define regTXD_CFG1_0 0x4000 459 | #define regTXD_CFG1_1 0x4004 460 | #define regTXD_CFG1_2 0x4008 461 | #define regTXD_CFG1_3 0x400C 462 | 463 | #define regRXF_CFG1_0 0x4010 464 | #define regRXF_CFG1_1 0x4014 465 | #define regRXF_CFG1_2 0x4018 466 | #define regRXF_CFG1_3 0x401C 467 | 468 | #define regRXD_CFG1_0 0x4020 469 | #define regRXD_CFG1_1 0x4024 470 | #define regRXD_CFG1_2 0x4028 471 | #define regRXD_CFG1_3 0x402C 472 | 473 | #define regTXF_CFG1_0 0x4030 474 | #define regTXF_CFG1_1 0x4034 475 | #define regTXF_CFG1_2 0x4038 476 | #define regTXF_CFG1_3 0x403C 477 | 478 | #define regTXD_CFG0_0 0x4040 479 | #define regTXD_CFG0_1 0x4044 480 | #define regTXD_CFG0_2 0x4048 481 | #define regTXD_CFG0_3 0x404C 482 | 483 | #define regRXF_CFG0_0 0x4050 484 | #define regRXF_CFG0_1 0x4054 485 | #define regRXF_CFG0_2 0x4058 486 | #define regRXF_CFG0_3 0x405C 487 | 488 | #define regRXD_CFG0_0 0x4060 489 | #define regRXD_CFG0_1 0x4064 490 | #define regRXD_CFG0_2 0x4068 491 | #define regRXD_CFG0_3 0x406C 492 | 493 | #define regTXF_CFG0_0 0x4070 494 | #define regTXF_CFG0_1 0x4074 495 | #define regTXF_CFG0_2 0x4078 496 | #define regTXF_CFG0_3 0x407C 497 | 498 | #define regTXD_WPTR_0 0x4080 499 | #define regTXD_WPTR_1 0x4084 500 | #define regTXD_WPTR_2 0x4088 501 | #define regTXD_WPTR_3 0x408C 502 | 503 | #define regRXF_WPTR_0 0x4090 504 | #define regRXF_WPTR_1 0x4094 505 | #define regRXF_WPTR_2 0x4098 506 | #define regRXF_WPTR_3 0x409C 507 | 508 | #define regRXD_WPTR_0 0x40A0 509 | #define regRXD_WPTR_1 0x40A4 510 | #define regRXD_WPTR_2 0x40A8 511 | #define regRXD_WPTR_3 0x40AC 512 | 513 | #define regTXF_WPTR_0 0x40B0 514 | #define regTXF_WPTR_1 0x40B4 515 | #define regTXF_WPTR_2 0x40B8 516 | #define regTXF_WPTR_3 0x40BC 517 | 518 | #define regTXD_RPTR_0 0x40C0 519 | #define regTXD_RPTR_1 0x40C4 520 | #define regTXD_RPTR_2 0x40C8 521 | #define regTXD_RPTR_3 0x40CC 522 | 523 | #define regRXF_RPTR_0 0x40D0 524 | #define regRXF_RPTR_1 0x40D4 525 | #define regRXF_RPTR_2 0x40D8 526 | #define regRXF_RPTR_3 0x40DC 527 | 528 | #define regRXD_RPTR_0 0x40E0 529 | #define regRXD_RPTR_1 0x40E4 530 | #define regRXD_RPTR_2 0x40E8 531 | #define regRXD_RPTR_3 0x40EC 532 | 533 | #define regTXF_RPTR_0 0x40F0 534 | #define regTXF_RPTR_1 0x40F4 535 | #define regTXF_RPTR_2 0x40F8 536 | #define regTXF_RPTR_3 0x40FC 537 | 538 | /* Hardware versioning */ 539 | #define FW_VER 0x5010 540 | #define SROM_VER 0x5020 541 | #define FPGA_VER 0x5030 542 | #define FPGA_SEED 0x5040 543 | 544 | /* Registers from 0x0100-0x0150 were remapped to 0x5100-0x5150 */ 545 | #define regISR regISR0 546 | #define regISR0 0x5100 547 | 548 | #define regIMR regIMR0 549 | #define regIMR0 0x5110 550 | 551 | #define regRDINTCM0 0x5120 552 | #define regRDINTCM2 0x5128 553 | 554 | #define regTDINTCM0 0x5130 555 | 556 | #define regISR_MSK0 0x5140 557 | 558 | #define regINIT_SEMAPHORE 0x5170 559 | #define regINIT_STATUS 0x5180 560 | 561 | #define regMAC_LNK_STAT 0x0200 562 | #define MAC_LINK_STAT 0x0004 /* Link state */ 563 | 564 | #define regBLNK_LED 0x0210 565 | 566 | #define regGMAC_RXF_A 0x1240 567 | 568 | #define regUNC_MAC0_A 0x1250 569 | #define regUNC_MAC1_A 0x1260 570 | #define regUNC_MAC2_A 0x1270 571 | 572 | #define regVLAN_0 0x1800 573 | 574 | #define regMAX_FRAME_A 0x12C0 575 | 576 | #define regRX_MAC_MCST0 0x1A80 577 | #define regRX_MAC_MCST1 0x1A84 578 | #define MAC_MCST_NUM 15 579 | #define regRX_MCST_HASH0 0x1A00 580 | #define MAC_MCST_HASH_NUM 8 581 | 582 | #define regVPC 0x2300 583 | #define regVIC 0x2320 584 | #define regVGLB 0x2340 585 | 586 | #define regCLKPLL 0x5000 587 | 588 | /* MDIO interface */ 589 | 590 | #define regMDIO_CMD_STAT 0x6030 591 | #define regMDIO_CMD 0x6034 592 | #define regMDIO_DATA 0x6038 593 | #define regMDIO_ADDR 0x603C 594 | #define GET_MDIO_BUSY(x) GET_BITS_SHIFT(x, 1, 0) 595 | #define GET_MDIO_RD_ERR(x) GET_BITS_SHIFT(x, 1, 1) 596 | 597 | /*for 10G only*/ 598 | #define regRSS_CNG 0x000000b0 599 | 600 | #define RSS_ENABLED 0x00000001 601 | #define RSS_HFT_TOEPLITZ 0x00000002 602 | #define RSS_HASH_IPV4 0x00000100 603 | #define RSS_HASH_TCP_IPV4 0x00000200 604 | #define RSS_HASH_IPV6 0x00000400 605 | #define RSS_HASH_IPV6_EX 0x00000800 606 | #define RSS_HASH_TCP_IPV6 0x00001000 607 | #define RSS_HASH_TCP_IPV6_EX 0x00002000 608 | 609 | #define regRSS_HASH_BASE 0x0400 610 | #define RSS_HASH_LEN 40 611 | #define regRSS_INDT_BASE 0x0600 612 | #define RSS_INDT_LEN 256 613 | 614 | #define regREVISION 0x6000 615 | #define regSCRATCH 0x6004 616 | #define regCTRLST 0x6008 617 | #define regMAC_ADDR_0 0x600C 618 | #define regMAC_ADDR_1 0x6010 619 | #define regFRM_LENGTH 0x6014 620 | #define regPAUSE_QUANT 0x6054 621 | #define regRX_FIFO_SECTION 0x601C 622 | #define regTX_FIFO_SECTION 0x6020 623 | #define regRX_FULLNESS 0x6024 624 | #define regTX_FULLNESS 0x6028 625 | #define regHASHTABLE 0x602C 626 | 627 | #define regRST_PORT 0x7000 628 | #define regDIS_PORT 0x7010 629 | #define regRST_QU 0x7020 630 | #define regDIS_QU 0x7030 631 | 632 | #define regCTRLST_TX_ENA 0x0001 633 | #define regCTRLST_RX_ENA 0x0002 634 | #define regCTRLST_PRM_ENA 0x0010 635 | #define regCTRLST_PAD_ENA 0x0020 636 | 637 | #define regCTRLST_BASE (regCTRLST_PAD_ENA|regCTRLST_PRM_ENA) 638 | 639 | #define regRX_FLT 0x1400 640 | 641 | /* TXD TXF RXF RXD CONFIG 0x0000 --- 0x007c*/ 642 | #define TX_RX_CFG1_BASE 0xffffffff /*0-31 */ 643 | #define TX_RX_CFG0_BASE 0xfffff000 /*31:12 */ 644 | #define TX_RX_CFG0_RSVD 0x00000ffc /*11:2 */ 645 | #define TX_RX_CFG0_SIZE 0x00000003 /*1:0 */ 646 | 647 | /* TXD TXF RXF RXD WRITE 0x0080 --- 0x00BC */ 648 | #define TXF_WPTR_WR_PTR 0x00007ff8 /*14:3 */ 649 | 650 | /* TXD TXF RXF RXD READ 0x00CO --- 0x00FC */ 651 | #define TXF_RPTR_RD_PTR 0x00007ff8 /*14:3 */ 652 | 653 | #define TXF_WPTR_MASK 0x7ff0 /* The last 4 bits are dropped 654 | * size is rounded to 16 */ 655 | 656 | /* regISR 0x0100 */ 657 | /* regIMR 0x0110 */ 658 | #define IMR_INPROG 0x80000000 /*31 */ 659 | #define IR_LNKCHG1 0x10000000 /*28 */ 660 | #define IR_LNKCHG0 0x08000000 /*27 */ 661 | #define IR_GPIO 0x04000000 /*26 */ 662 | #define IR_RFRSH 0x02000000 /*25 */ 663 | #define IR_RSVD 0x01000000 /*24 */ 664 | #define IR_SWI 0x00800000 /*23 */ 665 | #define IR_RX_FREE_3 0x00400000 /*22 */ 666 | #define IR_RX_FREE_2 0x00200000 /*21 */ 667 | #define IR_RX_FREE_1 0x00100000 /*20 */ 668 | #define IR_RX_FREE_0 0x00080000 /*19 */ 669 | #define IR_TX_FREE_3 0x00040000 /*18 */ 670 | #define IR_TX_FREE_2 0x00020000 /*17 */ 671 | #define IR_TX_FREE_1 0x00010000 /*16 */ 672 | #define IR_TX_FREE_0 0x00008000 /*15 */ 673 | #define IR_RX_DESC_3 0x00004000 /*14 */ 674 | #define IR_RX_DESC_2 0x00002000 /*13 */ 675 | #define IR_RX_DESC_1 0x00001000 /*12 */ 676 | #define IR_RX_DESC_0 0x00000800 /*11 */ 677 | #define IR_PSE 0x00000400 /*10 */ 678 | #define IR_TMR3 0x00000200 /* 9 */ 679 | #define IR_TMR2 0x00000100 /* 8 */ 680 | #define IR_TMR1 0x00000080 /* 7 */ 681 | #define IR_TMR0 0x00000040 /* 6 */ 682 | #define IR_VNT 0x00000020 /* 5 */ 683 | #define IR_RxFL 0x00000010 /* 4 */ 684 | #define IR_SDPERR 0x00000008 /* 3 */ 685 | #define IR_TR 0x00000004 /* 2 */ 686 | #define IR_PCIE_LINK 0x00000002 /* 1 */ 687 | #define IR_PCIE_TOUT 0x00000001 /* 0 */ 688 | 689 | #define IR_EXTRA (IR_RX_FREE_0 | IR_LNKCHG0 | IR_LNKCHG1 | IR_PSE | \ 690 | IR_TMR0 | IR_PCIE_LINK | IR_PCIE_TOUT) 691 | #define IR_RUN (IR_EXTRA | IR_RX_DESC_0 | IR_TX_FREE_0) 692 | #define IR_ALL 0xfdfffff7 693 | 694 | #define IR_LNKCHG0_ofst 27 695 | 696 | #define GMAC_RX_FILTER_OSEN 0x1000 /* shared OS enable */ 697 | #define GMAC_RX_FILTER_TXFC 0x0400 /* Tx flow control */ 698 | #define GMAC_RX_FILTER_RSV0 0x0200 /* reserved */ 699 | #define GMAC_RX_FILTER_FDA 0x0100 /* filter out direct address */ 700 | #define GMAC_RX_FILTER_AOF 0x0080 /* accept over run */ 701 | #define GMAC_RX_FILTER_ACF 0x0040 /* accept control frames */ 702 | #define GMAC_RX_FILTER_ARUNT 0x0020 /* accept under run */ 703 | #define GMAC_RX_FILTER_ACRC 0x0010 /* accept crc error */ 704 | #define GMAC_RX_FILTER_AM 0x0008 /* accept multicast */ 705 | #define GMAC_RX_FILTER_AB 0x0004 /* accept broadcast */ 706 | #define GMAC_RX_FILTER_PRM 0x0001 /* [0:1] promiscuous mode */ 707 | 708 | #define MAX_FRAME_AB_VAL 0x3fff /* 13:0 */ 709 | 710 | #define CLKPLL_PLLLKD 0x0200 /* 9 */ 711 | #define CLKPLL_RSTEND 0x0100 /* 8 */ 712 | #define CLKPLL_SFTRST 0x0001 /* 0 */ 713 | 714 | #define CLKPLL_LKD (CLKPLL_PLLLKD|CLKPLL_RSTEND) 715 | 716 | /* 717 | * PCI-E Device Control Register (Offset 0x88) 718 | * Source: Luxor Data Sheet, 7.1.3.3.3 719 | */ 720 | #define PCI_DEV_CTRL_REG 0x88 721 | #define GET_DEV_CTRL_MAXPL(x) GET_BITS_SHIFT(x, 3, 5) 722 | #define GET_DEV_CTRL_MRRS(x) GET_BITS_SHIFT(x, 3, 12) 723 | 724 | /* 725 | * PCI-E Link Status Register (Offset 0x92) 726 | * Source: Luxor Data Sheet, 7.1.3.3.7 727 | */ 728 | #define PCI_LINK_STATUS_REG 0x92 729 | #define GET_LINK_STATUS_LANES(x) GET_BITS_SHIFT(x, 6, 4) 730 | 731 | #if !defined(netdev_mc_count) 732 | #define netdev_mc_count(dev) ((dev)->mc_count) 733 | #define netdev_for_each_mc_addr(mclist, dev) \ 734 | for (mclist = dev->mc_list; mclist; mclist = mclist->next) 735 | #endif 736 | 737 | #define dev_mc_list netdev_hw_addr 738 | #define dmi_addr addr 739 | 740 | /* 741 | * Note: 32 bit kernels use 16 bits for page_offset. Do not increase 742 | * LUXOR__MAX_PAGE_SIZE beyind 64K! 743 | */ 744 | #if BITS_PER_LONG > 32 745 | #define LUXOR__MAX_PAGE_SIZE 0x40000 746 | #else 747 | #define LUXOR__MAX_PAGE_SIZE 0x10000 748 | #endif 749 | 750 | #if defined(NETIF_F_GRO) 751 | #define IS_GRO(ndev) ((ndev->features & NETIF_F_GRO) != 0) 752 | #else 753 | #define NETIF_F_GRO 0 754 | 755 | #define IS_GRO(ndev) 0 756 | #endif 757 | 758 | #if !defined(NETIF_F_VLAN_TSO) 759 | #define NETIF_F_VLAN_TSO 0 /* RHEL specific flag */ 760 | #endif 761 | #if !defined(NETIF_F_VLAN_CSUM) 762 | #define NETIF_F_VLAN_CSUM 0 /* RHEL specific flag */ 763 | #endif 764 | #if !defined(NETIF_F_RXHASH) 765 | #define NETIF_F_RXHASH 0 766 | #endif 767 | 768 | #if !defined(MAX) 769 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 770 | #endif 771 | #if !defined(MIN) 772 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 773 | #endif 774 | #if !defined(ROUND_UP) 775 | #define ROUND_UP(n, m) (((n) + (m - 1)) & ~(m - 1)) 776 | #endif 777 | 778 | u32 bdx_mdio_get(struct bdx_priv *priv); 779 | int bdx_mdio_write(struct bdx_priv *priv, int device, int port, u16 addr, 780 | u16 data); 781 | u16 bdx_mdio_read(struct bdx_priv *priv, int device, int port, u16 addr); 782 | int bdx_speed_set(struct bdx_priv *priv, u32 speed); 783 | void bdx_speed_changed(struct bdx_priv *priv, u32 speed); 784 | 785 | #define PHY_MDIO_READ(priv,device,addr) bdx_mdio_read(priv,(device),(priv)->phy_mdio_port,(addr)) 786 | #define PHY_MDIO_WRITE(priv,device,addr,data) bdx_mdio_write((priv),(device),(priv)->phy_mdio_port, (addr), (data)) 787 | 788 | #define BDX_MDIO_WRITE(priv, space, addr, val) \ 789 | if (bdx_mdio_write((priv), (space), port, (addr), (val))) { \ 790 | pr_err("bdx: failed to write to phy at %x.%x val %x\n", \ 791 | (space),(addr),(val)); \ 792 | return 1; \ 793 | } 794 | 795 | enum PHY_TYPE MV88X3310_register(struct bdx_priv *priv); 796 | enum PHY_TYPE MV88X3120_register(struct bdx_priv *priv); 797 | enum PHY_TYPE QT2025_register(struct bdx_priv *priv); 798 | enum PHY_TYPE CX4_register(struct bdx_priv *priv); 799 | enum PHY_TYPE TLK10232_register(struct bdx_priv *priv); 800 | enum PHY_TYPE AQR105_register(struct bdx_priv *priv); 801 | 802 | #ifndef vlan_tx_tag_present 803 | #define vlan_tx_tag_present skb_vlan_tag_present 804 | #endif 805 | #ifndef vlan_tx_tag_get 806 | #define vlan_tx_tag_get skb_vlan_tag_get 807 | #endif 808 | 809 | #endif /* _TN40XX_H */ 810 | --------------------------------------------------------------------------------