⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpnet.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	dev_dbg(xpnet, "ifconfig up of %s; XPC connected\n", dev->name);	return 0;}static intxpnet_dev_stop(struct net_device *dev){	xpc_disconnect(XPC_NET_CHANNEL);	dev_dbg(xpnet, "ifconfig down of %s; XPC disconnected\n", dev->name);	return 0;}static intxpnet_dev_change_mtu(struct net_device *dev, int new_mtu){	/* 68 comes from min TCP+IP+MAC header */	if ((new_mtu < 68) || (new_mtu > XPNET_MAX_MTU)) {		dev_err(xpnet, "ifconfig %s mtu %d failed; value must be "			"between 68 and %ld\n", dev->name, new_mtu,			XPNET_MAX_MTU);		return -EINVAL;	}	dev->mtu = new_mtu;	dev_dbg(xpnet, "ifconfig %s mtu set to %d\n", dev->name, new_mtu);	return 0;}/* * Required for the net_device structure. */static intxpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map){	return 0;}/* * Return statistics to the caller. */static struct net_device_stats *xpnet_dev_get_stats(struct net_device *dev){	struct xpnet_dev_private *priv;	priv = (struct xpnet_dev_private *) dev->priv;	return &priv->stats;}/* * Notification that the other end has received the message and * DMA'd the skb information.  At this point, they are done with * our side.  When all recipients are done processing, we * release the skb and then release our pending message structure. */static voidxpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel,			void *__qm){	struct xpnet_pending_msg *queued_msg =		(struct xpnet_pending_msg *) __qm;	DBUG_ON(queued_msg == NULL);	dev_dbg(xpnet, "message to %d notified with reason %d\n",		partid, reason);	if (atomic_dec_return(&queued_msg->use_count) == 0) {		dev_dbg(xpnet, "all acks for skb->head=-x%p\n",			(void *) queued_msg->skb->head);		dev_kfree_skb_any(queued_msg->skb);		kfree(queued_msg);	}}/* * Network layer has formatted a packet (skb) and is ready to place it * "on the wire".  Prepare and send an xpnet_message to all partitions * which have connected with us and are targets of this packet. * * MAC-NOTE:  For the XPNET driver, the MAC address contains the * destination partition_id.  If the destination partition id word * is 0xff, this packet is to broadcast to all partitions. */static intxpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct xpnet_pending_msg *queued_msg;	enum xpc_retval ret;	struct xpnet_message *msg;	u64 start_addr, end_addr;	long dp;	u8 second_mac_octet;	partid_t dest_partid;	struct xpnet_dev_private *priv;	u16 embedded_bytes;	priv = (struct xpnet_dev_private *) dev->priv;	dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "		"skb->end=0x%p skb->len=%d\n", (void *) skb->head,		(void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb),		skb->len);	/*	 * The xpnet_pending_msg tracks how many outstanding	 * xpc_send_notifies are relying on this skb.  When none	 * remain, release the skb.	 */	queued_msg = kmalloc(sizeof(struct xpnet_pending_msg), GFP_ATOMIC);	if (queued_msg == NULL) {		dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping "			"packet\n", sizeof(struct xpnet_pending_msg));		priv->stats.tx_errors++;		return -ENOMEM;	}	/* get the beginning of the first cacheline and end of last */	start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1));	end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb));	/* calculate how many bytes to embed in the XPC message */	embedded_bytes = 0;	if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) {		/* skb->data does fit so embed */		embedded_bytes = skb->len;	}	/*	 * Since the send occurs asynchronously, we set the count to one	 * and begin sending.  Any sends that happen to complete before	 * we are done sending will not free the skb.  We will be left	 * with that task during exit.  This also handles the case of	 * a packet destined for a partition which is no longer up.	 */	atomic_set(&queued_msg->use_count, 1);	queued_msg->skb = skb;	second_mac_octet = skb->data[XPNET_PARTID_OCTET];	if (second_mac_octet == 0xff) {		/* we are being asked to broadcast to all partitions */		dp = xpnet_broadcast_partitions;	} else if (second_mac_octet != 0) {		dp = xpnet_broadcast_partitions &					(1UL << (second_mac_octet - 1));	} else {		/* 0 is an invalid partid.  Ignore */		dp = 0;	}	dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp);	/*	 * If we wanted to allow promiscuous mode to work like an	 * unswitched network, this would be a good point to OR in a	 * mask of partitions which should be receiving all packets.	 */	/*	 * Main send loop.	 */	for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS;	     dest_partid++) {		if (!(dp & (1UL << (dest_partid - 1)))) {			/* not destined for this partition */			continue;		}		/* remove this partition from the destinations mask */		dp &= ~(1UL << (dest_partid - 1));		/* found a partition to send to */		ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL,				   XPC_NOWAIT, (void **)&msg);		if (unlikely(ret != xpcSuccess)) {			continue;		}		msg->embedded_bytes = embedded_bytes;		if (unlikely(embedded_bytes != 0)) {			msg->version = XPNET_VERSION_EMBED;			dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n",				&msg->data, skb->data, (size_t) embedded_bytes);			skb_copy_from_linear_data(skb, &msg->data,						  (size_t)embedded_bytes);		} else {			msg->version = XPNET_VERSION;		}		msg->magic = XPNET_MAGIC;		msg->size = end_addr - start_addr;		msg->leadin_ignore = (u64) skb->data - start_addr;		msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb);		msg->buf_pa = __pa(start_addr);		dev_dbg(xpnet, "sending XPC message to %d:%d\n"			KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "			"msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",			dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,			msg->leadin_ignore, msg->tailout_ignore);		atomic_inc(&queued_msg->use_count);		ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg,				      xpnet_send_completed, queued_msg);		if (unlikely(ret != xpcSuccess)) {			atomic_dec(&queued_msg->use_count);			continue;		}	}	if (atomic_dec_return(&queued_msg->use_count) == 0) {		dev_dbg(xpnet, "no partitions to receive packet destined for "			"%d\n", dest_partid);		dev_kfree_skb(skb);		kfree(queued_msg);	}	priv->stats.tx_packets++;	priv->stats.tx_bytes += skb->len;	return 0;}/* * Deal with transmit timeouts coming from the network layer. */static voidxpnet_dev_tx_timeout (struct net_device *dev){	struct xpnet_dev_private *priv;	priv = (struct xpnet_dev_private *) dev->priv;	priv->stats.tx_errors++;	return;}static int __initxpnet_init(void){	int i;	u32 license_num;	int result = -ENOMEM;	if (!ia64_platform_is("sn2")) {		return -ENODEV;	}	dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);	/*	 * use ether_setup() to init the majority of our device	 * structure and then override the necessary pieces.	 */	xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private),				    XPNET_DEVICE_NAME, ether_setup);	if (xpnet_device == NULL) {		return -ENOMEM;	}	netif_carrier_off(xpnet_device);	xpnet_device->mtu = XPNET_DEF_MTU;	xpnet_device->change_mtu = xpnet_dev_change_mtu;	xpnet_device->open = xpnet_dev_open;	xpnet_device->get_stats = xpnet_dev_get_stats;	xpnet_device->stop = xpnet_dev_stop;	xpnet_device->hard_start_xmit = xpnet_dev_hard_start_xmit;	xpnet_device->tx_timeout = xpnet_dev_tx_timeout;	xpnet_device->set_config = xpnet_dev_set_config;	/*	 * Multicast assumes the LSB of the first octet is set for multicast	 * MAC addresses.  We chose the first octet of the MAC to be unlikely	 * to collide with any vendor's officially issued MAC.	 */	xpnet_device->dev_addr[0] = 0xfe;	xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id;	license_num = sn_partition_serial_number_val();	for (i = 3; i >= 0; i--) {		xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] =							license_num & 0xff;		license_num = license_num >> 8;	}	/*	 * ether_setup() sets this to a multicast device.  We are	 * really not supporting multicast at this time.	 */	xpnet_device->flags &= ~IFF_MULTICAST;	/*	 * No need to checksum as it is a DMA transfer.  The BTE will	 * report an error if the data is not retrievable and the	 * packet will be dropped.	 */	xpnet_device->features = NETIF_F_NO_CSUM;	result = register_netdev(xpnet_device);	if (result != 0) {		free_netdev(xpnet_device);	}	return result;}module_init(xpnet_init);static void __exitxpnet_exit(void){	dev_info(xpnet, "unregistering network device %s\n",		xpnet_device[0].name);	unregister_netdev(xpnet_device);	free_netdev(xpnet_device);}module_exit(xpnet_exit);MODULE_AUTHOR("Silicon Graphics, Inc.");MODULE_DESCRIPTION("Cross Partition Network adapter (XPNET)");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -