drivers/net/wwan/mhi_wwan_mbim.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/mhi_wwan_mbim.c
Extension
.c
Size
18194 bytes
Lines
671
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 const struct net_device_ops mhi_mbim_ndo = {
	.ndo_open = mhi_mbim_ndo_open,
	.ndo_stop = mhi_mbim_ndo_stop,
	.ndo_start_xmit = mhi_mbim_ndo_xmit,
	.ndo_get_stats64 = mhi_mbim_ndo_get_stats64,
};

static int mhi_mbim_newlink(void *ctxt, struct net_device *ndev, u32 if_id,
			    struct netlink_ext_ack *extack)
{
	struct mhi_mbim_link *link = wwan_netdev_drvpriv(ndev);
	struct mhi_mbim_context *mbim = ctxt;

	link->mbim = mbim;
	link->session = mhi_mbim_get_link_mux_id(link->mbim->mdev->mhi_cntrl) + if_id;
	link->ndev = ndev;
	u64_stats_init(&link->rx_syncp);
	u64_stats_init(&link->tx_syncp);

	rcu_read_lock();
	if (mhi_mbim_get_link_rcu(mbim, if_id)) {
		rcu_read_unlock();
		return -EEXIST;
	}
	rcu_read_unlock();

	/* Already protected by RTNL lock */
	hlist_add_head_rcu(&link->hlnode, &mbim->link_list[LINK_HASH(if_id)]);

	return register_netdevice(ndev);
}

static void mhi_mbim_dellink(void *ctxt, struct net_device *ndev,
			     struct list_head *head)
{
	struct mhi_mbim_link *link = wwan_netdev_drvpriv(ndev);

	hlist_del_init_rcu(&link->hlnode);
	synchronize_rcu();

	unregister_netdevice_queue(ndev, head);
}

static void mhi_mbim_setup(struct net_device *ndev)
{
	ndev->header_ops = NULL;  /* No header */
	ndev->type = ARPHRD_RAWIP;
	ndev->needed_headroom = sizeof(struct mbim_tx_hdr);
	ndev->hard_header_len = 0;
	ndev->addr_len = 0;
	ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
	ndev->netdev_ops = &mhi_mbim_ndo;
	ndev->mtu = MHI_MBIM_DEFAULT_MTU;
	ndev->min_mtu = ETH_MIN_MTU;
	ndev->max_mtu = MHI_MAX_BUF_SZ - ndev->needed_headroom;
	ndev->tx_queue_len = 1000;
	ndev->needs_free_netdev = true;
}

static const struct wwan_ops mhi_mbim_wwan_ops = {
	.priv_size = sizeof(struct mhi_mbim_link),
	.setup = mhi_mbim_setup,
	.newlink = mhi_mbim_newlink,
	.dellink = mhi_mbim_dellink,
};

static int mhi_mbim_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
{
	struct mhi_controller *cntrl = mhi_dev->mhi_cntrl;
	struct mhi_mbim_context *mbim;
	int err;

	mbim = devm_kzalloc(&mhi_dev->dev, sizeof(*mbim), GFP_KERNEL);
	if (!mbim)
		return -ENOMEM;

	spin_lock_init(&mbim->tx_lock);
	dev_set_drvdata(&mhi_dev->dev, mbim);
	mbim->mdev = mhi_dev;
	mbim->mru = mhi_dev->mhi_cntrl->mru ? mhi_dev->mhi_cntrl->mru : MHI_DEFAULT_MRU;

	INIT_DELAYED_WORK(&mbim->rx_refill, mhi_net_rx_refill_work);

	/* Start MHI channels */
	err = mhi_prepare_for_transfer(mhi_dev);
	if (err)
		return err;

	/* Number of transfer descriptors determines size of the queue */
	mbim->rx_queue_sz = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);

Annotation

Implementation Notes