/*********************************************************** * eth_set_multicast_list -- * * Add multicast addresses or set promiscuous mode. * * This function should have been but was not included * * by Marvell. -bbozarth * ***********************************************************/ void mv_eth_set_multicast_list(struct net_device *dev) { mv_eth_priv *priv = MV_ETH_PRIV(dev); int queue = ETH_DEF_RXQ; struct dev_mc_list *curr_addr = dev->mc_list; int i; if (dev->flags & IFF_PROMISC) { mvEthRxFilterModeSet(priv->hal_priv, 1); } else if (dev->flags & IFF_ALLMULTI) { mvEthRxFilterModeSet(priv->hal_priv, 0); mvEthMacAddrSet(priv->hal_priv, dev->dev_addr, queue); mvEthSetSpecialMcastTable(priv->port, queue); mvEthSetOtherMcastTable(priv->port, queue); } else if (dev->mc_count) { mvEthRxFilterModeSet(priv->hal_priv, 0); mvEthMacAddrSet(priv->hal_priv, dev->dev_addr, queue); for (i=0; i<dev->mc_count; i++, curr_addr = curr_addr->next) { if (!curr_addr) break; mvEthMcastAddrSet(priv->hal_priv, curr_addr->dmi_addr, queue); } } else /* No Mcast addrs, not promisc or all multi - clear tables */ { mvEthRxFilterModeSet(priv->hal_priv, 0); mvEthMacAddrSet(priv->hal_priv, dev->dev_addr, queue); } }
/*********************************************************** * mv_eth_stop -- * * stop interface with linux core. stop port activity. * * free skb's from rings. * ***********************************************************/ int mv_eth_stop(struct net_device *dev) { struct eth_port *priv = MV_ETH_PRIV(dev); /* first make sure that the port finished its Rx polling - see tg3 */ napi_disable(priv->napiGroup[CPU_GROUP_DEF]); /* stop upper layer */ netif_carrier_off(dev); netif_stop_queue(dev); /* stop tx/rx activity, mask all interrupts, relese skb in rings,*/ mv_eth_stop_internals(priv); del_timer(&priv->tx_done_timer); clear_bit(MV_ETH_F_TX_DONE_TIMER_BIT, &(priv->flags)); del_timer(&priv->cleanup_timer); clear_bit(MV_ETH_F_CLEANUP_TIMER_BIT, &(priv->flags)); if (dev->irq != 0) free_irq(dev->irq, priv); printk(KERN_NOTICE "%s: stopped\n", dev->name); return 0; }
/*********************************************************** * eth_set_mac_addr -- * * stop port activity. set new addr in device and hw. * * restart port activity. * ***********************************************************/ static int mv_eth_set_mac_addr_internals(struct net_device *dev, void *addr ) { mv_eth_priv *priv = MV_ETH_PRIV(dev); u8 *mac = &(((u8*)addr)[2]); /* skip on first 2B (ether HW addr type) */ int i; /* remove previous address table entry */ if( mvEthMacAddrSet( priv->hal_priv, dev->dev_addr, -1) != MV_OK ) { printk( KERN_ERR "%s: ethSetMacAddr failed\n", dev->name ); return -1; } /* set new addr in hw */ if( mvEthMacAddrSet( priv->hal_priv, mac, ETH_DEF_RXQ) != MV_OK ) { printk( KERN_ERR "%s: ethSetMacAddr failed\n", dev->name ); return -1; } /* set addr in the device */ for( i = 0; i < 6; i++ ) dev->dev_addr[i] = mac[i]; printk( KERN_NOTICE "%s: mac address changed\n", dev->name ); return 0; }
/*********************************************************** * mv_eth_stop -- * * stop interface with linux core. stop port activity. * * free skb's from rings. * ***********************************************************/ int mv_eth_stop( struct net_device *dev ) { unsigned long flags; mv_eth_priv *priv = MV_ETH_PRIV(dev); /* first make sure that the port finished its Rx polling - see tg3 */ /* otherwise it may cause issue in SMP, one CPU is here and the other is doing the polling and both of it are messing with the descriptors rings!! */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) netif_poll_disable(dev); #else napi_disable(&priv->napi); #endif spin_lock_irqsave(priv->lock, flags); /* stop upper layer */ netif_carrier_off(dev); netif_stop_queue(dev); /* stop tx/rx activity, mask all interrupts, relese skb in rings,*/ mv_eth_stop_internals(priv); spin_unlock_irqrestore(priv->lock, flags); if( dev->irq != 0 ) { free_irq(dev->irq, priv); } printk(KERN_NOTICE "%s: stopped\n", dev->name); return 0; }
/****************************************************************************** * mv_eth_tool_set_coalesce * Description: * ethtool set RX/TX coalesce parameters * INPUT: * netdev Network device structure pointer * cmd Coalesce parameters * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *cmd) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); if ((cmd->rx_coalesce_usecs == 0) || (cmd->tx_coalesce_usecs == 0)) { /* coalesce usec=0 means that coalesce frames should be used, * which is not permitted (unsupported) */ return -EPERM; } if ((cmd->rx_coalesce_usecs * 166 / 64 > 0x3FFF) || (cmd->tx_coalesce_usecs * 166 / 64 > 0x3FFF)) return -EINVAL; /* Save values for mv_eth_start_internals() */ priv->rx_coal_usec = cmd->rx_coalesce_usecs; priv->tx_coal_usec = cmd->tx_coalesce_usecs; mvEthRxCoalSet (priv->hal_priv, cmd->rx_coalesce_usecs); mvEthTxCoalSet (priv->hal_priv, cmd->tx_coalesce_usecs); return 0; }
/****************************************************************************** * mv_eth_tool_get_pauseparam * Description: * ethtool get pause parameters * INPUT: * netdev Network device structure pointer * OUTPUT * pause Pause paranmeters * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); ETH_PORT_CTRL *pPortCtrl = (ETH_PORT_CTRL*)(priv->hal_priv); MV_U32 reg; reg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(pPortCtrl->portNo)); pause->rx_pause = 0; pause->tx_pause = 0; if (reg & ETH_DISABLE_FC_AUTO_NEG_MASK) { /* autoneg disabled */ pause->autoneg = AUTONEG_DISABLE; if (reg & ETH_SET_FLOW_CTRL_MASK) { pause->rx_pause = 1; pause->tx_pause = 1; } } else { /* autoneg enabled */ pause->autoneg = AUTONEG_ENABLE; if (reg & ETH_ADVERTISE_SYM_FC_MASK) { pause->rx_pause = 1; pause->tx_pause = 1; } } }
/****************************************************************************** * mv_eth_tool_set_settings * Description: * ethtool set standard port settings * INPUT: * netdev Network device structure pointer * cmd command (settings) * OUTPUT * None * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct eth_port *priv = MV_ETH_PRIV(dev); int _speed, _duplex, _autoneg, err; #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(priv)) return -EPERM; #endif /* CONFIG_MV_ETH_SWITCH */ _duplex = priv->duplex_cfg; _speed = priv->speed_cfg; _autoneg = priv->autoneg_cfg; priv->duplex_cfg = cmd->duplex; priv->speed_cfg = cmd->speed; priv->autoneg_cfg = cmd->autoneg; err = mv_eth_tool_restore_settings(dev); if (err) { priv->duplex_cfg = _duplex; priv->speed_cfg = _speed; priv->autoneg_cfg = _autoneg; } return err; }
/*********************************************************** * eth_set_multicast_list -- * * Add multicast addresses or set promiscuous mode. * * This function should have been but was not included * * by Marvell. -bbozarth * ***********************************************************/ void mv_eth_set_multicast_list(struct net_device *dev) { mv_eth_priv *priv = MV_ETH_PRIV(dev); int queue = ETH_DEF_RXQ; int i; if (dev->flags & IFF_PROMISC) { mvEthRxFilterModeSet(priv->hal_priv, 1); } else if (dev->flags & IFF_ALLMULTI) { mvEthRxFilterModeSet(priv->hal_priv, 0); mvEthMacAddrSet(priv->hal_priv, dev->dev_addr, queue); mvEthSetSpecialMcastTable(priv->port, queue); mvEthSetOtherMcastTable(priv->port, queue); } else if (!netdev_mc_empty(dev)) { struct netdev_hw_addr *ha; mvEthRxFilterModeSet(priv->hal_priv, 0); mvEthMacAddrSet(priv->hal_priv, dev->dev_addr, queue); netdev_for_each_mc_addr(ha, dev) { mvEthMcastAddrSet(priv->hal_priv, ha->addr, queue); } }
/****************************************************************************** * mv_eth_tool_get_pauseparam * Description: * ethtool get pause parameters * INPUT: * netdev Network device structure pointer * OUTPUT * pause Pause paranmeters * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct eth_port *priv = MV_ETH_PRIV(netdev); int port = priv->port; MV_ETH_PORT_STATUS portStatus; MV_ETH_PORT_FC flowCtrl; #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(priv)) { printk("mv_eth_tool_get_pauseparam() is not supported on a switch port\n"); return; } #endif /* CONFIG_MV_ETH_SWITCH */ mvNetaFlowCtrlGet(port, &flowCtrl); if ((flowCtrl == MV_ETH_FC_AN_NO) || (flowCtrl == MV_ETH_FC_AN_SYM) || (flowCtrl == MV_ETH_FC_AN_ASYM)) pause->autoneg = AUTONEG_ENABLE; else pause->autoneg = AUTONEG_DISABLE; mvNetaLinkStatus(port, &portStatus); if (portStatus.rxFc == MV_ETH_FC_DISABLE) pause->rx_pause = 0; else pause->rx_pause = 1; if (portStatus.txFc == MV_ETH_FC_DISABLE) pause->tx_pause = 0; else pause->tx_pause = 1; }
/****************************************************************************** * mv_eth_tool_get_regs * Description: * ethtool get registers array * INPUT: * netdev Network device structure pointer * regs registers information * OUTPUT * p registers array * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct eth_port *priv = MV_ETH_PRIV(netdev); uint32_t *regs_buff = p; memset(p, 0, MV_ETH_TOOL_REGS_LEN * sizeof(uint32_t)); regs->version = mvCtrlModelRevGet(); /* ETH port registers */ regs_buff[0] = MV_REG_READ(ETH_PORT_STATUS_REG(priv->port)); regs_buff[1] = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(priv->port)); regs_buff[2] = MV_REG_READ(ETH_PORT_CONFIG_REG(priv->port)); regs_buff[3] = MV_REG_READ(ETH_PORT_CONFIG_EXTEND_REG(priv->port)); regs_buff[4] = MV_REG_READ(ETH_SDMA_CONFIG_REG(priv->port)); /* regs_buff[5] = MV_REG_READ(ETH_TX_FIFO_URGENT_THRESH_REG(priv->port)); */ regs_buff[6] = MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(priv->port)); /* regs_buff[7] = MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(priv->port)); */ regs_buff[8] = MV_REG_READ(ETH_INTR_CAUSE_REG(priv->port)); regs_buff[9] = MV_REG_READ(ETH_INTR_CAUSE_EXT_REG(priv->port)); regs_buff[10] = MV_REG_READ(ETH_INTR_MASK_REG(priv->port)); regs_buff[11] = MV_REG_READ(ETH_INTR_MASK_EXT_REG(priv->port)); /* ETH Unit registers */ regs_buff[16] = MV_REG_READ(ETH_PHY_ADDR_REG(priv->port)); regs_buff[17] = MV_REG_READ(ETH_UNIT_INTR_CAUSE_REG(priv->port)); regs_buff[18] = MV_REG_READ(ETH_UNIT_INTR_MASK_REG(priv->port)); regs_buff[19] = MV_REG_READ(ETH_UNIT_ERROR_ADDR_REG(priv->port)); regs_buff[20] = MV_REG_READ(ETH_UNIT_INT_ADDR_ERROR_REG(priv->port)); }
/****************************************************************************** * mv_eth_tool_get_ethtool_stats * Description: * ethtool get statistics * INPUT: * netdev Network device structure pointer * stats stats parameters * OUTPUT * data output data * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); uint64_t *pdest = data; int i, q; for (i = 0; i < MV_ETH_TOOL_GLOBAL_STATS_LEN; i++) { char *p = (char *)priv + mv_eth_tool_global_strings_stats[i].stat_offset; pdest[i] = *(uint32_t *)p; } pdest += MV_ETH_TOOL_GLOBAL_STATS_LEN; for (q = 0; q < MV_ETH_RX_Q_NUM; q++) { for (i = 0; i < MV_ETH_TOOL_RX_QUEUE_STATS_LEN; i++) { char *p = (char *)priv + mv_eth_tool_rx_queue_strings_stats[i].stat_offset; pdest[i] = *((uint32_t *)p + q); } pdest += MV_ETH_TOOL_RX_QUEUE_STATS_LEN; } for (q = 0; q < MV_ETH_TX_Q_NUM; q++) { for (i = 0; i < MV_ETH_TOOL_TX_QUEUE_STATS_LEN; i++) { char *p = (char *)priv + mv_eth_tool_tx_queue_strings_stats[i].stat_offset; pdest[i] = *((uint32_t *)p + q); } pdest += MV_ETH_TOOL_TX_QUEUE_STATS_LEN; } }
/****************************************************************************** * mv_eth_tool_set_settings * Description: * ethtool set standard port settings * INPUT: * netdev Network device structure pointer * cmd command (settings) * OUTPUT * None * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct eth_port *priv = MV_ETH_PRIV(dev); int _speed, _duplex, _autoneg, _advertise, err; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, dev->name); return -EOPNOTSUPP; } _duplex = priv->duplex_cfg; _speed = priv->speed_cfg; _autoneg = priv->autoneg_cfg; _advertise = priv->advertise_cfg; priv->duplex_cfg = cmd->duplex; priv->speed_cfg = cmd->speed; priv->autoneg_cfg = cmd->autoneg; priv->advertise_cfg = cmd->advertising; err = mv_eth_tool_restore_settings(dev); if (err) { priv->duplex_cfg = _duplex; priv->speed_cfg = _speed; priv->autoneg_cfg = _autoneg; priv->advertise_cfg = _advertise; } return err; }
/****************************************************************************** * mv_eth_tool_get_pauseparam * Description: * ethtool get pause parameters * INPUT: * netdev Network device structure pointer * OUTPUT * pause Pause paranmeters * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct eth_port *priv = MV_ETH_PRIV(netdev); int port = priv->port; MV_ETH_PORT_STATUS portStatus; MV_ETH_PORT_FC flowCtrl; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, netdev->name); return; } mvNetaFlowCtrlGet(port, &flowCtrl); if ((flowCtrl == MV_ETH_FC_AN_NO) || (flowCtrl == MV_ETH_FC_AN_SYM) || (flowCtrl == MV_ETH_FC_AN_ASYM)) pause->autoneg = AUTONEG_ENABLE; else pause->autoneg = AUTONEG_DISABLE; mvNetaLinkStatus(port, &portStatus); if (portStatus.rxFc == MV_ETH_FC_DISABLE) pause->rx_pause = 0; else pause->rx_pause = 1; if (portStatus.txFc == MV_ETH_FC_DISABLE) pause->tx_pause = 0; else pause->tx_pause = 1; }
/*********************************************************** * mv_eth_start -- * * start a network device. connect and enable interrupts * * set hw defaults. fill rx buffers. restart phy link * * auto neg. set device link flags. report status. * ***********************************************************/ static int mv_eth_start(struct net_device *dev) { struct eth_port *priv = MV_ETH_PRIV(dev); int group; /* in default link is down */ netif_carrier_off(dev); /* Stop the TX queue - it will be enabled upon PHY status change after link-up interrupt/timer */ netif_tx_stop_all_queues(dev); /* fill rx buffers, start rx/tx activity, set coalescing */ if (mv_eth_start_internals(priv, dev->mtu) != 0) { printk(KERN_ERR "%s: start internals failed\n", dev->name); goto error; } /* enable polling on the port, must be used after netif_poll_disable */ if (priv->flags & MV_ETH_F_CONNECT_LINUX) for (group = 0; group < CONFIG_MV_ETH_NAPI_GROUPS; group++) napi_enable(priv->napiGroup[group]); if ((priv->flags & MV_ETH_F_LINK_UP) && !(priv->flags & MV_ETH_F_EXT_SWITCH)) { if (mv_eth_ctrl_is_tx_enabled(priv)) { netif_carrier_on(dev); netif_tx_wake_all_queues(dev); } printk(KERN_NOTICE "%s: link up\n", dev->name); } #ifdef CONFIG_MV_ETH_SWITCH_LINK if (priv->flags & MV_ETH_F_EXT_SWITCH) { struct eth_netdev *dev_priv = MV_DEV_PRIV(dev); dev_priv->link_map = 0; mv_switch_link_update_event(dev_priv->port_map, 1); } #endif /* CONFIG_MV_ETH_SWITCH_LINK */ if (priv->flags & MV_ETH_F_CONNECT_LINUX) { /* connect to port interrupt line */ if (request_irq(dev->irq, mv_eth_isr, (IRQF_DISABLED|IRQF_SAMPLE_RANDOM), "mv_eth", priv)) { printk(KERN_ERR "cannot request irq %d for %s port %d\n", dev->irq, dev->name, priv->port); if (priv->flags & MV_ETH_F_CONNECT_LINUX) napi_disable(priv->napiGroup[CPU_GROUP_DEF]); goto error; } /* unmask interrupts */ mv_eth_interrupts_unmask(priv); smp_call_function_many(cpu_online_mask, (smp_call_func_t)mv_eth_interrupts_unmask, (void *)priv, 1); printk(KERN_NOTICE "%s: started\n", dev->name); } return 0; error: printk(KERN_ERR "%s: start failed\n", dev->name); return -1; }
/*********************************************************** * mv_eth_stop -- * * stop interface with linux core. stop port activity. * * free skb's from rings. * ***********************************************************/ int mv_eth_stop(struct net_device *dev) { struct eth_port *priv = MV_ETH_PRIV(dev); struct cpu_ctrl *cpuCtrl; int group, cpu; /* first make sure that the port finished its Rx polling - see tg3 */ for (group = 0; group < CONFIG_MV_ETH_NAPI_GROUPS; group++) napi_disable(priv->napiGroup[group]); /* stop upper layer */ netif_carrier_off(dev); netif_tx_stop_all_queues(dev); /* stop tx/rx activity, mask all interrupts, relese skb in rings,*/ mv_eth_stop_internals(priv); for_each_possible_cpu(cpu) { cpuCtrl = priv->cpu_config[cpu]; del_timer(&cpuCtrl->tx_done_timer); clear_bit(MV_ETH_F_TX_DONE_TIMER_BIT, &(cpuCtrl->flags)); del_timer(&cpuCtrl->cleanup_timer); clear_bit(MV_ETH_F_CLEANUP_TIMER_BIT, &(cpuCtrl->flags)); } if (dev->irq != 0) free_irq(dev->irq, priv); printk(KERN_NOTICE "%s: stopped\n", dev->name); return 0; }
void mv_eth_set_multicast_list(struct net_device *dev) { struct eth_port *priv = MV_ETH_PRIV(dev); int rxq = CONFIG_MV_ETH_RXQ_DEF; /* printk("%s - mv_eth_set_multicast_list: flags=0x%x, mc_count=%d\n", dev->name, dev->flags, dev->mc_count); */ if (!mv_eth_pnc_ctrl_en) { printk(KERN_ERR "%s: PNC control is disabled\n", __func__); return; } if (dev->flags & IFF_PROMISC) { /* Accept all */ pnc_mac_me(priv->port, NULL, rxq); pnc_mcast_all(priv->port, 1); } else { /* Accept Unicast to me */ pnc_mac_me(priv->port, dev->dev_addr, rxq); if (dev->flags & IFF_ALLMULTI) { /* Accept all multicast */ pnc_mcast_all(priv->port, 1); } else { /* Accept only initialized Multicast */ pnc_mcast_all(priv->port, 0); pnc_mcast_me(priv->port, NULL); /* Number of entires for all ports is restricted by CONFIG_MV_ETH_PNC_MCAST_NUM */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) if (!netdev_mc_empty(dev)) { struct netdev_hw_addr *ha; netdev_for_each_mc_addr(ha, dev) { if (pnc_mcast_me(priv->port, ha->addr)) { printk(KERN_ERR "%s: Mcast init failed\n", dev->name); break; } } } #else { struct dev_mc_list *curr_addr = dev->mc_list; int i; for (i = 0; i < dev->mc_count; i++, curr_addr = curr_addr->next) { if (!curr_addr) break; if (pnc_mcast_me(priv->port, curr_addr->dmi_addr)) { printk(KERN_ERR "%s: Mcast init failed - %d of %d\n", dev->name, i, dev->mc_count); break; } } } #endif /* KERNEL_VERSION >= 2.6.34 */ } } }
/****************************************************************************** * mv_eth_tool_get_rx_csum * Description: * ethtool get RX checksum offloading status * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * RX checksum * *******************************************************************************/ u32 mv_eth_tool_get_rx_csum(struct net_device *netdev) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); #ifdef RX_CSUM_OFFLOAD return (priv->rx_csum_offload != 0); #else return 0; #endif }
/****************************************************************************** * mv_eth_tool_get_rx_csum * Description: * ethtool get RX checksum offloading status * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * RX checksum * *******************************************************************************/ u32 mv_eth_tool_get_rx_csum(struct net_device *netdev) { #ifdef CONFIG_MV_ETH_RX_CSUM_OFFLOAD struct eth_port *priv = MV_ETH_PRIV(netdev); return (priv->rx_csum_offload != 0); #else return 0; #endif }
/****************************************************************************** * mv_eth_tool_nway_reset * Description: * ethtool restart auto negotiation * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_nway_reset(struct net_device *netdev) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr = (MV_U32)(priv->phy_id); if (mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT) != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_set_rx_csum * Description: * ethtool enable/disable RX checksum offloading * INPUT: * netdev Network device structure pointer * data Command data * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_set_rx_csum(struct net_device *netdev, uint32_t data) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); #ifdef RX_CSUM_OFFLOAD priv->rx_csum_offload = data; return 0; #else return data ? -EINVAL : 0; #endif }
/****************************************************************************** * mv_eth_tool_get_settings * Description: * ethtool get standard port settings * INPUT: * netdev Network device structure pointer * OUTPUT * cmd command (settings) * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { struct eth_port *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr; MV_ETH_PORT_SPEED speed; MV_ETH_PORT_DUPLEX duplex; MV_ETH_PORT_STATUS status; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, netdev->name); return -EOPNOTSUPP; } cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_1000baseT_Full); mv_phy_addr = mvBoardPhyAddrGet(priv->port); mvNetaLinkStatus(priv->port, &status); switch (status.speed) { case MV_ETH_SPEED_1000: cmd->speed = SPEED_1000; break; case MV_ETH_SPEED_100: cmd->speed = SPEED_100; break; case MV_ETH_SPEED_10: cmd->speed = SPEED_10; break; default: return -EINVAL; } if (status.duplex == MV_ETH_DUPLEX_FULL) cmd->duplex = 1; else cmd->duplex = 0; cmd->port = PORT_MII; cmd->phy_address = mv_phy_addr; cmd->transceiver = XCVR_INTERNAL; /* check if speed and duplex are AN */ mvNetaSpeedDuplexGet(priv->port, &speed, &duplex); if (speed == MV_ETH_SPEED_AN && duplex == MV_ETH_DUPLEX_AN) { /* Note: lp_advertising not available in this kernel */ cmd->advertising = 0; cmd->autoneg = AUTONEG_ENABLE; mvEthPhyAdvertiseGet(mv_phy_addr, (MV_U16 *)&(cmd->advertising)); } else cmd->autoneg = AUTONEG_DISABLE; return 0; }
/****************************************************************************** * mv_eth_tool_set_rx_csum * Description: * ethtool enable/disable RX checksum offloading * INPUT: * netdev Network device structure pointer * data Command data * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_set_rx_csum(struct net_device *netdev, uint32_t data) { #ifdef CONFIG_MV_ETH_RX_CSUM_OFFLOAD struct eth_port *priv = MV_ETH_PRIV(netdev); priv->rx_csum_offload = data; return 0; #else return -EOPNOTSUPP; #endif }
/****************************************************************************** * mv_eth_tool_get_coalesce * Description: * ethtool get RX/TX coalesce parameters * INPUT: * netdev Network device structure pointer * OUTPUT * cmd Coalesce parameters * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *cmd) { struct eth_port *pp = MV_ETH_PRIV(netdev); /* get coal parameters only for rxq=0, txp=txq=0 !!! notice that if you use ethtool to set coal, then all queues have the same value */ cmd->rx_coalesce_usecs = mvNetaRxqTimeCoalGet(pp->port, 0); cmd->rx_max_coalesced_frames = mvNetaRxqPktsCoalGet(pp->port, 0); cmd->tx_max_coalesced_frames = mvNetaTxDonePktsCoalGet(pp->port, 0, 0); return 0; }
/****************************************************************************** * mv_eth_tool_get_link * Description: * ethtool get link status * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 if link is down, 1 if link is up * *******************************************************************************/ u32 mv_eth_tool_get_link(struct net_device *netdev) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); MV_ETH_PORT_STATUS status; mvEthStatusGet(priv->hal_priv, &status); if (status.isLinkUp == MV_TRUE) return 1; return 0; }
/****************************************************************************** * mv_eth_tool_get_coalesce * Description: * ethtool get RX/TX coalesce parameters * INPUT: * netdev Network device structure pointer * OUTPUT * cmd Coalesce parameters * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *cmd) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); if (mvEthCoalGet(priv->hal_priv, &cmd->rx_coalesce_usecs, &cmd->tx_coalesce_usecs) != MV_OK) return -EINVAL; return 0; }
int mv_gtw_start( struct net_device *dev ) { mv_eth_priv *priv = MV_ETH_PRIV(dev); struct mv_vlan_cfg *vlan_cfg = MV_NETDEV_VLAN(dev); unsigned char broadcast[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; printk("mv_gateway: starting %s\n",dev->name); /* start upper layer */ netif_carrier_on(dev); netif_wake_queue(dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) netif_poll_enable(dev); #else if ( (priv->net_dev == dev) || !netif_running(priv->net_dev) ) { napi_enable(&priv->napi); } #endif /* Add our MAC addr to the VLAN DB at switch level to forward packets with this DA */ /* to CPU port by using the tunneling feature. The device is always in promisc mode. */ mv_gtw_set_mac_addr_to_switch(dev->dev_addr, MV_GTW_VLAN_TO_GROUP(vlan_cfg->vlan_grp_id), (1<<SWITCH_PORT_CPU), 1); /* We also need to allow L2 broadcasts comming up for this interface */ mv_gtw_set_mac_addr_to_switch(broadcast, MV_GTW_VLAN_TO_GROUP(vlan_cfg->vlan_grp_id), vlan_cfg->ports_mask|(1<<SWITCH_PORT_CPU), 1); if (!(priv->flags & MV_ETH_F_TIMER)) { priv->timer.expires = jiffies + ((HZ*CONFIG_MV_ETH_TIMER_PERIOD)/1000); /*ms*/ add_timer( &(priv->timer) ); priv->flags |= MV_ETH_F_TIMER; } if ( (priv->net_dev == dev) || !netif_running(priv->net_dev) ) { priv->net_dev = dev; /* connect to MAC port interrupt line */ if ( request_irq( ETH_PORT_IRQ_NUM(priv->port), mv_eth_interrupt_handler, (IRQF_DISABLED | IRQF_SAMPLE_RANDOM), "mv_gateway", priv) ) { printk(KERN_ERR "failed to assign irq%d\n", ETH_PORT_IRQ_NUM(priv->port)); } /* unmask interrupts */ mv_eth_unmask_interrupts(priv); } return 0; }
/****************************************************************************** * mv_eth_tool_get_settings * Description: * ethtool get standard port settings * INPUT: * netdev Network device structure pointer * OUTPUT * cmd command (settings) * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); struct mii_if_info mii; int retval; MV_ETH_PORT_STATUS status; #ifdef CONFIG_MII mii.dev = netdev; mii.phy_id_mask = 0x1F; mii.reg_num_mask = 0x1F; mii.mdio_read = mv_eth_tool_read_mdio; mii.mdio_write = mv_eth_tool_write_mdio; mii.phy_id = priv->phy_id; mii.supports_gmii = 1; /* Get values from PHY */ retval = mii_ethtool_gset(&mii, cmd); if (retval) return retval; #endif /* Get some values from MAC */ mvEthStatusGet(priv->hal_priv, &status); switch (status.speed) { case MV_ETH_SPEED_1000: cmd->speed = SPEED_1000; break; case MV_ETH_SPEED_100: cmd->speed = SPEED_100; break; case MV_ETH_SPEED_10: cmd->speed = SPEED_10; break; default: return -EINVAL; } if (status.duplex == MV_ETH_DUPLEX_FULL) cmd->duplex = 1; else cmd->duplex = 0; cmd->port = PORT_MII; cmd->phy_address = priv->phy_id; return 0; }
static struct net_device* mv_gtw_main_net_dev_get(void) { int i; mv_eth_priv *priv; struct net_device *dev; for (i=0; i<mv_net_devs_num; i++) { dev = mv_net_devs[i]; priv = MV_ETH_PRIV(dev); if (netif_running(dev) && priv->isGtw) return dev; } return NULL; }
/****************************************************************************** * mv_eth_tool_get_link * Description: * ethtool get link status * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 if link is down, 1 if link is up * *******************************************************************************/ u32 mv_eth_tool_get_link(struct net_device *netdev) { struct eth_port *pp = MV_ETH_PRIV(netdev); #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(pp)) return -EPERM; #endif /* CONFIG_MV_ETH_SWITCH */ if (pp) { if (mvNetaLinkIsUp(pp->port)) return 1; } return 0; }
/****************************************************************************** * mv_eth_tool_nway_reset * Description: * ethtool restart auto negotiation * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_nway_reset(struct net_device *netdev) { struct eth_port *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr = mvBoardPhyAddrGet(priv->port); #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(priv)) return -EPERM; #endif /* CONFIG_MV_ETH_SWITCH */ if (mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT) != MV_OK) return -EINVAL; return 0; }