drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c

Source file repositories/reference/linux-study-clean/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
Extension
.c
Size
14656 bytes
Lines
542
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

if (rsp_ring[i]) {
			rsp_ring[i]->status =
				le32_to_cpu(msg->common.completion_status);
			complete(&rsp_ring[i]->completion);
			rsp_ring[i] = NULL;
		}
		msg_processed = true;
	}

	ipc_protocol->old_msg_tail = i;
	return msg_processed;
}

/* Sends data from UL list to CP for the provided pipe by updating the Head
 * pointer of given pipe.
 */
bool ipc_protocol_ul_td_send(struct iosm_protocol *ipc_protocol,
			     struct ipc_pipe *pipe,
			     struct sk_buff_head *p_ul_list)
{
	struct ipc_protocol_td *td;
	bool hpda_pending = false;
	struct sk_buff *skb;
	s32 free_elements;
	u32 head;
	u32 tail;

	if (!ipc_protocol->p_ap_shm) {
		dev_err(ipc_protocol->dev, "driver is not initialized");
		return false;
	}

	/* Get head and tail of the td list and calculate
	 * the number of free elements.
	 */
	head = le32_to_cpu(ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr]);
	tail = pipe->old_tail;

	while (!skb_queue_empty(p_ul_list)) {
		if (head < tail)
			free_elements = tail - head - 1;
		else
			free_elements =
				pipe->nr_of_entries - head + ((s32)tail - 1);

		if (free_elements <= 0) {
			dev_dbg(ipc_protocol->dev,
				"no free td elements for UL pipe %d",
				pipe->pipe_nr);
			break;
		}

		/* Get the td address. */
		td = &pipe->tdr_start[head];

		/* Take the first element of the uplink list and add it
		 * to the td list.
		 */
		skb = skb_dequeue(p_ul_list);
		if (WARN_ON(!skb))
			break;

		/* Save the reference to the uplink skbuf. */
		pipe->skbr_start[head] = skb;

		td->buffer.address = IPC_CB(skb)->mapping;
		td->scs = cpu_to_le32(skb->len) & cpu_to_le32(SIZE_MASK);
		td->next = 0;

		pipe->nr_of_queued_entries++;

		/* Calculate the new head and save it. */
		head++;
		if (head >= pipe->nr_of_entries)
			head = 0;

		ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr] =
			cpu_to_le32(head);
	}

	if (pipe->old_head != head) {
		dev_dbg(ipc_protocol->dev, "New UL TDs Pipe:%d", pipe->pipe_nr);

		pipe->old_head = head;
		/* Trigger doorbell because of pending UL packets. */
		hpda_pending = true;
	}

	return hpda_pending;
}

Annotation

Implementation Notes