drivers/net/ethernet/sfc/falcon/qt202x_phy.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sfc/falcon/qt202x_phy.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/falcon/qt202x_phy.c
Extension
.c
Size
14246 bytes
Lines
494
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

struct qt202x_phy_data {
	enum ef4_phy_mode phy_mode;
	bool bug17190_in_bad_state;
	unsigned long bug17190_timer;
	u32 firmware_ver;
};

#define QT2022C2_MAX_RESET_TIME 500
#define QT2022C2_RESET_WAIT 10

#define QT2025C_MAX_HEARTB_TIME (5 * HZ)
#define QT2025C_HEARTB_WAIT 100
#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10)
#define QT2025C_FWSTART_WAIT 100

#define BUG17190_INTERVAL (2 * HZ)

static int qt2025c_wait_heartbeat(struct ef4_nic *efx)
{
	unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME;
	int reg, old_counter = 0;

	/* Wait for firmware heartbeat to start */
	for (;;) {
		int counter;
		reg = ef4_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG);
		if (reg < 0)
			return reg;
		counter = ((reg >> PCS_FW_HEARTB_LBN) &
			    ((1 << PCS_FW_HEARTB_WIDTH) - 1));
		if (old_counter == 0)
			old_counter = counter;
		else if (counter != old_counter)
			break;
		if (time_after(jiffies, timeout)) {
			/* Some cables have EEPROMs that conflict with the
			 * PHY's on-board EEPROM so it cannot load firmware */
			netif_err(efx, hw, efx->net_dev,
				  "If an SFP+ direct attach cable is"
				  " connected, please check that it complies"
				  " with the SFP+ specification\n");
			return -ETIMEDOUT;
		}
		msleep(QT2025C_HEARTB_WAIT);
	}

	return 0;
}

static int qt2025c_wait_fw_status_good(struct ef4_nic *efx)
{
	unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME;
	int reg;

	/* Wait for firmware status to look good */
	for (;;) {
		reg = ef4_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
		if (reg < 0)
			return reg;
		if ((reg &
		     ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >=
		    PCS_UC_STATUS_FW_SAVE)
			break;
		if (time_after(jiffies, timeout))
			return -ETIMEDOUT;
		msleep(QT2025C_FWSTART_WAIT);
	}

	return 0;
}

static void qt2025c_restart_firmware(struct ef4_nic *efx)
{
	/* Restart microcontroller execution of firmware from RAM */
	ef4_mdio_write(efx, 3, 0xe854, 0x00c0);
	ef4_mdio_write(efx, 3, 0xe854, 0x0040);
	msleep(50);
}

static int qt2025c_wait_reset(struct ef4_nic *efx)
{
	int rc;

	rc = qt2025c_wait_heartbeat(efx);
	if (rc != 0)
		return rc;

	rc = qt2025c_wait_fw_status_good(efx);
	if (rc == -ETIMEDOUT) {
		/* Bug 17689: occasionally heartbeat starts but firmware status

Annotation

Implementation Notes