Page MenuHomeFreeBSD

Improve loading of multipage aligned buffers.
Needs ReviewPublic

Authored by mmel on Oct 11 2020, 9:00 AM.
Referenced Files
Unknown Object (File)
Sat, Feb 24, 3:01 PM
Unknown Object (File)
Mon, Feb 19, 2:33 AM
Unknown Object (File)
Jan 10 2024, 2:17 AM
Unknown Object (File)
Dec 28 2023, 10:04 PM
Unknown Object (File)
Dec 23 2023, 7:14 AM
Unknown Object (File)
Dec 13 2023, 8:41 AM
Unknown Object (File)
Dec 13 2023, 6:20 AM
Unknown Object (File)
Nov 9 2023, 7:17 PM



The multipage alignment requirements is incompatible with many aspects
of actual busdma code. Multi-page alignment requests are incompatible
with many aspects of current busdma code. Mainly with partially bounced
buffer segments and per-page loop in bus_dmamap_load_buffer(). Because
proper implementation would be a major restructuring of the code, add
the fix only for already known uses and do KASSERT for all other cases.

For this reason, bus_dmamap_load_buffer() should take the memory allocated
by bus_dmamap_alloc() as one segment bypassing per page segmentation. We can
do this because it is guaranteed that the memory is physically continuous.

Diff Detail

rS FreeBSD src repository - subversion
Lint Skipped
Tests Skipped

Event Timeline

mmel requested review of this revision.Oct 11 2020, 9:00 AM
bz added inline comments.




I tend to print the questionable value usually in KASSERTs as to see when it panics, what we got so we might be able to track down why we got there.


than instead of that again


and than again

I booted this on my emag:
CPU 1: APM eMAG 8180 r3p2 affinity: 0 1
and it seems to fix the issues that I had with cd sometimes detecting, other times not, as well as some weird reliability stuff relating to /etc/rc running at boot reliably.
I also had a weird issue where I'd type 'sudo reboot' and it would echo back 'sudo rebeoot' sometimes.
Not super extensive, but it's definitely not worse and preliminary indications are that it's better (though I'll admit to a smaller sample size with the patch than testing to produce the litany of horrors I've recounted).

This seems to fix issues with my USB connected optical drives not showing up as cd (only pass device). I've done 10 reboots, replugging it 10 times and they show up correctly each time.

Tested on:
FreeBSD 13.0-CURRENT r366770M
Pine64 RockPro64
USB adapter(s):
2x ASMedia Technology 1153e-based (external PSU connected) - Firmware: 141126_A1_EE_82, USB 3.0 compatible - Used for reboot/replug testing
JMicron-based PATA/SATA-adapter (PATA, external PSU connected), USB 2.0 compatible (don't know exact chipset)

This MR solved problem with eMMC cards on RK3399. Previously card slot was not initialized correctly due to some DMA mapping issues.

Tested on Armada 8040 DB - this patch fixes SDHCI DMA allocation issue.

This revision was not accepted when it landed; it landed in state Needs Review.Nov 2 2020, 8:26 AM
This revision was automatically updated to reflect the committed changes.
bz added inline comments.
864 ↗(On Diff #79063)

In the first if() case above we change sgsize which can become larger then buflen; in theory even the MIN() call at the start of the while loop can do that already.

I noticed this whit a call which started as "XXX-BZ buflen 0xe curaddr 0x1f382000 buf 0x1f382000 sgsize 0xe"

I am not entirely sure yet what is the proper way to deal with this "underflow" in `buflen -= sgsize;`; I am tempted to say

if (sgsize > buflen)
   buflen = 0;
   buflen -= sgsize;

but I am not (yet) sure what other implications that might have--as in: is there a valid case where we can end up here with buflen going negative?

In my case the return below would return EFBIG depsite it not being an error case otherwise.

The other concern I have and haven't checked yet, is if sgsize > buflen might lead to all other kinds of len problems with the segment downstream (and that would probably lead to a data inconsistency problem rather than an error/aborted transaction)?

864 ↗(On Diff #79063)

Can you, please, try this?

the three lines with sgsize should be replaced with

if (sgsize > (PAGE_SIZE - (curaddr & PAGE_MASK)) {
      sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
      sgsize =roundup2(sgsize, dmat->common.alignment));
      sgsize = MIN(sgsize, dmat->common.maxsegsz);

Untested, uncompiled.

864 ↗(On Diff #79063)

Fixing the () to make it compile this seems to be passing at quick glance and from reading compared to the old code seems to make sense.

Thanks a lot for the very quick reply.