drivers/net/wwan/iosm/iosm_ipc_pcie.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/iosm/iosm_ipc_pcie.c
Extension
.c
Size
14255 bytes
Lines
587
Domain
Driver Families
Bucket
drivers/net
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 pci_driver iosm_ipc_driver = {
	.name = KBUILD_MODNAME,
	.probe = ipc_pcie_probe,
	.remove = ipc_pcie_remove,
	.driver = {
		.pm = &iosm_ipc_pm,
	},
	.id_table = iosm_ipc_ids,
};

int ipc_pcie_addr_map(struct iosm_pcie *ipc_pcie, unsigned char *data,
		      size_t size, dma_addr_t *mapping, int direction)
{
	if (ipc_pcie->pci) {
		*mapping = dma_map_single(&ipc_pcie->pci->dev, data, size,
					  direction);
		if (dma_mapping_error(&ipc_pcie->pci->dev, *mapping)) {
			dev_err(ipc_pcie->dev, "dma mapping failed");
			return -EINVAL;
		}
	}
	return 0;
}

void ipc_pcie_addr_unmap(struct iosm_pcie *ipc_pcie, size_t size,
			 dma_addr_t mapping, int direction)
{
	if (!mapping)
		return;
	if (ipc_pcie->pci)
		dma_unmap_single(&ipc_pcie->pci->dev, mapping, size, direction);
}

struct sk_buff *ipc_pcie_alloc_local_skb(struct iosm_pcie *ipc_pcie,
					 gfp_t flags, size_t size)
{
	struct sk_buff *skb;

	if (!ipc_pcie || !size) {
		pr_err("invalid pcie object or size");
		return NULL;
	}

	skb = __netdev_alloc_skb(NULL, size, flags);
	if (!skb)
		return NULL;

	IPC_CB(skb)->op_type = (u8)UL_DEFAULT;
	IPC_CB(skb)->mapping = 0;

	return skb;
}

struct sk_buff *ipc_pcie_alloc_skb(struct iosm_pcie *ipc_pcie, size_t size,
				   gfp_t flags, dma_addr_t *mapping,
				   int direction, size_t headroom)
{
	struct sk_buff *skb = ipc_pcie_alloc_local_skb(ipc_pcie, flags,
						       size + headroom);
	if (!skb)
		return NULL;

	if (headroom)
		skb_reserve(skb, headroom);

	if (ipc_pcie_addr_map(ipc_pcie, skb->data, size, mapping, direction)) {
		dev_kfree_skb(skb);
		return NULL;
	}

	BUILD_BUG_ON(sizeof(*IPC_CB(skb)) > sizeof(skb->cb));

	/* Store the mapping address in skb scratch pad for later usage */
	IPC_CB(skb)->mapping = *mapping;
	IPC_CB(skb)->direction = direction;
	IPC_CB(skb)->len = size;

	return skb;
}

void ipc_pcie_kfree_skb(struct iosm_pcie *ipc_pcie, struct sk_buff *skb)
{
	if (!skb)
		return;

	ipc_pcie_addr_unmap(ipc_pcie, IPC_CB(skb)->len, IPC_CB(skb)->mapping,
			    IPC_CB(skb)->direction);
	IPC_CB(skb)->mapping = 0;
	dev_kfree_skb(skb);
}

Annotation

Implementation Notes