# DF-3826 — e1000 HAL: double release of the SW_FW_SYNC PHY0 semaphore in `e1000_read_i2c_byte_generic`

## What

`sys/dev/netif/ig_hal/e1000_82575.c`, `e1000_read_i2c_byte_generic()`
(lines 3270-3349): when every I2C transfer attempt fails and the retry loop
is exhausted, the `fail:` label (line 3333) releases the
`E1000_SWFW_PHY0_SM` semaphore for each failed attempt, and then the
**unconditional** post-loop release at line 3344 releases it once more —
`releases == acquires + 1`. The sibling writer,
`e1000_write_i2c_byte_generic()` (lines 3361-3422), acquires once before the
loop, does **not** release inside `fail:`, and releases once after the loop —
proving the read path's asymmetry is a defect, not a protocol choice.

## Impact

The extra `e1000_release_swfw_sync_82575(hw, E1000_SWFW_PHY0_SM)` clears the
PHY0 bit in `E1000_SW_FW_SYNC` at a moment when this code path no longer owns
it. The two releases are separated by ~100 ms (`msec_delay(100)` at 3334 +
`e1000_i2c_bus_clear` bit-banging at 3335). If, in that window, another
function (multi-port i350 path, NVM/EEPROM path via
`e1000_acquire_nvm_82575`, or management firmware) legitimately acquires
PHY0, its ownership bit is silently dropped and a second party can then
acquire the "same" resource → concurrent PHY register / I2C access, torn
MDIO transfers, possible EEPROM/NVM access corruption. Logic/lifetime defect
in the SW/FW semaphore protocol; **not** kernel memory corruption.

Hardware-gated: reachable only on real 82575/82576/82580/i350/i354/i210
silicon with a failing/unseated SFP or wedged I2C bus (the read is used by
SFP detection, `e1000_set_sfp_media_type_82575`).

## Reproduce (logic-level replica — no hardware required)

```
scp swfw_double_release.c dfbsd-maxx:/tmp/
ssh dfbsd 'cc -O2 -Wall -o /tmp/swfw_double_release /tmp/swfw_double_release.c'
ssh dfbsd '/tmp/swfw_double_release; echo exit=$?'
```

Expected (see `run.log`):

```
case1 (all I2C ops fail, retries exhausted): acquires=9 releases=10 -> DOUBLE RELEASE
case2 (first attempt succeeds): acquires=1 releases=1 -> balanced
case3 (acquire fails): acquires=0 releases=0 -> balanced
exit=0
```

`swfw_double_release.c` replicates the exact control flow of
`e1000_read_i2c_byte_generic()` (retry starts at 1, `while (retry < 10)`,
release in `fail:`, unconditional release after the loop) with mocked
acquire/release; case 1 shows 9 successful acquires and 10 releases — the
kernel loop arithmetic is identical.

## Kernel-path verification status

The KVM audit guest has **no Intel 8257x-class NIC** (`pciconf -l`:
virtio-net + virtio-blk + bochs VGA only, see `env.txt`), so the in-kernel
path cannot be executed there — verdict `not_reproduced` for the kernel
reachability; the control-flow defect itself is proven at source level
(certain) and by the replica.

## Fix

`fix.diff` — only the post-loop release when the loop was exited via
`break` (semaphore still held). Never applied to `sys/` (read-only audit).
