drivers/s390/net/qeth_l2_main.c

Source file repositories/reference/linux-study-clean/drivers/s390/net/qeth_l2_main.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/net/qeth_l2_main.c
Extension
.c
Size
69057 bytes
Lines
2473
Domain
Driver Families
Bucket
drivers/s390
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 qeth_l2_iqd_netdev_ops;
static const struct net_device_ops qeth_l2_osa_netdev_ops;

static bool qeth_l2_must_learn(struct net_device *netdev,
			       struct net_device *dstdev)
{
	struct qeth_priv *priv;

	priv = netdev_priv(netdev);
	return (netdev != dstdev &&
		(priv->brport_features & BR_LEARNING_SYNC) &&
		!(br_port_flag_is_set(netdev, BR_ISOLATED) &&
		  br_port_flag_is_set(dstdev, BR_ISOLATED)) &&
		(netdev->netdev_ops == &qeth_l2_iqd_netdev_ops ||
		 netdev->netdev_ops == &qeth_l2_osa_netdev_ops));
}

/**
 *	qeth_l2_br2dev_worker() - update local MACs
 *	@work: bridge to device FDB update
 *
 *	Update local MACs of a learning_sync bridgeport so it can receive
 *	messages for a destination port.
 *	In case of an isolated learning_sync port, also update its isolated
 *	siblings.
 */
static void qeth_l2_br2dev_worker(struct work_struct *work)
{
	struct qeth_l2_br2dev_event_work *br2dev_event_work =
		container_of(work, struct qeth_l2_br2dev_event_work, work);
	struct net_device *lsyncdev = br2dev_event_work->lsync_dev;
	struct net_device *dstdev = br2dev_event_work->dst_dev;
	struct net_device *brdev = br2dev_event_work->br_dev;
	unsigned long event = br2dev_event_work->event;
	unsigned char *addr = br2dev_event_work->addr;
	struct qeth_card *card = lsyncdev->ml_priv;
	struct net_device *lowerdev;
	struct list_head *iter;
	int err = 0;

	QETH_CARD_TEXT_(card, 4, "b2dw%04lx", event);
	QETH_CARD_TEXT_(card, 4, "ma%012llx", ether_addr_to_u64(addr));

	rcu_read_lock();
	/* Verify preconditions are still valid: */
	if (!netif_is_bridge_port(lsyncdev) ||
	    brdev != netdev_master_upper_dev_get_rcu(lsyncdev))
		goto unlock;
	if (!qeth_l2_must_learn(lsyncdev, dstdev))
		goto unlock;

	if (br_port_flag_is_set(lsyncdev, BR_ISOLATED)) {
		/* Update lsyncdev and its isolated sibling(s): */
		iter = &brdev->adj_list.lower;
		lowerdev = netdev_next_lower_dev_rcu(brdev, &iter);
		while (lowerdev) {
			if (br_port_flag_is_set(lowerdev, BR_ISOLATED)) {
				switch (event) {
				case SWITCHDEV_FDB_ADD_TO_DEVICE:
					err = dev_uc_add(lowerdev, addr);
					break;
				case SWITCHDEV_FDB_DEL_TO_DEVICE:
					err = dev_uc_del(lowerdev, addr);
					break;
				default:
					break;
				}
				if (err) {
					QETH_CARD_TEXT(card, 2, "b2derris");
					QETH_CARD_TEXT_(card, 2,
							"err%02lx%03d", event,
							lowerdev->ifindex);
				}
			}
			lowerdev = netdev_next_lower_dev_rcu(brdev, &iter);
		}
	} else {
		switch (event) {
		case SWITCHDEV_FDB_ADD_TO_DEVICE:
			err = dev_uc_add(lsyncdev, addr);
			break;
		case SWITCHDEV_FDB_DEL_TO_DEVICE:
			err = dev_uc_del(lsyncdev, addr);
			break;
		default:
			break;
		}
		if (err)
			QETH_CARD_TEXT_(card, 2, "b2derr%02lx", event);
	}

Annotation

Implementation Notes