diff options
| author | Miguel Ojeda <ojeda@kernel.org> | 2026-08-16 15:32:33 +0200 |
|---|---|---|
| committer | Miguel Ojeda <ojeda@kernel.org> | 2026-08-23 21:27:17 +0200 |
| commit | 5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch) | |
| tree | 93a1ed1d337bc53adf1e572c2586d347703b286e /drivers/comedi/comedi_pci.c | |
| download | linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip | |
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit
`objtool` errors such as:
vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a:
can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd
The reason is that in such builds, the Clang invocation that compiles
the combined Rust plus helpers bitcode emits LLVM bitcode (again) --
the final code generation happens in the linker's LTO step, which the
`-mllvm` trap options passed to Clang do not reach.
This, in turn, means that unreachable traps are missing, and the
impossible paths do not merely fallthrough to the next symbol, but past
the end of their own section, since LTO builds place each function in
its own section.
Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always
emits machine code directly, with the traps in place.
Assisted-by: LLM
Cc: Gary Guo <gary@garyguo.net>
Cc: Boqun Feng <boqun@kernel.org>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust")
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'drivers/comedi/comedi_pci.c')
| -rw-r--r-- | drivers/comedi/comedi_pci.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/drivers/comedi/comedi_pci.c b/drivers/comedi/comedi_pci.c new file mode 100644 index 000000000..da618f5e3 --- /dev/null +++ b/drivers/comedi/comedi_pci.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * comedi_pci.c + * Comedi PCI driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/comedi/comedi_pci.h> + +/** + * comedi_to_pci_dev() - Return PCI device attached to COMEDI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. + * + * Return: Attached PCI device if @dev->hw_dev is non-%NULL. + * Return %NULL if @dev->hw_dev is %NULL. + */ +struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) +{ + return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_pci_dev); + +/** + * comedi_pci_enable() - Enable the PCI device and request the regions + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. Enable the PCI device + * and request its regions. Set @dev->ioenabled to %true if successful, + * otherwise undo what was done. + * + * Calls to comedi_pci_enable() and comedi_pci_disable() cannot be nested. + * + * Return: + * 0 on success, + * -%ENODEV if @dev->hw_dev is %NULL, + * -%EBUSY if regions busy, + * or some negative error number if failed to enable PCI device. + * + */ +int comedi_pci_enable(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + int rc; + + if (!pcidev) + return -ENODEV; + + rc = pci_enable_device(pcidev); + if (rc < 0) + return rc; + + rc = pci_request_regions(pcidev, dev->board_name); + if (rc < 0) + pci_disable_device(pcidev); + else + dev->ioenabled = true; + + return rc; +} +EXPORT_SYMBOL_GPL(comedi_pci_enable); + +/** + * comedi_pci_disable() - Release the regions and disable the PCI device + * @dev: COMEDI device. + * + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a + * a &struct device embedded in a &struct pci_dev. If the earlier call + * to comedi_pci_enable() was successful, release the PCI device's regions + * and disable it. Reset @dev->ioenabled back to %false. + */ +void comedi_pci_disable(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (pcidev && dev->ioenabled) { + pci_release_regions(pcidev); + pci_disable_device(pcidev); + } + dev->ioenabled = false; +} +EXPORT_SYMBOL_GPL(comedi_pci_disable); + +/** + * comedi_pci_detach() - A generic "detach" handler for PCI COMEDI drivers + * @dev: COMEDI device. + * + * COMEDI drivers for PCI devices that need no special clean-up of private data + * and have no ioremapped regions other than that pointed to by @dev->mmio may + * use this function as its "detach" handler called by the COMEDI core when a + * COMEDI device is being detached from the low-level driver. It may be also + * called from a more specific "detach" handler that does additional clean-up. + * + * Free the IRQ if @dev->irq is non-zero, iounmap @dev->mmio if it is + * non-%NULL, and call comedi_pci_disable() to release the PCI device's regions + * and disable it. + */ +void comedi_pci_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (!pcidev || !dev->ioenabled) + return; + + if (dev->irq) { + free_irq(dev->irq, dev); + dev->irq = 0; + } + if (dev->mmio) { + iounmap(dev->mmio); + dev->mmio = NULL; + } + comedi_pci_disable(dev); +} +EXPORT_SYMBOL_GPL(comedi_pci_detach); + +/** + * comedi_pci_auto_config() - Configure/probe a PCI COMEDI device + * @pcidev: PCI device. + * @driver: Registered COMEDI driver. + * @context: Driver specific data, passed to comedi_auto_config(). + * + * Typically called from the pci_driver (*probe) function. Auto-configure + * a COMEDI device, using the &struct device embedded in *@pcidev as the + * hardware device. The @context value gets passed through to @driver's + * "auto_attach" handler. The "auto_attach" handler may call + * comedi_to_pci_dev() on the passed in COMEDI device to recover @pcidev. + * + * Return: The result of calling comedi_auto_config() (0 on success, or + * a negative error number on failure). + */ +int comedi_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver, + unsigned long context) +{ + return comedi_auto_config(&pcidev->dev, driver, context); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_config); + +/** + * comedi_pci_auto_unconfig() - Unconfigure/remove a PCI COMEDI device + * @pcidev: PCI device. + * + * Typically called from the pci_driver (*remove) function. Auto-unconfigure + * a COMEDI device attached to this PCI device, using a pointer to the + * &struct device embedded in *@pcidev as the hardware device. The COMEDI + * driver's "detach" handler will be called during unconfiguration of the + * COMEDI device. + * + * Note that the COMEDI device may have already been unconfigured using the + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it + * again should be ignored. + */ +void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +{ + comedi_auto_unconfig(&pcidev->dev); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); + +/** + * comedi_pci_driver_register() - Register a PCI COMEDI driver + * @comedi_driver: COMEDI driver to be registered. + * @pci_driver: PCI driver to be registered. + * + * This function is called from the module_init() of PCI COMEDI driver modules + * to register the COMEDI driver and the PCI driver. Do not call it directly, + * use the module_comedi_pci_driver() helper macro instead. + * + * Return: 0 on success, or a negative error number on failure. + */ +int comedi_pci_driver_register(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = pci_register_driver(pci_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_register); + +/** + * comedi_pci_driver_unregister() - Unregister a PCI COMEDI driver + * @comedi_driver: COMEDI driver to be unregistered. + * @pci_driver: PCI driver to be unregistered. + * + * This function is called from the module_exit() of PCI COMEDI driver modules + * to unregister the PCI driver and the COMEDI driver. Do not call it + * directly, use the module_comedi_pci_driver() helper macro instead. + */ +void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + pci_unregister_driver(pci_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); + +MODULE_AUTHOR("https://www.comedi.org"); +MODULE_DESCRIPTION("Comedi PCI interface module"); +MODULE_LICENSE("GPL"); |
