/* * EMAC driver for NVCom-02TEM-3U evaluation kit * * Copyright (c) 2020 Elvees (support@elvees.com) * Author: Dmitry Evtushenko * */ #include #include #include #include #include #ifdef CONFIG_MC30SF6 #include #else #include #endif #include #include "ctl.h" #include "emac.h" void etool_get_drvinfo( struct net_device *pndev, struct ethtool_drvinfo *pinf) { strcpy( pinf->driver, MODULE_NAME); strcpy( pinf->version, DRIVER_VERSION); strcpy( pinf->fw_version, CARD_VERSION); strcpy( pinf->bus_info, "Elvees AMBA"); } int etool_get_settings( struct net_device *pndev, struct ethtool_cmd *pcmd) { mc_emac_t *pe = netdev_priv(pndev); u32 ctl; #ifdef CONFIG_MC30SF6 u32 phy_hcdspeed; #endif //CONFIG_MC30SF6 pr_info( "etool_get_settings: cmd=%Xh\n", pcmd->cmd); memset( pcmd, 0, sizeof(*pcmd)); pcmd->phy_address = pe->phy; pcmd->supported = SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_MII; pcmd->advertising = ADVERTISED_Autoneg | ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_MII; if( !mc_phy_read( pe, PHY_CTL, &ctl)) { pr_info( "etool_get_settings: PHY_CTL reading ERROR\n"); return RC_EMAC_ERROR; } pcmd->autoneg = (ctl & PHY_CTL_ANEG_EN) ? (1) : (0); pcmd->port = PORT_MII; pcmd->transceiver = XCVR_EXTERNAL; #ifdef CONFIG_MC30SF6 if( !mc_phy_read( pe, PHY_SCS, &phy_hcdspeed)) { pr_info( "etool_get_settings: PHY_SCS reading ERROR\n"); return RC_EMAC_ERROR; } phy_hcdspeed &= PHY_SCS_HCDSPD_MSK; switch( phy_hcdspeed) { case PHY_SCS_HCDSPD_10HD: // 10Base-T half duplex pcmd->duplex = DUPLEX_HALF; pcmd->speed = SPEED_10; break; case PHY_SCS_HCDSPD_10FD: // 10Base-T full duplex pcmd->duplex = DUPLEX_FULL; pcmd->speed = SPEED_10; break; case PHY_SCS_HCDSPD_100HD: // 100Base-TX half duplex pcmd->duplex = DUPLEX_HALF; pcmd->speed = SPEED_100; break; case PHY_SCS_HCDSPD_100FD: // 100Base-TX full duplex pcmd->duplex = DUPLEX_FULL; pcmd->speed = SPEED_100; break; default: return RC_EMAC_SUCCESS; } #else if( !mc_phy_read( pe, PHY_EXTCTL, &ctl)) { pr_info( "etool_get_settings: PHY_EXTCTL reading ERROR\n"); return RC_EMAC_ERROR; } switch( ctl & PHY_EXTCTL_MODE_MASK) { case PHY_EXTCTL_MODE_10_HDX: /* 10Base-T half duplex */ pcmd->duplex = DUPLEX_HALF; pcmd->speed = SPEED_10; break; case PHY_EXTCTL_MODE_100_HDX: /* 100Base-TX half duplex */ pcmd->duplex = DUPLEX_HALF; pcmd->speed = SPEED_100; break; case PHY_EXTCTL_MODE_10_FDX: /* 10Base-T full duplex */ pcmd->duplex = DUPLEX_FULL; pcmd->speed = SPEED_10; break; case PHY_EXTCTL_MODE_100_FDX: /* 100Base-TX full duplex */ pcmd->duplex = DUPLEX_FULL; pcmd->speed = SPEED_100; break; default: return RC_EMAC_SUCCESS; } #endif return RC_EMAC_SUCCESS; } /*static void etool_print_set_settings( struct ethtool_cmd *pcmd) { pr_info( "ethtool set settings:\n"); pr_info("cmd : %Xh\n", pcmd->cmd); pr_info("supported : %Xh\n", pcmd->supported); pr_info("advertising : %Xh\n", pcmd->advertising); pr_info("speed : %u\n", pcmd->speed); pr_info("duplex : %Xh\n", pcmd->duplex); pr_info("port : %Xh\n", pcmd->port); pr_info("phy_address : %Xh\n", pcmd->phy_address); pr_info("transceiver : %Xh\n", pcmd->transceiver); pr_info("autoneg : %u\n", pcmd->autoneg); pr_info("mdio_support : %u\n", pcmd->mdio_support); pr_info("maxtxpkt : %Xh\n", pcmd->maxtxpkt); pr_info("maxrxpkt : %Xh\n", pcmd->maxrxpkt); pr_info("speed_hi : %u\n", pcmd->speed_hi); pr_info("eth_tp_mdix : %u\n", pcmd->eth_tp_mdix); pr_info("eth_tp_mdix_ctrl : %u\n", pcmd->eth_tp_mdix_ctrl); pr_info("lp_advertising : %Xh\n", pcmd->lp_advertising); }*/ int etool_set_settings( struct net_device *pndev, struct ethtool_cmd *pcmd) { mc_emac_t *pe = netdev_priv(pndev); struct ethtool_cmd cmd; u32 ctl, ctl_new; pr_info("etool_set_settings: cmd=%Xh\n", pcmd->cmd); //etool_print_set_settings( pcmd); //etool_get_settings( pndev, &cmd); if( !mc_phy_read( pe, PHY_CTL, &ctl)) { pr_info( "etool_set_settings: PHY_CTL reading ERROR\n"); return RC_EMAC_ERROR; } ctl_new = ctl; if( pcmd->speed != cmd.speed) { ctl_new &= ~PHY_CTL_SPEED_100; ctl_new |= ((pcmd->speed==100) ? PHY_CTL_SPEED_100 : 0); } if( pcmd->duplex != cmd.duplex) { ctl_new &= ~PHY_CTL_DPLX; ctl_new |= (pcmd->duplex ? PHY_CTL_DPLX : 0); } if( pcmd->autoneg != cmd.autoneg) { ctl_new &= ~PHY_CTL_ANEG_EN; ctl_new |= (pcmd->autoneg ? PHY_CTL_ANEG_EN : 0); } if( ctl_new != ctl) if( !mc_phy_write( pe, PHY_CTL, ctl_new)) { pr_info( "etool_set_settings: PHY_CTL writing ERROR\n"); return RC_EMAC_ERROR; } return RC_EMAC_SUCCESS; } void etool_get_ringparam( struct net_device *pndev, struct ethtool_ringparam *pring) { mc_emac_t *pe = netdev_priv( pndev); pring->rx_max_pending = EMAC_MAX_RX_DSC_QNT; pring->tx_max_pending = EMAC_MAX_TX_DSC_QNT; pring->rx_pending = pe->rx_dma_fifo_size; pring->tx_pending = pe->tx_dma_fifo_size; } int etool_set_ringparam( struct net_device *pndev, struct ethtool_ringparam *pring) { mc_emac_t *pe = netdev_priv( pndev); u32 new_rx_qnt, new_tx_qnt; int rc = RC_EMAC_SUCCESS; //pr_info("etool_set_ringparam:\n"); new_tx_qnt = max_t(u32, pring->tx_pending, EMAC_MIN_TX_DSC_QNT); new_tx_qnt = min_t(u32, new_tx_qnt, EMAC_MAX_TX_DSC_QNT); new_rx_qnt = max_t(u32, pring->rx_pending, EMAC_MIN_RX_DSC_QNT); new_rx_qnt = min_t(u32, new_rx_qnt, EMAC_MAX_RX_DSC_QNT); if( (new_tx_qnt == pe->tx_dma_fifo_size) && (new_rx_qnt == pe->rx_dma_fifo_size)) return RC_EMAC_SUCCESS; mutex_lock( &pe->mtx_change_work); pe->is_param_changing = 1; emac_stop_tx( pe); emac_stop_rx( pe); //pr_info("etool_set_ringparam: dma_fifo_size tx=%u, rx=%u\n", pe->tx_dma_fifo_size, pe->rx_dma_fifo_size); if( new_tx_qnt != pe->tx_dma_fifo_size) { fifo_free( &pe->ffTx); pe->tx_dma_fifo_size = new_tx_qnt; if( !emac_init_ff_tx(pe)) { pr_info("etool_set_ringparam: Could create DMA TX data list\n"); rc = -ENOMEM; goto l_err; } } if( new_rx_qnt != pe->rx_dma_fifo_size) { fifo_free( &pe->ffRx); pe->rx_dma_fifo_size = new_rx_qnt; if( !emac_init_ff_rx( pe)) { pr_info("etool_set_ringparam: Could create DMA RX data list\n"); rc = -ENOMEM; goto l_err; } } //emac_reinit_phy(pe); //schedule_timeout(10); //reinit_emac( pe); emac_set_mac_addr( pe->pndev, pe->pndev->perm_addr); //pr_info("etool_set_ringparam: emac_start_rx()\n"); emac_start_rx( pe); schedule_timeout(1); //pr_info("etool_set_ringparam: emac_start_tx()\n"); emac_start_tx( pe); pe->is_param_changing = false; l_err:; mutex_unlock( &pe->mtx_change_work); return rc; } u32 etool_get_msglevel( struct net_device *pndev) { mc_emac_t *pe = netdev_priv( pndev); return pe->msg_level; } void etool_set_msglevel( struct net_device *pndev, u32 value) { mc_emac_t *pe = netdev_priv(pndev); pe->msg_level = value; }