/*********************************************************** * 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_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); struct eth_netdev *dev_priv = MV_DEV_PRIV(netdev); if (pp == NULL) { printk(KERN_ERR "interface %s is not supported\n", netdev->name); return -EOPNOTSUPP; } if (isSwitch(pp)) { if (dev_priv == NULL) return -EOPNOTSUPP; return (dev_priv->link_map != 0); } #ifdef CONFIG_MV_PON if (MV_PON_PORT(pp->port)) return mv_pon_link_status(); #endif /* CONFIG_MV_PON */ return mvNetaLinkIsUp(pp->port); }
int mv_eth_switch_set_mac_addr(struct net_device *dev, void *mac) { struct eth_netdev *dev_priv = MV_DEV_PRIV(dev); struct sockaddr *addr = (struct sockaddr *)mac; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; /* remove old mac addr from VLAN DB */ mv_switch_mac_addr_set(dev->dev_addr, MV_SWITCH_VLAN_TO_GROUP(dev_priv->vlan_grp_id), (1 << dev_priv->cpu_port), 0); memcpy(dev->dev_addr, addr->sa_data, MV_MAC_ADDR_SIZE); /* add new mac addr to VLAN DB */ mv_switch_mac_addr_set(dev->dev_addr, MV_SWITCH_VLAN_TO_GROUP(dev_priv->vlan_grp_id), (1 << dev_priv->cpu_port), 1); printk(KERN_ERR "mv_eth_switch: %s change mac address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(dev->dev_addr), *(dev->dev_addr+1), *(dev->dev_addr+2), *(dev->dev_addr+3), *(dev->dev_addr+4), *(dev->dev_addr+5)); return 0; }
void mv_eth_switch_set_multicast_list(struct net_device *dev) { struct eth_netdev *dev_priv = MV_DEV_PRIV(dev); if (dev->flags & IFF_PROMISC) { /* promiscuous mode - connect the CPU port to the VLAN (port based + 802.1q) */ /* printk(KERN_ERR "mv_eth_switch: setting promiscuous mode\n"); */ if (mv_switch_promisc_set(dev_priv->vlan_grp_id, dev_priv->port_map, dev_priv->cpu_port, 1)) printk(KERN_ERR "mv_switch_promisc_set to 1 failed\n"); } else { /* not in promiscuous mode - disconnect the CPU port to the VLAN (port based + 802.1q) */ if (mv_switch_promisc_set(dev_priv->vlan_grp_id, dev_priv->port_map, dev_priv->cpu_port, 0)) printk(KERN_ERR "mv_switch_promisc_set to 0 failed\n"); if (dev->flags & IFF_ALLMULTI) { /* allmulticast - not supported. There is no way to tell the Switch to accept only */ /* the multicast addresses but not Unicast addresses, so the alternatives are: */ /* 1) Don't support multicast and do nothing */ /* 2) Support multicast with same implementation as promiscuous */ /* 3) Don't rely on Switch for MAC filtering, but use PnC */ /* Currently option 1 is selected */ printk(KERN_ERR "mv_eth_switch: setting all-multicast mode is not supported\n"); } /* Add or delete specific multicast addresses: */ /* Linux provides a list of the current multicast addresses for the device. */ /* First, we delete all the multicast addresses in the ATU. */ /* Then we add the specific multicast addresses Linux provides. */ if (mv_switch_all_multicasts_del(MV_SWITCH_VLAN_TO_GROUP(dev_priv->vlan_grp_id))) printk(KERN_ERR "mv_eth_switch: mv_switch_all_multicasts_del failed\n"); #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) { mv_switch_mac_addr_set(ha->addr, MV_SWITCH_VLAN_TO_GROUP(dev_priv->vlan_grp_id), (dev_priv->port_map | (1 << dev_priv->cpu_port)), 1); } } #else { int i; struct dev_mc_list *curr_addr = dev->mc_list; /* accept specific multicasts */ for (i = 0; i < dev->mc_count; i++, curr_addr = curr_addr->next) { if (!curr_addr) break; /* printk(KERN_ERR "Setting MC = %02X:%02X:%02X:%02X:%02X:%02X\n", curr_addr->dmi_addr[0], curr_addr->dmi_addr[1], curr_addr->dmi_addr[2], curr_addr->dmi_addr[3], curr_addr->dmi_addr[4], curr_addr->dmi_addr[5]); */ mv_switch_mac_addr_set(curr_addr->dmi_addr, MV_SWITCH_VLAN_TO_GROUP(dev_priv->vlan_grp_id), (dev_priv->port_map | (1 << dev_priv->cpu_port)), 1); } } #endif /* KERNEL_VERSION >= 2.6.34 */ }