drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
Extension
.c
Size
8514 bytes
Lines
329
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (!ret) {
			ce = cte;
			read_unlock_bh(&ctbl->lock);
			refcount_inc(&ce->refcnt);
			return 0;
		}
	}
	read_unlock_bh(&ctbl->lock);

	write_lock_bh(&ctbl->lock);
	if (!list_empty(&ctbl->ce_free_head)) {
		ce = list_first_entry(&ctbl->ce_free_head,
				      struct clip_entry, list);
		list_del_init(&ce->list);
		spin_lock_init(&ce->lock);
		refcount_set(&ce->refcnt, 0);
		atomic_dec(&ctbl->nfree);
		list_add_tail(&ce->list, &ctbl->hash_list[hash]);
		if (v6) {
			ce->addr6.sin6_family = AF_INET6;
			memcpy(ce->addr6.sin6_addr.s6_addr,
			       lip, sizeof(struct in6_addr));
			ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
			if (ret) {
				write_unlock_bh(&ctbl->lock);
				dev_err(adap->pdev_dev,
					"CLIP FW cmd failed with error %d, "
					"Connections using %pI6c won't be "
					"offloaded",
					ret, ce->addr6.sin6_addr.s6_addr);
				return ret;
			}
		} else {
			ce->addr.sin_family = AF_INET;
			memcpy((char *)(&ce->addr.sin_addr), lip,
			       sizeof(struct in_addr));
		}
	} else {
		write_unlock_bh(&ctbl->lock);
		dev_info(adap->pdev_dev, "CLIP table overflow, "
			 "Connections using %pI6c won't be offloaded",
			 (void *)lip);
		return -ENOMEM;
	}
	write_unlock_bh(&ctbl->lock);
	refcount_set(&ce->refcnt, 1);
	return 0;
}
EXPORT_SYMBOL(cxgb4_clip_get);

void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
{
	struct adapter *adap = netdev2adap(dev);
	struct clip_tbl *ctbl = adap->clipt;
	struct clip_entry *ce, *cte;
	u32 *addr = (u32 *)lip;
	int hash;
	int ret = -1;

	if (!ctbl)
		return;

	hash = clip_addr_hash(ctbl, addr, v6);

	read_lock_bh(&ctbl->lock);
	list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
		if (cte->addr6.sin6_family == AF_INET6 && v6)
			ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
				     sizeof(struct in6_addr));
		else if (cte->addr.sin_family == AF_INET && !v6)
			ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
				     sizeof(struct in_addr));
		if (!ret) {
			ce = cte;
			read_unlock_bh(&ctbl->lock);
			goto found;
		}
	}
	read_unlock_bh(&ctbl->lock);

	return;
found:
	write_lock_bh(&ctbl->lock);
	spin_lock_bh(&ce->lock);
	if (refcount_dec_and_test(&ce->refcnt)) {
		list_del_init(&ce->list);
		list_add_tail(&ce->list, &ctbl->ce_free_head);
		atomic_inc(&ctbl->nfree);
		if (v6)
			clip6_release_mbox(dev, (const struct in6_addr *)lip);

Annotation

Implementation Notes