drivers/net/ethernet/atheros/alx/hw.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/atheros/alx/hw.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/atheros/alx/hw.c
Extension
.c
Size
32348 bytes
Lines
1125
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

if ((read & wait) == 0) {
			if (val)
				*val = read;
			return true;
		}
		mdelay(1);
	}

	return false;
}

static bool alx_read_macaddr(struct alx_hw *hw, u8 *addr)
{
	u32 mac0, mac1;

	mac0 = alx_read_mem32(hw, ALX_STAD0);
	mac1 = alx_read_mem32(hw, ALX_STAD1);

	/* addr should be big-endian */
	put_unaligned(cpu_to_be32(mac0), (__be32 *)(addr + 2));
	put_unaligned(cpu_to_be16(mac1), (__be16 *)addr);

	return is_valid_ether_addr(addr);
}

int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr)
{
	u32 val;

	/* try to get it from register first */
	if (alx_read_macaddr(hw, addr))
		return 0;

	/* try to load from efuse */
	if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val))
		return -EIO;
	alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START);
	if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL))
		return -EIO;
	if (alx_read_macaddr(hw, addr))
		return 0;

	/* try to load from flash/eeprom (if present) */
	val = alx_read_mem32(hw, ALX_EFLD);
	if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) {
		if (!alx_wait_reg(hw, ALX_EFLD,
				  ALX_EFLD_STAT | ALX_EFLD_START, &val))
			return -EIO;
		alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START);
		if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL))
			return -EIO;
		if (alx_read_macaddr(hw, addr))
			return 0;
	}

	return -EIO;
}

void alx_set_macaddr(struct alx_hw *hw, const u8 *addr)
{
	u32 val;

	/* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */
	val = be32_to_cpu(get_unaligned((__be32 *)(addr + 2)));
	alx_write_mem32(hw, ALX_STAD0, val);
	val = be16_to_cpu(get_unaligned((__be16 *)addr));
	alx_write_mem32(hw, ALX_STAD1, val);
}

static void alx_reset_osc(struct alx_hw *hw, u8 rev)
{
	u32 val, val2;

	/* clear Internal OSC settings, switching OSC by hw itself */
	val = alx_read_mem32(hw, ALX_MISC3);
	alx_write_mem32(hw, ALX_MISC3,
			(val & ~ALX_MISC3_25M_BY_SW) |
			ALX_MISC3_25M_NOTO_INTNL);

	/* 25M clk from chipset may be unstable 1s after de-assert of
	 * PERST, driver need re-calibrate before enter Sleep for WoL
	 */
	val = alx_read_mem32(hw, ALX_MISC);
	if (rev >= ALX_REV_B0) {
		/* restore over current protection def-val,
		 * this val could be reset by MAC-RST
		 */
		ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF);
		/* a 0->1 change will update the internal val of osc */
		val &= ~ALX_MISC_INTNLOSC_OPEN;

Annotation

Implementation Notes