Skip to content
Snippets Groups Projects
dev.c 104 KiB
Newer Older
  • Learn to ignore specific revisions
  • static void net_dma_rebalance(struct net_dma *net_dma)
    
    	unsigned int cpu, i, n, chan_idx;
    
    	if (cpus_empty(net_dma->channel_mask)) {
    
    		for_each_online_cpu(cpu)
    
    			rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL);
    
    		return;
    	}
    
    	i = 0;
    	cpu = first_cpu(cpu_online_map);
    
    
    	for_each_cpu_mask(chan_idx, net_dma->channel_mask) {
    		chan = net_dma->channels[chan_idx];
    
    		n = ((num_online_cpus() / cpus_weight(net_dma->channel_mask))
    		   + (i < (num_online_cpus() %
    			cpus_weight(net_dma->channel_mask)) ? 1 : 0));
    
    			per_cpu(softnet_data, cpu).net_dma = chan;
    
    			cpu = next_cpu(cpu, cpu_online_map);
    			n--;
    		}
    		i++;
    	}
    }
    
    /**
     * netdev_dma_event - event callback for the net_dma_client
     * @client: should always be net_dma_client
    
     * @chan: DMA channel for the event
    
    Randy Dunlap's avatar
    Randy Dunlap committed
     * @state: DMA state to be handled
    
    static enum dma_state_client
    netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
    	enum dma_state state)
    {
    	int i, found = 0, pos = -1;
    	struct net_dma *net_dma =
    		container_of(client, struct net_dma, client);
    	enum dma_state_client ack = DMA_DUP; /* default: take no action */
    
    	spin_lock(&net_dma->lock);
    	switch (state) {
    	case DMA_RESOURCE_AVAILABLE:
    		for (i = 0; i < NR_CPUS; i++)
    			if (net_dma->channels[i] == chan) {
    				found = 1;
    				break;
    			} else if (net_dma->channels[i] == NULL && pos < 0)
    				pos = i;
    
    		if (!found && pos >= 0) {
    			ack = DMA_ACK;
    			net_dma->channels[pos] = chan;
    			cpu_set(pos, net_dma->channel_mask);
    			net_dma_rebalance(net_dma);
    		}
    
    		break;
    	case DMA_RESOURCE_REMOVED:
    
    		for (i = 0; i < NR_CPUS; i++)
    			if (net_dma->channels[i] == chan) {
    				found = 1;
    				pos = i;
    				break;
    			}
    
    		if (found) {
    			ack = DMA_ACK;
    			cpu_clear(pos, net_dma->channel_mask);
    			net_dma->channels[i] = NULL;
    			net_dma_rebalance(net_dma);
    		}
    
    	spin_unlock(&net_dma->lock);
    
    	return ack;
    
    }
    
    /**
     * netdev_dma_regiser - register the networking subsystem as a DMA client
     */
    static int __init netdev_dma_register(void)
    {
    
    	spin_lock_init(&net_dma.lock);
    	dma_cap_set(DMA_MEMCPY, net_dma.client.cap_mask);
    	dma_async_client_register(&net_dma.client);
    	dma_async_client_chan_request(&net_dma.client);
    
    	return 0;
    }
    
    #else
    static int __init netdev_dma_register(void) { return -ENODEV; }
    #endif /* CONFIG_NET_DMA */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    /**
     *	netdev_compute_feature - compute conjunction of two feature sets
     *	@all: first feature set
     *	@one: second feature set
     *
     *	Computes a new feature set after adding a device with feature set
     *	@one to the master device with current feature set @all.  Returns
     *	the new feature set.
     */
    int netdev_compute_features(unsigned long all, unsigned long one)
    {
    	/* if device needs checksumming, downgrade to hw checksumming */
    	if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
    		all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
    
    	/* if device can't do all checksum, downgrade to ipv4/ipv6 */
    	if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM))
    		all ^= NETIF_F_HW_CSUM
    			| NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
    
    	if (one & NETIF_F_GSO)
    		one |= NETIF_F_GSO_SOFTWARE;
    	one |= NETIF_F_GSO;
    
    	/* If even one device supports robust GSO, enable it for all. */
    	if (one & NETIF_F_GSO_ROBUST)
    		all |= NETIF_F_GSO_ROBUST;
    
    	all &= one | NETIF_F_LLTX;
    
    	if (!(all & NETIF_F_ALL_CSUM))
    		all &= ~NETIF_F_SG;
    	if (!(all & NETIF_F_SG))
    		all &= ~NETIF_F_GSO_MASK;
    
    	return all;
    }
    EXPORT_SYMBOL(netdev_compute_features);
    
    
    /* Initialize per network namespace state */
    static int netdev_init(struct net *net)
    {
    	int i;
    	INIT_LIST_HEAD(&net->dev_base_head);
    	rwlock_init(&dev_base_lock);
    
    	net->dev_name_head = kmalloc(
    		sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
    	if (!net->dev_name_head)
    		return -ENOMEM;
    
    	net->dev_index_head = kmalloc(
    		sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
    	if (!net->dev_index_head) {
    		kfree(net->dev_name_head);
    		return -ENOMEM;
    	}
    
    	for (i = 0; i < NETDEV_HASHENTRIES; i++)
    		INIT_HLIST_HEAD(&net->dev_name_head[i]);
    
    	for (i = 0; i < NETDEV_HASHENTRIES; i++)
    		INIT_HLIST_HEAD(&net->dev_index_head[i]);
    
    	return 0;
    }
    
    static void netdev_exit(struct net *net)
    {
    	kfree(net->dev_name_head);
    	kfree(net->dev_index_head);
    }
    
    static struct pernet_operations netdev_net_ops = {
    	.init = netdev_init,
    	.exit = netdev_exit,
    };
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /*
     *	Initialize the DEV module. At boot time this walks the device list and
     *	unhooks any devices that fail to initialise (normally hardware not
     *	present) and leaves us with a valid list of present and active devices.
     *
     */
    
    /*
     *       This is called single threaded during boot, so no need
     *       to take the rtnl semaphore.
     */
    static int __init net_dev_init(void)
    {
    	int i, rc = -ENOMEM;
    
    	BUG_ON(!dev_boot_phase);
    
    	if (dev_proc_init())
    		goto out;
    
    	if (netdev_sysfs_init())
    		goto out;
    
    	INIT_LIST_HEAD(&ptype_all);
    
    	for (i = 0; i < 16; i++)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		INIT_LIST_HEAD(&ptype_base[i]);
    
    
    	if (register_pernet_subsys(&netdev_net_ops))
    		goto out;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/*
    	 *	Initialise the packet receive queues.
    	 */
    
    
    	for_each_possible_cpu(i) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		struct softnet_data *queue;
    
    		queue = &per_cpu(softnet_data, i);
    		skb_queue_head_init(&queue->input_pkt_queue);
    		queue->completion_queue = NULL;
    		INIT_LIST_HEAD(&queue->poll_list);
    
    
    		queue->backlog.poll = process_backlog;
    		queue->backlog.weight = weight_p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	dev_boot_phase = 0;
    
    	open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
    	open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
    
    	hotcpu_notifier(dev_cpu_callback, 0);
    	dst_init();
    	dev_mcast_init();
    	rc = 0;
    out:
    	return rc;
    }
    
    subsys_initcall(net_dev_init);
    
    EXPORT_SYMBOL(__dev_get_by_index);
    EXPORT_SYMBOL(__dev_get_by_name);
    EXPORT_SYMBOL(__dev_remove_pack);
    
    EXPORT_SYMBOL(dev_valid_name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    EXPORT_SYMBOL(dev_add_pack);
    EXPORT_SYMBOL(dev_alloc_name);
    EXPORT_SYMBOL(dev_close);
    EXPORT_SYMBOL(dev_get_by_flags);
    EXPORT_SYMBOL(dev_get_by_index);
    EXPORT_SYMBOL(dev_get_by_name);
    EXPORT_SYMBOL(dev_open);
    EXPORT_SYMBOL(dev_queue_xmit);
    EXPORT_SYMBOL(dev_remove_pack);
    EXPORT_SYMBOL(dev_set_allmulti);
    EXPORT_SYMBOL(dev_set_promiscuity);
    EXPORT_SYMBOL(dev_change_flags);
    EXPORT_SYMBOL(dev_set_mtu);
    EXPORT_SYMBOL(dev_set_mac_address);
    EXPORT_SYMBOL(free_netdev);
    EXPORT_SYMBOL(netdev_boot_setup_check);
    EXPORT_SYMBOL(netdev_set_master);
    EXPORT_SYMBOL(netdev_state_change);
    EXPORT_SYMBOL(netif_receive_skb);
    EXPORT_SYMBOL(netif_rx);
    EXPORT_SYMBOL(register_gifconf);
    EXPORT_SYMBOL(register_netdevice);
    EXPORT_SYMBOL(register_netdevice_notifier);
    EXPORT_SYMBOL(skb_checksum_help);
    EXPORT_SYMBOL(synchronize_net);
    EXPORT_SYMBOL(unregister_netdevice);
    EXPORT_SYMBOL(unregister_netdevice_notifier);
    EXPORT_SYMBOL(net_enable_timestamp);
    EXPORT_SYMBOL(net_disable_timestamp);
    EXPORT_SYMBOL(dev_get_flags);
    
    #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
    EXPORT_SYMBOL(br_handle_frame_hook);
    EXPORT_SYMBOL(br_fdb_get_hook);
    EXPORT_SYMBOL(br_fdb_put_hook);
    #endif
    
    #ifdef CONFIG_KMOD
    EXPORT_SYMBOL(dev_load);
    #endif
    
    EXPORT_PER_CPU_SYMBOL(softnet_data);