Example #1
0
/***********************************************************
 * 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;
}
Example #2
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)
{
	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);
}
Example #3
0
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;
}
Example #4
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 */
    }