From 7c269fa374421169c5f0df2d7aaa8aa04b037ea3 Mon Sep 17 00:00:00 2001 From: Alexander Gall Date: Wed, 15 Apr 2020 10:33:14 +0200 Subject: [PATCH 1/3] map_pci_memory: wait for kernel driver to release the device Starting with 4.5, the kernel returns EINVAL for mmap() if compiled with CONFIG_IO_STRICT_DEVMEM=y. Unbinding the device is an asynchronous operation. map_pci_memory() waits for EINVAL to disappear or gives up after a timeout of 5 seconds. # Conflicts: # src/lib/hardware/pci.lua --- src/lib/hardware/pci.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/hardware/pci.lua b/src/lib/hardware/pci.lua index ab1714be03..39b3bbb8c4 100644 --- a/src/lib/hardware/pci.lua +++ b/src/lib/hardware/pci.lua @@ -186,7 +186,17 @@ end function map_pci_memory (f) local st = assert(f:stat()) - local mem = assert(f:mmap(nil, st.size, "read, write", "shared", 0)) + local mem + -- mmap() returns EINVAL on Linux >= 4.5 if the device is still + -- claimed by the kernel driver. We assume that + -- unbind_device_from_linux() has already been called but it may take + -- some time for the driver to release the device. + lib.waitfor2("mmap of "..filepath, + function () + mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) + assert(not err or err.INVAL) + return mem + end, 5, 1000000) return ffi.cast("uint32_t *", mem) end From 1c7497cb192493e2d80a3f0394daafa3813dbff3 Mon Sep 17 00:00:00 2001 From: Alexander Gall Date: Mon, 4 May 2020 16:56:10 +0200 Subject: [PATCH 2/3] lib.hardware.pci.map_pci_memory: only wait if first call failed # Conflicts: # src/lib/hardware/pci.lua --- src/lib/hardware/pci.lua | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib/hardware/pci.lua b/src/lib/hardware/pci.lua index 39b3bbb8c4..d450ad80a8 100644 --- a/src/lib/hardware/pci.lua +++ b/src/lib/hardware/pci.lua @@ -186,17 +186,20 @@ end function map_pci_memory (f) local st = assert(f:stat()) - local mem + local mem, err + mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) -- mmap() returns EINVAL on Linux >= 4.5 if the device is still -- claimed by the kernel driver. We assume that -- unbind_device_from_linux() has already been called but it may take -- some time for the driver to release the device. - lib.waitfor2("mmap of "..filepath, - function () - mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) - assert(not err or err.INVAL) - return mem - end, 5, 1000000) + if not mem then + lib.waitfor2("mmap of "..filepath, + function () + mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) + assert(not err or err.INVAL) + return mem + end, 5, 1000000) + end return ffi.cast("uint32_t *", mem) end From 6dd5418d38099f0a043edba2f63dbe825ee8c9c6 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Tue, 19 Apr 2022 12:41:08 +0200 Subject: [PATCH 3/3] lib.hardware.pci: cleanup previous commits --- src/lib/hardware/pci.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/hardware/pci.lua b/src/lib/hardware/pci.lua index d450ad80a8..f45b182ff8 100644 --- a/src/lib/hardware/pci.lua +++ b/src/lib/hardware/pci.lua @@ -186,20 +186,19 @@ end function map_pci_memory (f) local st = assert(f:stat()) - local mem, err - mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) + local mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) -- mmap() returns EINVAL on Linux >= 4.5 if the device is still -- claimed by the kernel driver. We assume that -- unbind_device_from_linux() has already been called but it may take -- some time for the driver to release the device. - if not mem then + if not mem and err.INVAL then lib.waitfor2("mmap of "..filepath, function () mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) - assert(not err or err.INVAL) - return mem + return mem ~= nil or not err.INVAL end, 5, 1000000) end + assert(mem, err) return ffi.cast("uint32_t *", mem) end