drivers/misc/sgi-xp/xpnet.c

Source file repositories/reference/linux-study-clean/drivers/misc/sgi-xp/xpnet.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/sgi-xp/xpnet.c
Extension
.c
Size
17759 bytes
Lines
600
Domain
Driver Families
Bucket
drivers/misc
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static struct device_driver xpnet_dbg_name = {
	.name = "xpnet"
};

static struct device xpnet_dbg_subname = {
	.init_name = "",	/* set to "" */
	.driver = &xpnet_dbg_name
};

static struct device *xpnet = &xpnet_dbg_subname;

/*
 * Packet was recevied by XPC and forwarded to us.
 */
static void
xpnet_receive(short partid, int channel, struct xpnet_message *msg)
{
	struct sk_buff *skb;
	void *dst;
	enum xp_retval ret;

	if (!XPNET_VALID_MSG(msg)) {
		/*
		 * Packet with a different XPC version.  Ignore.
		 */
		xpc_received(partid, channel, (void *)msg);

		xpnet_device->stats.rx_errors++;

		return;
	}
	dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size,
		msg->leadin_ignore, msg->tailout_ignore);

	/* reserve an extra cache line */
	skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES);
	if (!skb) {
		dev_err(xpnet, "failed on dev_alloc_skb(%d)\n",
			msg->size + L1_CACHE_BYTES);

		xpc_received(partid, channel, (void *)msg);

		xpnet_device->stats.rx_errors++;

		return;
	}

	/*
	 * The allocated skb has some reserved space.
	 * In order to use xp_remote_memcpy(), we need to get the
	 * skb->data pointer moved forward.
	 */
	skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data &
					    (L1_CACHE_BYTES - 1)) +
			  msg->leadin_ignore));

	/*
	 * Update the tail pointer to indicate data actually
	 * transferred.
	 */
	skb_put(skb, (msg->size - msg->leadin_ignore - msg->tailout_ignore));

	/*
	 * Move the data over from the other side.
	 */
	if ((XPNET_VERSION_MINOR(msg->version) == 1) &&
	    (msg->embedded_bytes != 0)) {
		dev_dbg(xpnet, "copying embedded message. memcpy(0x%p, 0x%p, "
			"%lu)\n", skb->data, &msg->data,
			(size_t)msg->embedded_bytes);

		skb_copy_to_linear_data(skb, &msg->data,
					(size_t)msg->embedded_bytes);
	} else {
		dst = (void *)((u64)skb->data & ~(L1_CACHE_BYTES - 1));
		dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t"
			"xp_remote_memcpy(0x%p, 0x%p, %u)\n", dst,
					  (void *)msg->buf_pa, msg->size);

		ret = xp_remote_memcpy(xp_pa(dst), msg->buf_pa, msg->size);
		if (ret != xpSuccess) {
			/*
			 * !!! Need better way of cleaning skb.  Currently skb
			 * !!! appears in_use and we can't just call
			 * !!! dev_kfree_skb.
			 */
			dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%x) "
				"returned error=0x%x\n", dst,
				(void *)msg->buf_pa, msg->size, ret);

Annotation

Implementation Notes