Skip to content

himci: finish the request when the FIFO reset times out - #57

Merged
widgetii merged 2 commits into
hisilicon-hi3516cv500from
himci/finish-the-request-on-fifo-reset-timeout
Sep 22, 2026
Merged

widgetii merged 2 commits into
hisilicon-hi3516cv500from
himci/finish-the-request-on-fifo-reset-timeout

Conversation

@widgetii

Copy link
Copy Markdown
Member

himci_request() has ten ways out. Nine reach request_end, which calls
himci_finish_request() and through it mmc_request_done(). The tenth — in
the FIFO-reset loop on the data path — is a bare return.

do {
    tmp_reg = himci_readl(host->base + MCI_CTRL);
    fifo_count++;
    if (fifo_count >= retry_count) {
        pr_info("fifo reset is timeout!");
        return;                       /* <- nothing completes the request */
    }
} while (tmp_reg & FIFO_RESET);

Why it matters more than one lost request

The MMC core is parked in mmc_wait_for_req() on an uninterruptible
wait_for_completion(). Nothing will ever complete it, so the caller is an
unkillable D state — and because the host is never released, every later
request queues behind the same claim. The block layer, any MMC_IOC_CMD
passthrough, and the card's own rescan all stop together.

On a camera that is recording stopping and staying stopped until someone cuts
the power.

The fix

Set the data error the way every other timeout in this driver does
(-ETIMEDOUT, as himci_wait_data_complete() and himci_wait_card_complete()
both do) and goto request_end. There is no DMA to unwind — himci_idma_start()
is below this point.

What this is and is not

Found by reading, while establishing whether the MMC_IOC_CMD passthrough is
usable for SD vendor-health commands on HiSilicon. There is an older report of
exactly this shape — a data command on a card that did not answer leaving an
unkillable process and a camera that needed a power cycle — and the signature
matches, but I could not re-trigger it, so this is offered as a correctness
fix rather than a diagnosis.

I did look for a way to force it honestly. retry_count is a module_param
with 0600 permissions, but the driver is built in and exposes no
/sys/module/himci/parameters/, so the only lever is a himci.retry_count=1
bootarg — and on a board whose rootfs is on NOR while the SD card is mounted
during init, that wedges the mount on every boot. The test board has neither
altbootcmd nor a wired serial console, so that experiment ends in a board
nobody can reach. Not worth it to prove what the control flow already states.

The path leaves fifo reset is timeout! in dmesg, which is what to grep for if
it is ever seen in the field.

Testing

Compile-tested for hi3516av300 — CONFIG_HIMCI=y, arm-openipc-linux-gnueabi,
kernel 4.9.37, make drivers/mmc/host/himci/himci.o clean with no new
warnings. Behaviour on that board is unchanged in normal use: SD recording, a
CMD13 passthrough and a 512-byte CMD56 data read all behave exactly as
before this patch, because none of them reaches the FIFO-reset timeout.

Other branches

The identical bare return is in hisilicon-hi3516ev200,
hisilicon-hi3516cv200, hisilicon-hi3516av100 and hisilicon-hi3536dv100.
hisilicon-hi3516cv300 and hisilicon-hi3519v101 do not have it. Happy to
send the same one-line change to the other four if you would like it in one go
or as separate PRs — say which.

himci_request() has ten ways out and nine of them reach request_end, which
calls himci_finish_request() and through it mmc_request_done(). The tenth,
in the FIFO-reset loop on the data path, is a bare return.

Nothing else completes the request. The MMC core is sitting in
mmc_wait_for_req() on an uninterruptible wait_for_completion(), so the caller
becomes an unkillable D state, and because the host is never released every
later request queues behind it. On a camera that is recording stopping and
staying stopped until someone cuts the power -- the block layer, any
MMC_IOC_CMD passthrough, and the card's own rescan all block on the same
claim.

Set the data error the way every other timeout in this driver does and jump to
request_end. There is no DMA to unwind: himci_idma_start() is below this
point.

Found by reading, while working out why an MMC_IOC_CMD passthrough had once
been reported as hanging a camera unkillably. That report matches this
signature exactly -- a data command on a card that did not answer -- but I
could not re-trigger it to confirm, so this is offered as a correctness fix
rather than a diagnosis. The path leaves "fifo reset is timeout!" in dmesg,
which is the thing to grep for if it is ever seen in the field.

Compile-tested for hi3516av300 (CONFIG_HIMCI=y, arm-openipc-linux-gnueabi,
kernel 4.9.37); no new warnings. The same bare return is in the
hisilicon-hi3516ev200, hisilicon-hi3516cv200, hisilicon-hi3516av100 and
hisilicon-hi3536dv100 branches and wants the same one-line change there.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Complete HiMCI requests after FIFO reset timeouts

🐞 Bug fix 🕐 Less than 10 minutes

Grey Divider

AI Description

• Marks FIFO reset timeouts as data transfer errors.
• Routes timeout failures through shared request cleanup and MMC completion.
• Prevents indefinite waits and host-wide request stalls.
Diagram

sequenceDiagram
    actor Caller
    participant Core as MMC Core
    participant Driver as himci_request
    participant FIFO as FIFO Control
    participant Cleanup as request_end
    participant Finish as finish_request
    Caller->>Core: Submit data request
    Core->>Driver: Dispatch request
    Driver->>FIFO: Reset FIFO
    FIFO-->>Driver: Reset timeout
    Driver->>Driver: Set ETIMEDOUT
    Driver->>Cleanup: Enter shared cleanup
    Cleanup->>Finish: Finish request
    Finish-->>Core: mmc_request_done
    Core-->>Caller: Complete with error
Loading
High-Level Assessment

The shared request_end path is the appropriate solution because it preserves existing interrupt cleanup, error accounting, host-state reset, and MMC completion behavior. Directly calling mmc_request_done() or himci_finish_request() from the timeout branch would duplicate control flow and could bypass required cleanup.

Files changed (1) +16 / -1

Bug fix (1) +16 / -1
himci.cComplete timed-out FIFO reset requests +16/-1

Complete timed-out FIFO reset requests

• The FIFO reset timeout now records -ETIMEDOUT on the request data and jumps to request_end instead of returning early. This ensures interrupt cleanup, error accounting, host-state release, and mmc_request_done() all occur.

drivers/mmc/host/himci/himci.c

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Timed-out requests keep buffers mapped ✓ Resolved 🐞 Bug ☼ Reliability
Description
himci_setup_data() maps the request scatterlist before the new timeout branch sets data->error
and jumps directly to request_end, bypassing the only dma_unmap_sg() call in
himci_data_done(). A FIFO-reset timeout therefore returns the request buffer to the MMC core while
it remains DMA-mapped, leaking mapping resources and violating buffer ownership on every occurrence.
Code

drivers/mmc/host/himci/himci.c[R1049-1050]

+				mrq->data->error = -ETIMEDOUT;
+				goto request_end;
Evidence
himci_setup_data() assigns host->data and calls dma_map_sg() at lines 523-531. The driver's
sole matching dma_unmap_sg() is inside himci_data_done() at lines 772-780, while the newly added
branch at lines 1049-1050 reaches request completion without calling that cleanup function.

drivers/mmc/host/himci/himci.c[523-531]
drivers/mmc/host/himci/himci.c[772-780]
drivers/mmc/host/himci/himci.c[1049-1050]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The FIFO-reset timeout completes a request after `himci_setup_data()` has DMA-mapped its scatterlist, but it bypasses `himci_data_done()`, which contains the driver's only matching unmap operation.
## Fix Focus Areas
- drivers/mmc/host/himci/himci.c[528-531]
- drivers/mmc/host/himci/himci.c[777-780]
- drivers/mmc/host/himci/himci.c[1049-1050]
## Recommended Fix
After setting `mrq->data->error`, call `himci_data_done(host, 0)` before jumping to `request_end`. This releases the mapping, records zero transferred bytes because the error is already set, and clears `host->data`; DMA does not need stopping because it has not started.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread drivers/mmc/host/himci/himci.c
From review of the previous commit, and a fault in it.

himci_setup_data() does two things that have to be undone: it maps the
scatterlist for the device, and it takes host->data. himci_data_done() is the
only thing that gives either back. Jumping to request_end from the FIFO-reset
timeout skipped it, so the buffer went back to the MMC core still mapped for
the device, and host->data was left pointing at a request that had just been
completed.

Call it, with no status bits, so it unmaps, clears host->data, zeroes
bytes_xfered and keeps the -ETIMEDOUT set above rather than deciding an error
of its own. Still no himci_idma_stop(): the engine is genuinely not running
there, because himci_idma_start() is below this point.

Worth noting while this is open: the command-error paths further down have the
same shape. When himci_exec_cmd() fails or the command completes with an
error, the data branch calls himci_idma_stop() and falls through to
request_end without himci_data_done(), so those leak the mapping too. That is
older than this change and is left alone here rather than folded into a
one-line fix.

Compile-tested as before, no new warnings.
@widgetii

Copy link
Copy Markdown
Member Author

Right, and it is a fault in the fix rather than in the old code. Addressed in
the follow-up commit.

himci_setup_data() does two things that have to be undone: it maps the
scatterlist for the device, and it takes host->data. himci_data_done() is
the only thing that gives either back. Jumping to request_end skipped it, so
the buffer went back to the MMC core still mapped for the device — and
host->data was left pointing at a request that had just been completed, which
is the worse half: a later himci_data_done() or an IRQ would have dereferenced
it.

It now calls himci_data_done(host, 0) before the jump. With no status bits
neither error branch inside it fires, so it unmaps, clears host->data, zeroes
bytes_xfered and keeps the -ETIMEDOUT set just above rather than deciding an
error of its own. Still no himci_idma_stop(): the engine genuinely is not
running there, because himci_idma_start() is below this point.

Worth recording while this is open, since it is the same class and I looked:
the command-error paths further down leak the same mapping. When
himci_exec_cmd() fails, or the command completes with an error, the data
branch calls himci_idma_stop() and falls through to request_end without
himci_data_done(). That is older than this change and is left alone rather
than folded into a one-line fix — happy to send it separately if you want it.

Compile-tested as before, no new warnings.

@widgetii
widgetii merged commit 24e839e into hisilicon-hi3516cv500 Sep 22, 2026
@widgetii
widgetii deleted the himci/finish-the-request-on-fifo-reset-timeout branch September 22, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant