drivers/net/ethernet/meta/fbnic/fbnic_mdio.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
Extension
.c
Size
6548 bytes
Lines
283
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

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */

#include <linux/mdio.h>
#include <linux/pcs/pcs-xpcs.h>

#include "fbnic.h"
#include "fbnic_netdev.h"

/* fbnic MDIO Interface Layout
 *
 *        +-------------------+
 *        |        MAC        |
 *        +-------------------+
 *            |   |   |   |  <-- 25GMII, 50GMII, or CGMII
 *        +-------------------+
 *  MMD 3 |        PCS        |
 *        +-------------------+
 *        |        FEC        |
 *        +-------------------+
 *  MMD 8 |  Separated PMA    |
 *        +-------------------+
 *              |       |     <-- PMD Service Interface
 *        +-------------------+
 *  MMD 1 |        PMD        |
 *        +-------------------+
 */

#define DW_VENDOR		BIT(15)
#define FBNIC_PCS_VENDOR	BIT(9)
#define FBNIC_PCS_ZERO_MASK	(DW_VENDOR - FBNIC_PCS_VENDOR)

static int
fbnic_mdio_ids(int id, int regnum)
{
	/* return correct IDs */
	switch (regnum) {
	case MDIO_DEVID1:
		return id >> 16;
	case MDIO_DEVID2:
		return id & 0xffff;
	case MDIO_DEVS1:
		return MDIO_DEVS_SEP_PMA1 | MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS;
	case MDIO_DEVS2:
		return 0;
	case MDIO_STAT2:
		return MDIO_STAT2_DEVPRST_VAL;
	}

	return 0;
}

static int
fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum)
{
	u8 aui = FBNIC_AUI_UNKNOWN;
	struct fbnic_net *fbn;
	int ret = 0;

	/* We don't need a second PMD, just one can handle both lanes */
	if (addr)
		return 0;

	if (fbd->netdev) {
		fbn = netdev_priv(fbd->netdev);
		if (fbn->aui < FBNIC_AUI_UNKNOWN)
			aui = fbn->aui;
	}

	switch (regnum) {
	case MDIO_PMA_RXDET:
		/* If training isn't complete default to 0 */
		if (fbd->pmd_state != FBNIC_PMD_SEND_DATA)
			break;
		/* Report either 1 or 2 lanes detected depending on config */
		ret = (MDIO_PMD_RXDET_GLOBAL | MDIO_PMD_RXDET_0) |
		      ((aui & FBNIC_AUI_MODE_R2) *
		       (MDIO_PMD_RXDET_1 / FBNIC_AUI_MODE_R2));
		break;
	default:
		ret = fbnic_mdio_ids(MP_FBNIC_XPCS_PMA_100G_ID, regnum);
		break;
	}

	dev_dbg(fbd->dev,
		"SWMII PMD Rd: Addr: %d RegNum: %d Value: 0x%04x\n",
		addr, regnum, ret);

	return ret;
}

Annotation

Implementation Notes