From 82922fca2fd26a05ce5ce72ce913ab503c2b4ada Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Thu, 10 Oct 2024 12:52:07 -0500 Subject: [PATCH 0001/2947] Documentation: dmaengine: Correct reference to glReadPixels() The author very likely meant "glReadPixels()" instead of "glReadpielx()", which does not appear in the OpenGL API. https://registry.khronos.org/OpenGL-Refpages/gl4/html/glReadPixels.xhtml Signed-off-by: Nathan Lynch Link: https://lore.kernel.org/r/20241010-doc-dmaengine-glreadpixels-v1-1-8202e5834b13@amd.com Signed-off-by: Vinod Koul --- Documentation/driver-api/dmaengine/provider.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index 3085f8b460fa..48ad4fd6e277 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -172,8 +172,8 @@ Currently, the types available are: - It's usually used for copying pixel data between host memory and memory-mapped GPU device memory, such as found on modern PCI video graphics cards. The most immediate example is the OpenGL API function - ``glReadPielx()``, which might require a verbatim copy of a huge framebuffer - from local device memory onto host memory. + ``glReadPixels()``, which might require a verbatim copy of a huge + framebuffer from local device memory onto host memory. - DMA_XOR From 31fce300a1fef7b54ffb98e4cece8589529ca3bf Mon Sep 17 00:00:00 2001 From: Abraham Samuel Adekunle Date: Sat, 22 Mar 2025 16:36:53 +0100 Subject: [PATCH 0002/2947] staging: bcm2835-camera: Modify function call formatting The line is a function call which ends with an opening parenthesis thereby not adhering to the Linux kernel coding style. Modify the function call to include parameters on the same line as the opening parenthesis to improve readability and consistency while adhering to Linux coding styles. Reported by checkpatch: CHECK: Lines should not end with '(' Signed-off-by: Abraham Samuel Adekunle Link: https://lore.kernel.org/r/Z97ZFURPvDcTkjjf@HP-650 Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/bcm2835-camera/controls.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index 6bce45925bf1..e670226f1edf 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -533,17 +533,15 @@ static int ctrl_set_image_effect(struct bcm2835_mmal_dev *dev, control = &dev->component[COMP_CAMERA]->control; - ret = vchiq_mmal_port_parameter_set( - dev->instance, control, - MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, - &imagefx, sizeof(imagefx)); + ret = vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, + &imagefx, sizeof(imagefx)); if (ret) goto exit; - ret = vchiq_mmal_port_parameter_set( - dev->instance, control, - MMAL_PARAMETER_COLOUR_EFFECT, - &dev->colourfx, sizeof(dev->colourfx)); + ret = vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_COLOUR_EFFECT, + &dev->colourfx, sizeof(dev->colourfx)); } exit: From b0c3d42658a89a09bcd51d0013444d608b45836a Mon Sep 17 00:00:00 2001 From: Justin Cromer Date: Sun, 23 Mar 2025 15:46:27 -0700 Subject: [PATCH 0003/2947] staging: sm750fb: fix casing style on getDeviceID Fixes camel casing for getDeviceID function. This includes an update to the internal function variable 'deviceID' as it's relevant, needs updating, and is clearly scoped to the small function. Signed-off-by: Justin Cromer Link: https://lore.kernel.org/r/Z-CPQ7dGuTBZ3sWv@fedora Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_dvi.c | 2 +- drivers/staging/sm750fb/ddk750_sii164.c | 12 ++++++------ drivers/staging/sm750fb/ddk750_sii164.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index 8b81e8642f9e..3fb14eff2de1 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -16,7 +16,7 @@ static struct dvi_ctrl_device dcft_supported_dvi_controller[] = { { .init = sii164_init_chip, .get_vendor_id = sii164_get_vendor_id, - .get_device_id = sii164GetDeviceID, + .get_device_id = sii164_get_device_id, #ifdef SII164_FULL_FUNCTIONS .reset_chip = sii164ResetChip, .get_chip_string = sii164GetChipString, diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index 2532b60245ac..d50c71824321 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -48,22 +48,22 @@ unsigned short sii164_get_vendor_id(void) } /* - * sii164GetDeviceID + * sii164_get_device_id * This function gets the device ID of the DVI controller chip. * * Output: * Device ID */ -unsigned short sii164GetDeviceID(void) +unsigned short sii164_get_device_id(void) { - unsigned short deviceID; + unsigned short device_id; - deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, + device_id = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) | (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW); - return deviceID; + return device_id; } /* @@ -141,7 +141,7 @@ long sii164_init_chip(unsigned char edge_select, /* Check if SII164 Chip exists */ if ((sii164_get_vendor_id() == SII164_VENDOR_ID) && - (sii164GetDeviceID() == SII164_DEVICE_ID)) { + (sii164_get_device_id() == SII164_DEVICE_ID)) { /* * Initialize SII164 controller chip. */ diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h index 71a7c1cb42c4..a76091f6622b 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ b/drivers/staging/sm750fb/ddk750_sii164.h @@ -28,7 +28,7 @@ long sii164_init_chip(unsigned char edgeSelect, unsigned char pllFilterValue); unsigned short sii164_get_vendor_id(void); -unsigned short sii164GetDeviceID(void); +unsigned short sii164_get_device_id(void); #ifdef SII164_FULL_FUNCTIONS void sii164ResetChip(void); From 5771897aed7b24ff8c2acc5f38d1337024a7e82b Mon Sep 17 00:00:00 2001 From: Erick Karanja Date: Sat, 22 Mar 2025 09:58:00 +0300 Subject: [PATCH 0004/2947] staging: greybus: camera: fix code alignment warning Correct the alignment of the parameters to match the open parenthesis. Reported by checkpatch: CHECK: Alignment should match open parenthesis Signed-off-by: Erick Karanja Reviewed-by: Alex Elder Link: https://lore.kernel.org/r/20250322065800.21361-1-karanja99erick@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index 5d80ace41d8e..ec9fddfc0b14 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1165,8 +1165,8 @@ static int gb_camera_debugfs_init(struct gb_camera *gcam) gcam->debugfs.buffers[i].length = 0; debugfs_create_file_aux(entry->name, entry->mask, - gcam->debugfs.root, gcam, entry, - &gb_camera_debugfs_ops); + gcam->debugfs.root, gcam, entry, + &gb_camera_debugfs_ops); } return 0; From 7fc3a367b2f51004e4c0bd7b215502b7be6a042b Mon Sep 17 00:00:00 2001 From: Abraham Samuel Adekunle Date: Tue, 25 Mar 2025 14:11:04 +0100 Subject: [PATCH 0005/2947] staging: rtl8723bs: simplify if-else block by removing unnecessary braces The if-else block contained braces around single statements, which are unnecessary according to the Linux kernel coding style. Remove the redundant braces to improve code readability and maintain consistency with the rest of the codebase. Reported by checkpatch: WARNING: braces {} are not necessary for any arm of this statement Signed-off-by: Abraham Samuel Adekunle Reviewed-by: Julia Lawall Link: https://lore.kernel.org/r/Z+KraOo2DfmH5zMX@HP-650 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index 0ed420f3d096..53d4c113b19c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -988,11 +988,10 @@ void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr) if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) { addr = of_get_property(np, "local-mac-address", &len); - if (addr && len == ETH_ALEN) { + if (addr && len == ETH_ALEN) ether_addr_copy(mac_addr, addr); - } else { + else eth_random_addr(mac_addr); - } } } From f6d1d0ac1735ff4fccf84d08eadf291123b8e310 Mon Sep 17 00:00:00 2001 From: Abraham Samuel Adekunle Date: Tue, 25 Mar 2025 15:42:33 +0100 Subject: [PATCH 0006/2947] staging: rtl8723bs: remove unnecessary else block after return The else block after the return statement is unnecessary since execution does not continue past the return statement. Remove the else block while preserving logic making the code cleaner and more readable. reported by checkpatch: WARNING: else is not generally useful after a break or return Signed-off-by: Abraham Samuel Adekunle Reviewed-by: Julia Lawall Link: https://lore.kernel.org/r/Z+LA2eeFRL+K0KCy@HP-650 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 58de0c2fdd68..1d23ea7d6f59 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -2022,12 +2022,12 @@ signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, u } iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); - if (iEntry < 0) { + if (iEntry < 0) return ielength; - } else { - if (authmode == WLAN_EID_RSN) - ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); - } + + if (authmode == WLAN_EID_RSN) + ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); + return ielength; } From 9f61589a8b50715fb7c11f4d899c9689ae6674bc Mon Sep 17 00:00:00 2001 From: Abraham Samuel Adekunle Date: Wed, 26 Mar 2025 13:40:05 +0100 Subject: [PATCH 0007/2947] staging: rtl8723bs: remove braces around single statements The code contains braces around single statements in the if blocks which are unnecessary according to the Linux kernel coding style. Remove the braces to improve readability and maintain consistency. Reported by checkpatch: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Abraham Samuel Adekunle Link: https://lore.kernel.org/r/Z+P1pfLSKpiRtpaF@HP-650 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index c60e179bb2e1..74a8fcf18e84 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -56,9 +56,8 @@ int _ips_leave(struct adapter *padapter) pwrpriv->ips_leave_cnts++; result = rtw_ips_pwr_up(padapter); - if (result == _SUCCESS) { + if (result == _SUCCESS) pwrpriv->rf_pwrstate = rf_on; - } pwrpriv->bips_processing = false; pwrpriv->bkeepfwalive = false; @@ -549,9 +548,8 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter) LPS_Leave_check(Adapter); } else { - if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) ips_leave(Adapter); - } } } From d486f2e07836fd8435c2ec0512b5d81cfc00781c Mon Sep 17 00:00:00 2001 From: Erick Karanja Date: Wed, 26 Mar 2025 16:26:49 +0300 Subject: [PATCH 0008/2947] staging: rtl8723bs: Rename variables Rename the variable `mediaStatus` to `media_status` and variable `lpsVal` to `lps_val` to adhere to Linux kernel coding standards by using snake_case instead of CamelCase. Fixes checkpatch.pl warning: CHECK: Avoid CamelCase: CHECK: Avoid CamelCase: Signed-off-by: Erick Karanja Link: https://lore.kernel.org/r/20250326132649.22055-1-karanja99erick@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_btcoex.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c index d54095f50113..f4b19ef7b341 100644 --- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c +++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c @@ -8,14 +8,14 @@ #include #include -void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) +void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 media_status) { - if ((mediaStatus == RT_MEDIA_CONNECT) + if ((media_status == RT_MEDIA_CONNECT) && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) { rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); } - hal_btcoex_MediaStatusNotify(padapter, mediaStatus); + hal_btcoex_MediaStatusNotify(padapter, media_status); } void rtw_btcoex_HaltNotify(struct adapter *padapter) @@ -52,14 +52,14 @@ void rtw_btcoex_RejectApAggregatedPacket(struct adapter *padapter, u8 enable) void rtw_btcoex_LPS_Enter(struct adapter *padapter) { struct pwrctrl_priv *pwrpriv; - u8 lpsVal; + u8 lps_val; pwrpriv = adapter_to_pwrctl(padapter); pwrpriv->bpower_saving = true; - lpsVal = hal_btcoex_LpsVal(padapter); - rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); + lps_val = hal_btcoex_LpsVal(padapter); + rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lps_val, "BTCOEX"); } void rtw_btcoex_LPS_Leave(struct adapter *padapter) From fb1bf1067de979c89ae33589e0466d6ce0dde204 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 15 Mar 2025 16:43:02 +0100 Subject: [PATCH 0009/2947] rust: alloc: add missing invariant in Vec::set_len() When setting a new length, we have to justify that the set length represents the exact number of elements stored in the vector. Reviewed-by: Benno Lossin Reported-by: Alice Ryhl Closes: https://lore.kernel.org/rust-for-linux/20250311-iov-iter-v1-4-f6c9134ea824@google.com Fixes: 2aac4cd7dae3 ("rust: alloc: implement kernel `Vec` type") Link: https://lore.kernel.org/r/20250315154436.65065-2-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index ae9d072741ce..b01dabfe35aa 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -193,6 +193,9 @@ pub fn len(&self) -> usize { #[inline] pub unsafe fn set_len(&mut self, new_len: usize) { debug_assert!(new_len <= self.capacity()); + + // INVARIANT: By the safety requirements of this method `new_len` represents the exact + // number of elements stored within `self`. self.len = new_len; } From 81e1c4dab5d0c508907722f18b028102454d52e6 Mon Sep 17 00:00:00 2001 From: Andrew Ballance Date: Sun, 16 Mar 2025 06:16:42 -0500 Subject: [PATCH 0010/2947] rust: alloc: add Vec::truncate method Implement the equivalent to the std's Vec::truncate on the kernel's Vec type. Link: https://lore.kernel.org/r/20250316111644.154602-2-andrewjballance@gmail.com Signed-off-by: Andrew Ballance [ Rewrote safety comment of set_len(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index b01dabfe35aa..8fd941429d7c 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -455,6 +455,41 @@ pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocEr Ok(()) } + + /// Shortens the vector, setting the length to `len` and drops the removed values. + /// If `len` is greater than or equal to the current length, this does nothing. + /// + /// This has no effect on the capacity and will not allocate. + /// + /// # Examples + /// + /// ``` + /// let mut v = kernel::kvec![1, 2, 3]?; + /// v.truncate(1); + /// assert_eq!(v.len(), 1); + /// assert_eq!(&v, &[1]); + /// + /// # Ok::<(), Error>(()) + /// ``` + pub fn truncate(&mut self, len: usize) { + if len >= self.len() { + return; + } + + let drop_range = len..self.len(); + + // SAFETY: `drop_range` is a subrange of `[0, len)` by the bounds check above. + let ptr: *mut [T] = unsafe { self.get_unchecked_mut(drop_range) }; + + // SAFETY: By the above bounds check, it is guaranteed that `len < self.capacity()`. + unsafe { self.set_len(len) }; + + // SAFETY: + // - the dropped values are valid `T`s by the type invariant + // - we are allowed to invalidate [`new_len`, `old_len`) because we just changed the + // len, therefore we have exclusive access to [`new_len`, `old_len`) + unsafe { ptr::drop_in_place(ptr) }; + } } impl Vec { From 1679b7159379d11100e4ab7d1de23c8cd7765aa1 Mon Sep 17 00:00:00 2001 From: Andrew Ballance Date: Sun, 16 Mar 2025 06:16:43 -0500 Subject: [PATCH 0011/2947] rust: alloc: add Vec::resize method Implement the equivalent of the rust std's Vec::resize on the kernel's Vec type. Reviewed-by: Benno Lossin Reviewed-by: Tamir Duberstein Link: https://lore.kernel.org/r/20250316111644.154602-3-andrewjballance@gmail.com Signed-off-by: Andrew Ballance [ Use checked_sub(), as suggested by Tamir. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 8fd941429d7c..7ebec5c4a277 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -556,6 +556,33 @@ pub fn from_elem(value: T, n: usize, flags: Flags) -> Result { Ok(v) } + + /// Resizes the [`Vec`] so that `len` is equal to `new_len`. + /// + /// If `new_len` is smaller than `len`, the `Vec` is [`Vec::truncate`]d. + /// If `new_len` is larger, each new slot is filled with clones of `value`. + /// + /// # Examples + /// + /// ``` + /// let mut v = kernel::kvec![1, 2, 3]?; + /// v.resize(1, 42, GFP_KERNEL)?; + /// assert_eq!(&v, &[1]); + /// + /// v.resize(3, 42, GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 42, 42]); + /// + /// # Ok::<(), Error>(()) + /// ``` + pub fn resize(&mut self, new_len: usize, value: T, flags: Flags) -> Result<(), AllocError> { + match new_len.checked_sub(self.len()) { + Some(n) => self.extend_with(n, value, flags), + None => { + self.truncate(new_len); + Ok(()) + } + } + } } impl Drop for Vec From c3152988c047a7b6abb10d4dc5e24fafbabe8b7e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 18 Mar 2025 10:52:42 -0400 Subject: [PATCH 0012/2947] rust: alloc: use `spare_capacity_mut` to reduce unsafe Use `spare_capacity_mut` in the implementation of `push` to reduce the use of `unsafe`. Both methods were added in commit 2aac4cd7dae3 ("rust: alloc: implement kernel `Vec` type"). Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250318-vec-push-use-spare-v3-1-68741671d1af@gmail.com Signed-off-by: Tamir Duberstein Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 7ebec5c4a277..6ac8756989e5 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -288,15 +288,10 @@ pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { self.reserve(1, flags)?; - // SAFETY: - // - `self.len` is smaller than `self.capacity` and hence, the resulting pointer is - // guaranteed to be part of the same allocated object. - // - `self.len` can not overflow `isize`. - let ptr = unsafe { self.as_mut_ptr().add(self.len) }; + let spare = self.spare_capacity_mut(); - // SAFETY: - // - `ptr` is properly aligned and valid for writes. - unsafe { core::ptr::write(ptr, v) }; + // SAFETY: The call to `reserve` was successful so the spare capacity is at least 1. + unsafe { spare.get_unchecked_mut(0) }.write(v); // SAFETY: We just initialised the first spare entry, so it is safe to increase the length // by 1. We also know that the new length is <= capacity because of the previous call to From 9f7140bf23df90cdfd664dea0f0da7aacf8aeeb5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Mar 2025 18:22:53 +0200 Subject: [PATCH 0013/2947] iio: amplifiers: hmc425a: Remove not fully correct comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OF match table can be used outside of OF-based platforms. Remove the (misleading) comment. Signed-off-by: Andy Shevchenko Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250313162254.416422-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/amplifiers/hmc425a.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index d9a359e1388a..e92d7f399e33 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -398,7 +398,6 @@ static int hmc425a_probe(struct platform_device *pdev) return devm_iio_device_register(&pdev->dev, indio_dev); } -/* Match table for of_platform binding */ static const struct of_device_id hmc425a_of_match[] = { { .compatible = "adi,hmc425a", .data = &hmc425a_chip_info_tbl[ID_HMC425A]}, From de67f28abe586fc26711389fe80c01b658020c2c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 10 Mar 2025 15:43:04 -0500 Subject: [PATCH 0014/2947] iio: adc: ad4030: check scan_type for error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check scan_type for error ad4030_get_chan_scale(). Currently, this should never fail, but it is good practice to always check for errors in case of future changes. Calling iio_get_current_scan_type() is moved out of the if statement also to avoid potential issues with future changes instead of assuming that the non-differential case does not use extended scan_type. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202503040954.n6MhjSsV-lkp@intel.com/ Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250310-iio-adc-ad4030-check-scan-type-err-v1-1-589e4ebd9711@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4030.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index 9a020680885d..af7a817e8273 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -390,16 +390,18 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev, struct ad4030_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; + scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + if (chan->differential) { - scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); *val = (st->vref_uv * 2) / MILLI; *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; } *val = st->vref_uv / MILLI; - *val2 = chan->scan_type.realbits; + *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; } From dc78e71d7c1534293eaf6d17c5ce83e547532cf9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 10 Mar 2025 15:43:05 -0500 Subject: [PATCH 0015/2947] iio: adc: ad4030: remove some duplicate code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove some duplicate code in the ad4030_get_chan_scale() function by simplifying the if statement. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250310-iio-adc-ad4030-check-scan-type-err-v1-2-589e4ebd9711@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4030.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index af7a817e8273..f24b46164a47 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -394,14 +394,13 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev, if (IS_ERR(scan_type)) return PTR_ERR(scan_type); - if (chan->differential) { + if (chan->differential) *val = (st->vref_uv * 2) / MILLI; - *val2 = scan_type->realbits; - return IIO_VAL_FRACTIONAL_LOG2; - } + else + *val = st->vref_uv / MILLI; - *val = st->vref_uv / MILLI; *val2 = scan_type->realbits; + return IIO_VAL_FRACTIONAL_LOG2; } From efaa981e679ac0cbc8d89b69aa4595e422826329 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 10 Mar 2025 15:43:06 -0500 Subject: [PATCH 0016/2947] iio: adc: ad4030: move setting mode to update_scan_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move calling ad4030_set_mode() from the buffer preenable callback to the update_scan_mode callback. This doesn't change any functionality but is more logical since setting the mode is a function of the scan mask and doesn't require an "undo" operation when the buffer is disabled. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250310-iio-adc-ad4030-check-scan-type-err-v1-3-589e4ebd9711@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4030.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index f24b46164a47..c2117c7a296f 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -868,6 +868,12 @@ static int ad4030_get_current_scan_type(const struct iio_dev *indio_dev, return st->avg_log2 ? AD4030_SCAN_TYPE_AVG : AD4030_SCAN_TYPE_NORMAL; } +static int ad4030_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + return ad4030_set_mode(indio_dev, *scan_mask); +} + static const struct iio_info ad4030_iio_info = { .read_avail = ad4030_read_avail, .read_raw = ad4030_read_raw, @@ -875,13 +881,9 @@ static const struct iio_info ad4030_iio_info = { .debugfs_reg_access = ad4030_reg_access, .read_label = ad4030_read_label, .get_current_scan_type = ad4030_get_current_scan_type, + .update_scan_mode = ad4030_update_scan_mode, }; -static int ad4030_buffer_preenable(struct iio_dev *indio_dev) -{ - return ad4030_set_mode(indio_dev, *indio_dev->active_scan_mask); -} - static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev, const unsigned long *scan_mask) { @@ -895,7 +897,6 @@ static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev, } static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = { - .preenable = ad4030_buffer_preenable, .validate_scan_mask = ad4030_validate_scan_mask, }; From 15ffee89c7c6d8ac3509e301dd29bab687323133 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 10 Mar 2025 15:43:07 -0500 Subject: [PATCH 0017/2947] iio: adc: ad4030: don't store scan_type in state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move getting the scan_type to ad4030_conversion(). Previously, we were getting the scan_type in two other places, then storing it in the state struct before using it in ad4030_conversion(). This was a bit fragile against potential future changes since it isn't obvious that anything that could potentially change the scan_type would need to also update the state struct. Also, the non-obviousness of this led to a redundant call to iio_get_current_scan_type() in ad4030_single_conversion() since it also calls ad4030_set_mode() which in turn calls ad4030_conversion(). To simplify things, just call iio_get_current_scan_type() in ad4030_conversion() where the returned struct is actually used and don't bother storing it in the state struct. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250310-iio-adc-ad4030-check-scan-type-err-v1-4-589e4ebd9711@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4030.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index c2117c7a296f..54ad74b96c9f 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -147,7 +147,6 @@ struct ad4030_state { struct spi_device *spi; struct regmap *regmap; const struct ad4030_chip_info *chip; - const struct iio_scan_type *current_scan_type; struct gpio_desc *cnv_gpio; int vref_uv; int vio_uv; @@ -562,11 +561,6 @@ static int ad4030_set_mode(struct iio_dev *indio_dev, unsigned long mask) st->mode = AD4030_OUT_DATA_MD_DIFF; } - st->current_scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); - if (IS_ERR(st->current_scan_type)) - return PTR_ERR(st->current_scan_type); - return regmap_update_bits(st->regmap, AD4030_REG_MODES, AD4030_REG_MODES_MASK_OUT_DATA_MODE, st->mode); @@ -614,15 +608,20 @@ static void ad4030_extract_interleaved(u8 *src, u32 *ch0, u32 *ch1) static int ad4030_conversion(struct iio_dev *indio_dev) { struct ad4030_state *st = iio_priv(indio_dev); - unsigned char diff_realbytes = - BITS_TO_BYTES(st->current_scan_type->realbits); - unsigned char diff_storagebytes = - BITS_TO_BYTES(st->current_scan_type->storagebits); + const struct iio_scan_type *scan_type; + unsigned char diff_realbytes, diff_storagebytes; unsigned int bytes_to_read; unsigned long cnv_nb = BIT(st->avg_log2); unsigned int i; int ret; + scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + diff_realbytes = BITS_TO_BYTES(scan_type->realbits); + diff_storagebytes = BITS_TO_BYTES(scan_type->storagebits); + /* Number of bytes for one differential channel */ bytes_to_read = diff_realbytes; /* Add one byte if we are using a differential + common byte mode */ @@ -673,11 +672,6 @@ static int ad4030_single_conversion(struct iio_dev *indio_dev, if (ret) return ret; - st->current_scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); - if (IS_ERR(st->current_scan_type)) - return PTR_ERR(st->current_scan_type); - ret = ad4030_conversion(indio_dev); if (ret) return ret; From 9415c8b5b9b7ba927d98f80022a2890e8639e9e4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 10 Mar 2025 15:43:08 -0500 Subject: [PATCH 0018/2947] iio: adc: ad4030: explain rearranging raw sample data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a comment explaining why the raw sample data is rearranged in the in the ad4030_conversion() function. It is not so obvious from the code why this is done. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250310-iio-adc-ad4030-check-scan-type-err-v1-5-589e4ebd9711@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4030.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index 54ad74b96c9f..636f9f33e66a 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -646,6 +646,12 @@ static int ad4030_conversion(struct iio_dev *indio_dev) &st->rx_data.dual.diff[0], &st->rx_data.dual.diff[1]); + /* + * If no common mode voltage channel is enabled, we can use the raw + * data as is. Otherwise, we need to rearrange the data a bit to match + * the natural alignment of the IIO buffer. + */ + if (st->mode != AD4030_OUT_DATA_MD_16_DIFF_8_COM && st->mode != AD4030_OUT_DATA_MD_24_DIFF_8_COM) return 0; From 8f2efdbc303fe7baa83843d3290dd6ea5ba3276c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:42:56 +0100 Subject: [PATCH 0019/2947] rtc: sh: assign correct interrupts with DT The DT bindings for this driver define the interrupts in the order as they are numbered in the interrupt controller. The old platform_data, however, listed them in a different order. So, for DT based platforms, they are mixed up. Assign them specifically for DT, so we can keep the bindings stable. After the fix, 'rtctest' passes again on the Renesas Genmai board (RZ-A1 / R7S72100). Fixes: dab5aec64bf5 ("rtc: sh: add support for rza series") Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-11-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9ea40f40188f..3409f5764224 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -485,9 +485,15 @@ static int __init sh_rtc_probe(struct platform_device *pdev) return -ENOENT; } - rtc->periodic_irq = ret; - rtc->carry_irq = platform_get_irq(pdev, 1); - rtc->alarm_irq = platform_get_irq(pdev, 2); + if (!pdev->dev.of_node) { + rtc->periodic_irq = ret; + rtc->carry_irq = platform_get_irq(pdev, 1); + rtc->alarm_irq = platform_get_irq(pdev, 2); + } else { + rtc->alarm_irq = ret; + rtc->periodic_irq = platform_get_irq(pdev, 1); + rtc->carry_irq = platform_get_irq(pdev, 2); + } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) From c090d390e5ed917a7f33a35da9bd8de4b505cc8e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:42:57 +0100 Subject: [PATCH 0020/2947] rtc: sh: remove update interrupt handling Since commit e428c6a2772b ("RTC: Clean out UIE icotl implementations"), the flag for UIE cannot be set anymore. Because UIE is now handled via regular alarms and a timerqueue by the RTC core, the UIE handling code can simply go away now. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-12-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 48 +------------------------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 3409f5764224..f8227a71084a 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -75,7 +75,6 @@ /* Period Bits */ #define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */ #define PF_COUNT 0x200 /* Half periodic counter */ -#define PF_OXS 0x400 /* Periodic One x Second */ #define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */ #define PF_MASK 0xf00 @@ -107,22 +106,6 @@ struct sh_rtc { unsigned short periodic_freq; }; -static int __sh_rtc_interrupt(struct sh_rtc *rtc) -{ - unsigned int tmp, pending; - - tmp = readb(rtc->regbase + RCR1); - pending = tmp & RCR1_CF; - tmp &= ~RCR1_CF; - writeb(tmp, rtc->regbase + RCR1); - - /* Users have requested One x Second IRQ */ - if (pending && rtc->periodic_freq & PF_OXS) - rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); - - return pending; -} - static int __sh_rtc_alarm(struct sh_rtc *rtc) { unsigned int tmp, pending; @@ -162,18 +145,6 @@ static int __sh_rtc_periodic(struct sh_rtc *rtc) return pending; } -static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_interrupt(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); -} - static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) { struct sh_rtc *rtc = dev_id; @@ -204,8 +175,7 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id) int ret; spin_lock(&rtc->lock); - ret = __sh_rtc_interrupt(rtc); - ret |= __sh_rtc_alarm(rtc); + ret = __sh_rtc_alarm(rtc); ret |= __sh_rtc_periodic(rtc); spin_unlock(&rtc->lock); @@ -236,9 +206,6 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int tmp; - tmp = readb(rtc->regbase + RCR1); - seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no"); - tmp = readb(rtc->regbase + RCR2); seq_printf(seq, "periodic_IRQ\t: %s\n", (tmp & RCR2_PESMASK) ? "yes" : "no"); @@ -320,10 +287,6 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec--; #endif - /* only keep the carry interrupt enabled if UIE is on */ - if (!(rtc->periodic_freq & PF_OXS)) - sh_rtc_setcie(dev, 0); - dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, @@ -577,15 +540,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) goto err_unmap; } - ret = devm_request_irq(&pdev->dev, rtc->carry_irq, - sh_rtc_interrupt, 0, "sh-rtc carry", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request carry IRQ failed with %d, IRQ %d\n", - ret, rtc->carry_irq); - goto err_unmap; - } - ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc alarm", rtc); if (unlikely(ret)) { From fb06b6b54b33b145925e18fc2e66498cf98ed9fb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:42:58 +0100 Subject: [PATCH 0021/2947] rtc: sh: only disable carry interrupts in probe() With old, custom UIE handling removed, we can now disable the carry interrupt in probe() and leave it like this. No further handling is required. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-13-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index f8227a71084a..469806604f31 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -213,25 +213,6 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static inline void sh_rtc_setcie(struct device *dev, unsigned int enable) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - spin_lock_irq(&rtc->lock); - - tmp = readb(rtc->regbase + RCR1); - - if (!enable) - tmp &= ~RCR1_CIE; - else - tmp |= RCR1_CIE; - - writeb(tmp, rtc->regbase + RCR1); - - spin_unlock_irq(&rtc->lock); -} - static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { sh_rtc_setaie(dev, enabled); @@ -434,6 +415,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) struct resource *res; char clk_name[14]; int clk_id, ret; + unsigned int tmp; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) @@ -553,8 +535,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); /* everything disabled by default */ - sh_rtc_setaie(&pdev->dev, 0); - sh_rtc_setcie(&pdev->dev, 0); + tmp = readb(rtc->regbase + RCR1); + tmp &= ~(RCR1_CIE | RCR1_AIE); + writeb(tmp, rtc->regbase + RCR1); rtc->rtc_dev->ops = &sh_rtc_ops; rtc->rtc_dev->max_user_freq = 256; @@ -585,7 +568,6 @@ static void __exit sh_rtc_remove(struct platform_device *pdev) struct sh_rtc *rtc = platform_get_drvdata(pdev); sh_rtc_setaie(&pdev->dev, 0); - sh_rtc_setcie(&pdev->dev, 0); clk_disable(rtc->clk); } From a7e7d966ccab12110680354636a666af2c015f77 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:42:59 +0100 Subject: [PATCH 0022/2947] rtc: sh: remove periodic interrupt handling Because periodic interrupts are emulated by the RTC core, the PIE handling code can simply go away now. And with it the custom proc-file. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-14-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 69 -------------------------------------------- 1 file changed, 69 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 469806604f31..e80d4ae979c9 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -72,12 +72,6 @@ /* ALARM Bits - or with BCD encoded value */ #define AR_ENB 0x80 /* Enable for alarm cmp */ -/* Period Bits */ -#define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */ -#define PF_COUNT 0x200 /* Half periodic counter */ -#define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */ -#define PF_MASK 0xf00 - /* RCR1 Bits */ #define RCR1_CF 0x80 /* Carry Flag */ #define RCR1_CIE 0x10 /* Carry Interrupt Enable */ @@ -85,8 +79,6 @@ #define RCR1_AF 0x01 /* Alarm Flag */ /* RCR2 Bits */ -#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ -#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ #define RCR2_RTCEN 0x08 /* ENable RTC */ #define RCR2_ADJ 0x04 /* ADJustment (30-second) */ #define RCR2_RESET 0x02 /* Reset bit */ @@ -103,7 +95,6 @@ struct sh_rtc { struct rtc_device *rtc_dev; spinlock_t lock; unsigned long capabilities; /* See asm/rtc.h for cap bits */ - unsigned short periodic_freq; }; static int __sh_rtc_alarm(struct sh_rtc *rtc) @@ -121,30 +112,6 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) return pending; } -static int __sh_rtc_periodic(struct sh_rtc *rtc) -{ - unsigned int tmp, pending; - - tmp = readb(rtc->regbase + RCR2); - pending = tmp & RCR2_PEF; - tmp &= ~RCR2_PEF; - writeb(tmp, rtc->regbase + RCR2); - - if (!pending) - return 0; - - /* Half period enabled than one skipped and the next notified */ - if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) - rtc->periodic_freq &= ~PF_COUNT; - else { - if (rtc->periodic_freq & PF_HP) - rtc->periodic_freq |= PF_COUNT; - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); - } - - return pending; -} - static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) { struct sh_rtc *rtc = dev_id; @@ -157,18 +124,6 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) return IRQ_RETVAL(ret); } -static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_periodic(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); -} - static irqreturn_t sh_rtc_shared(int irq, void *dev_id) { struct sh_rtc *rtc = dev_id; @@ -176,7 +131,6 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id) spin_lock(&rtc->lock); ret = __sh_rtc_alarm(rtc); - ret |= __sh_rtc_periodic(rtc); spin_unlock(&rtc->lock); return IRQ_RETVAL(ret); @@ -201,18 +155,6 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) spin_unlock_irq(&rtc->lock); } -static int sh_rtc_proc(struct device *dev, struct seq_file *seq) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - tmp = readb(rtc->regbase + RCR2); - seq_printf(seq, "periodic_IRQ\t: %s\n", - (tmp & RCR2_PESMASK) ? "yes" : "no"); - - return 0; -} - static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { sh_rtc_setaie(dev, enabled); @@ -405,7 +347,6 @@ static const struct rtc_class_ops sh_rtc_ops = { .set_time = sh_rtc_set_time, .read_alarm = sh_rtc_read_alarm, .set_alarm = sh_rtc_set_alarm, - .proc = sh_rtc_proc, .alarm_irq_enable = sh_rtc_alarm_irq_enable, }; @@ -512,16 +453,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) goto err_unmap; } } else { - /* register periodic/carry/alarm irqs */ - ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, - sh_rtc_periodic, 0, "sh-rtc period", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request period IRQ failed with %d, IRQ %d\n", - ret, rtc->periodic_irq); - goto err_unmap; - } - ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc alarm", rtc); if (unlikely(ret)) { From 689602e0609e2209e294f213c6cb5a6798517f4d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:43:00 +0100 Subject: [PATCH 0023/2947] rtc: sh: simplify irq setup after refactoring We only need the alarm_irq handler. That means we can remove everything related to periodic_irq and carry_irq. Also, the shared handler can go since we only we need the alarm interrupt in any case. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-15-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 83 +++++++++----------------------------------- 1 file changed, 17 insertions(+), 66 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index e80d4ae979c9..bf49dbd09cab 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -89,18 +89,19 @@ struct sh_rtc { unsigned long regsize; struct resource *res; int alarm_irq; - int periodic_irq; - int carry_irq; struct clk *clk; struct rtc_device *rtc_dev; spinlock_t lock; unsigned long capabilities; /* See asm/rtc.h for cap bits */ }; -static int __sh_rtc_alarm(struct sh_rtc *rtc) +static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) { + struct sh_rtc *rtc = dev_id; unsigned int tmp, pending; + spin_lock(&rtc->lock); + tmp = readb(rtc->regbase + RCR1); pending = tmp & RCR1_AF; tmp &= ~(RCR1_AF | RCR1_AIE); @@ -109,31 +110,9 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) if (pending) rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); - return pending; -} - -static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_alarm(rtc); spin_unlock(&rtc->lock); - return IRQ_RETVAL(ret); -} - -static irqreturn_t sh_rtc_shared(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_alarm(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); + return IRQ_RETVAL(pending); } static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) @@ -364,22 +343,16 @@ static int __init sh_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); - /* get periodic/carry/alarm irqs */ ret = platform_get_irq(pdev, 0); if (unlikely(ret <= 0)) { dev_err(&pdev->dev, "No IRQ resource\n"); return -ENOENT; } - if (!pdev->dev.of_node) { - rtc->periodic_irq = ret; - rtc->carry_irq = platform_get_irq(pdev, 1); + if (!pdev->dev.of_node) rtc->alarm_irq = platform_get_irq(pdev, 2); - } else { + else rtc->alarm_irq = ret; - rtc->periodic_irq = platform_get_irq(pdev, 1); - rtc->carry_irq = platform_get_irq(pdev, 2); - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) @@ -442,25 +415,11 @@ static int __init sh_rtc_probe(struct platform_device *pdev) } #endif - if (rtc->carry_irq <= 0) { - /* register shared periodic/carry/alarm irq */ - ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, - sh_rtc_shared, 0, "sh-rtc", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request IRQ failed with %d, IRQ %d\n", ret, - rtc->periodic_irq); - goto err_unmap; - } - } else { - ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, - sh_rtc_alarm, 0, "sh-rtc alarm", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request alarm IRQ failed with %d, IRQ %d\n", - ret, rtc->alarm_irq); - goto err_unmap; - } + ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc", rtc); + if (ret) { + dev_err(&pdev->dev, "request alarm IRQ failed with %d, IRQ %d\n", + ret, rtc->alarm_irq); + goto err_unmap; } platform_set_drvdata(pdev, rtc); @@ -503,30 +462,22 @@ static void __exit sh_rtc_remove(struct platform_device *pdev) clk_disable(rtc->clk); } -static void sh_rtc_set_irq_wake(struct device *dev, int enabled) +static int __maybe_unused sh_rtc_suspend(struct device *dev) { struct sh_rtc *rtc = dev_get_drvdata(dev); - irq_set_irq_wake(rtc->periodic_irq, enabled); - - if (rtc->carry_irq > 0) { - irq_set_irq_wake(rtc->carry_irq, enabled); - irq_set_irq_wake(rtc->alarm_irq, enabled); - } -} - -static int __maybe_unused sh_rtc_suspend(struct device *dev) -{ if (device_may_wakeup(dev)) - sh_rtc_set_irq_wake(dev, 1); + irq_set_irq_wake(rtc->alarm_irq, 1); return 0; } static int __maybe_unused sh_rtc_resume(struct device *dev) { + struct sh_rtc *rtc = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) - sh_rtc_set_irq_wake(dev, 0); + irq_set_irq_wake(rtc->alarm_irq, 0); return 0; } From 33df0a509dad96046aa7f9b133495bdccf77c593 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:43:01 +0100 Subject: [PATCH 0024/2947] rtc: sh: remove useless wrapper function The wrapper to enable interrupts is so thin that we can use it directly. Also gets rid of an 'inline' which doesn't make sense here. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-16-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index bf49dbd09cab..033bdfc83e42 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -115,7 +115,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) return IRQ_RETVAL(pending); } -static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) +static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int tmp; @@ -132,11 +132,7 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) writeb(tmp, rtc->regbase + RCR1); spin_unlock_irq(&rtc->lock); -} -static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - sh_rtc_setaie(dev, enabled); return 0; } @@ -457,7 +453,7 @@ static void __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - sh_rtc_setaie(&pdev->dev, 0); + sh_rtc_alarm_irq_enable(&pdev->dev, 0); clk_disable(rtc->clk); } From ea59ad0ca975841ea490315d886a612520e9e9da Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:43:02 +0100 Subject: [PATCH 0025/2947] rtc: sh: use local variables in probe() for mapping IO No need to store the resource for the registers in the per-device struct because we only need it during probe. Remove some unneeded unlikely() while here and correct the type of 'regsize'. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-17-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 033bdfc83e42..3bafb2a0659d 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -86,8 +86,6 @@ struct sh_rtc { void __iomem *regbase; - unsigned long regsize; - struct resource *res; int alarm_irq; struct clk *clk; struct rtc_device *rtc_dev; @@ -328,10 +326,11 @@ static const struct rtc_class_ops sh_rtc_ops = { static int __init sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; - struct resource *res; + struct resource *res, *req_res; char clk_name[14]; int clk_id, ret; unsigned int tmp; + resource_size_t regsize; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) @@ -353,20 +352,18 @@ static int __init sh_rtc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(res == NULL)) { + if (!res) { dev_err(&pdev->dev, "No IO resource\n"); return -ENOENT; } - rtc->regsize = resource_size(res); - - rtc->res = devm_request_mem_region(&pdev->dev, res->start, - rtc->regsize, pdev->name); - if (unlikely(!rtc->res)) + regsize = resource_size(res); + req_res = devm_request_mem_region(&pdev->dev, res->start, regsize, pdev->name); + if (!req_res) return -EBUSY; - rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, rtc->regsize); - if (unlikely(!rtc->regbase)) + rtc->regbase = devm_ioremap(&pdev->dev, req_res->start, regsize); + if (!rtc->regbase) return -EINVAL; if (!pdev->dev.of_node) { From 8003a5585fc8466b22e000204d29cf2fa5e21e3a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 27 Feb 2025 14:43:03 +0100 Subject: [PATCH 0026/2947] rtc: sh: minor fixes to adhere to coding style Use the BIT macro, use curly braces for else-blocks, don't split strings over multiple lines, annotate the lock, update copyright. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250227134256.9167-18-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 3bafb2a0659d..f15ef3aa82a0 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -5,6 +5,7 @@ * Copyright (C) 2006 - 2009 Paul Mundt * Copyright (C) 2006 Jamie Lenehan * Copyright (C) 2008 Angelo Castello + * Copyright (C) 2025 Wolfram Sang, Renesas Electronics Corporation * * Based on the old arch/sh/kernel/cpu/rtc.c by: * @@ -31,7 +32,7 @@ /* Default values for RZ/A RTC */ #define rtc_reg_size sizeof(u16) #define RTC_BIT_INVERTED 0 /* no chip bugs */ -#define RTC_CAP_4_DIGIT_YEAR (1 << 0) +#define RTC_CAP_4_DIGIT_YEAR BIT(0) #define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR #endif @@ -70,26 +71,26 @@ */ /* ALARM Bits - or with BCD encoded value */ -#define AR_ENB 0x80 /* Enable for alarm cmp */ +#define AR_ENB BIT(7) /* Enable for alarm cmp */ /* RCR1 Bits */ -#define RCR1_CF 0x80 /* Carry Flag */ -#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ -#define RCR1_AF 0x01 /* Alarm Flag */ +#define RCR1_CF BIT(7) /* Carry Flag */ +#define RCR1_CIE BIT(4) /* Carry Interrupt Enable */ +#define RCR1_AIE BIT(3) /* Alarm Interrupt Enable */ +#define RCR1_AF BIT(0) /* Alarm Flag */ /* RCR2 Bits */ -#define RCR2_RTCEN 0x08 /* ENable RTC */ -#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ -#define RCR2_RESET 0x02 /* Reset bit */ -#define RCR2_START 0x01 /* Start bit */ +#define RCR2_RTCEN BIT(3) /* ENable RTC */ +#define RCR2_ADJ BIT(2) /* ADJustment (30-second) */ +#define RCR2_RESET BIT(1) /* Reset bit */ +#define RCR2_START BIT(0) /* Start bit */ struct sh_rtc { void __iomem *regbase; int alarm_irq; struct clk *clk; struct rtc_device *rtc_dev; - spinlock_t lock; + spinlock_t lock; /* protecting register access */ unsigned long capabilities; /* See asm/rtc.h for cap bits */ }; @@ -183,10 +184,8 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec--; #endif - dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); return 0; @@ -373,8 +372,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev) clk_id = 0; snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id); - } else + } else { snprintf(clk_name, sizeof(clk_name), "fck"); + } rtc->clk = devm_clk_get(&pdev->dev, clk_name); if (IS_ERR(rtc->clk)) { @@ -501,8 +501,8 @@ static struct platform_driver sh_rtc_platform_driver __refdata = { module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe); MODULE_DESCRIPTION("SuperH on-chip RTC driver"); -MODULE_AUTHOR("Paul Mundt , " - "Jamie Lenehan , " - "Angelo Castello "); +MODULE_AUTHOR("Paul Mundt "); +MODULE_AUTHOR("Jamie Lenehan "); +MODULE_AUTHOR("Angelo Castello "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); From 0bddd060a6a3a10e6ebd386cc4d9a897e8a60861 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 12 Mar 2025 11:00:00 +0100 Subject: [PATCH 0027/2947] rtc: rzn1: clear interrupts on remove It is good practice to clear running interrupts before removing the driver. This is not really a bugfix because on current systems RuntimePM will disable the module clock, so interrupts won't be initiated. The dependency on that behaviour is subtle, though. Better be self-contained and clean up when removing. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250312100105.36767-2-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rzn1.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index eeb9612a666f..3c2861983ff1 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -444,6 +444,11 @@ static int rzn1_rtc_probe(struct platform_device *pdev) static void rzn1_rtc_remove(struct platform_device *pdev) { + struct rzn1_rtc *rtc = platform_get_drvdata(pdev); + + /* Disable all interrupts */ + writel(0, rtc->base + RZN1_RTC_CTL1); + pm_runtime_put(&pdev->dev); } From d370586746466166a57b709bfce8301f2adf97a0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 20 Mar 2025 11:18:49 +0100 Subject: [PATCH 0028/2947] rtc: da9063: simplify irq management The code for enabling and disabling the irq is so similar that it can easily be handled by one function. Like in most other RTC drivers. Save the duplicated code and one layer of indirection. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250320102218.10781-2-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-da9063.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 859397541f29..d05b8be98087 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -194,26 +194,17 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data, config->rtc_count_year_mask; } -static int da9063_rtc_stop_alarm(struct device *dev) +static int da9063_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) { struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); const struct da9063_compatible_rtc_regmap *config = rtc->config; + u8 set_bit = enabled ? config->rtc_alarm_on_mask : 0; return regmap_update_bits(rtc->regmap, config->rtc_alarm_year_reg, config->rtc_alarm_on_mask, - 0); -} - -static int da9063_rtc_start_alarm(struct device *dev) -{ - struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); - const struct da9063_compatible_rtc_regmap *config = rtc->config; - - return regmap_update_bits(rtc->regmap, - config->rtc_alarm_year_reg, - config->rtc_alarm_on_mask, - config->rtc_alarm_on_mask); + set_bit); } static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -312,7 +303,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) da9063_tm_to_data(&alrm->time, data, rtc); - ret = da9063_rtc_stop_alarm(dev); + ret = da9063_rtc_alarm_irq_enable(dev, 0); if (ret < 0) { dev_err(dev, "Failed to stop alarm: %d\n", ret); return ret; @@ -330,7 +321,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) da9063_data_to_tm(data, &rtc->alarm_time, rtc); if (alrm->enabled) { - ret = da9063_rtc_start_alarm(dev); + ret = da9063_rtc_alarm_irq_enable(dev, 1); if (ret < 0) { dev_err(dev, "Failed to start alarm: %d\n", ret); return ret; @@ -340,15 +331,6 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int da9063_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) -{ - if (enabled) - return da9063_rtc_start_alarm(dev); - else - return da9063_rtc_stop_alarm(dev); -} - static irqreturn_t da9063_alarm_event(int irq, void *data) { struct da9063_compatible_rtc *rtc = data; From ebf7547fd1df2db32b83de6f341c7bd9f0e98200 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 27 Mar 2025 12:07:07 +0100 Subject: [PATCH 0029/2947] mtip32xx: Remove unnecessary pcim_iounmap_regions() calls pcim_iounmap_regions() is deprecated. Moreover, it is not necessary to call it in the driver's remove() function or if probe() fails, since it does cleanup automatically on driver detach. Remove all calls to pcim_iounmap_regions(). Signed-off-by: Philipp Stanner Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko Acked-by: Jens Axboe Acked-by: Mark Brown Link: https://patch.msgid.link/20250327110707.20025-3-phasta@kernel.org --- drivers/block/mtip32xx/mtip32xx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 0d619df03fa9..66ce6b81c7d9 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3717,7 +3717,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rv) { dev_warn(&pdev->dev, "64-bit DMA enable failed\n"); - goto setmask_err; + goto iomap_err; } /* Copy the info we may need later into the private data structure. */ @@ -3733,7 +3733,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, if (!dd->isr_workq) { dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance); rv = -ENOMEM; - goto setmask_err; + goto iomap_err; } memset(cpu_list, 0, sizeof(cpu_list)); @@ -3830,8 +3830,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, drop_cpu(dd->work[1].cpu_binding); drop_cpu(dd->work[2].cpu_binding); } -setmask_err: - pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); iomap_err: kfree(dd); @@ -3907,7 +3905,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) pci_disable_msi(pdev); - pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); pci_set_drvdata(pdev, NULL); put_disk(dd->disk); From 855c634930f04c21434fae9c41a7a7372b6ac879 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 27 Mar 2025 12:07:08 +0100 Subject: [PATCH 0030/2947] PCI: Remove pcim_iounmap_regions() All users of the deprecated function pcim_iounmap_regions() have been ported by now. Remove it. Signed-off-by: Philipp Stanner Signed-off-by: Bjorn Helgaas Reviewed-by: Zijun Hu Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250327110707.20025-4-phasta@kernel.org --- .../driver-api/driver-model/devres.rst | 1 - drivers/pci/devres.c | 24 ------------------- include/linux/pci.h | 1 - 3 files changed, 26 deletions(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index d75728eb05f8..601f1a74d34d 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -396,7 +396,6 @@ PCI pcim_iomap_regions() : do request_region() and iomap() on multiple BARs pcim_iomap_table() : array of mapped addresses indexed by BAR pcim_iounmap() : do iounmap() on a single BAR - pcim_iounmap_regions() : do iounmap() and release_region() on multiple BARs pcim_pin_device() : keep PCI device enabled after release pcim_set_mwi() : enable Memory-Write-Invalidate PCI transaction diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 73047316889e..0317c56ac27d 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -955,30 +955,6 @@ int pcim_request_all_regions(struct pci_dev *pdev, const char *name) } EXPORT_SYMBOL(pcim_request_all_regions); -/** - * pcim_iounmap_regions - Unmap and release PCI BARs (DEPRECATED) - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to unmap and release - * - * Unmap and release regions specified by @mask. - * - * This function is DEPRECATED. Do not use it in new code. - * Use pcim_iounmap_region() instead. - */ -void pcim_iounmap_regions(struct pci_dev *pdev, int mask) -{ - int i; - - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - if (!mask_contains_bar(mask, i)) - continue; - - pcim_iounmap_region(pdev, i); - pcim_remove_bar_from_legacy_table(pdev, i); - } -} -EXPORT_SYMBOL(pcim_iounmap_regions); - /** * pcim_iomap_range - Create a ranged __iomap mapping within a PCI BAR * @pdev: PCI device to map IO resources for diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..a60fdb344d9e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2322,7 +2322,6 @@ void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); void __iomem * const *pcim_iomap_table(struct pci_dev *pdev); int pcim_request_region(struct pci_dev *pdev, int bar, const char *name); int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name); -void pcim_iounmap_regions(struct pci_dev *pdev, int mask); void __iomem *pcim_iomap_range(struct pci_dev *pdev, int bar, unsigned long offset, unsigned long len); From 1490cbb9dbfd0eabfe45f9b674097aea7e6760fc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Mar 2025 16:54:51 +0200 Subject: [PATCH 0031/2947] device property: Split fwnode_get_child_node_count() The new helper is introduced to allow counting the child firmware nodes of their parent without requiring a device to be passed. This also makes the fwnode and device property API more symmetrical with the rest. Signed-off-by: Andy Shevchenko Acked-by: "Rafael J. Wysocki" Reviewed-by: Sakari Ailus Reviewed-by: Heikki Krogerus Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20250310150835.3139322-2-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones --- drivers/base/property.c | 12 ++++++------ include/linux/property.h | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/base/property.c b/drivers/base/property.c index c1392743df9c..805f75b35115 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -928,22 +928,22 @@ bool fwnode_device_is_available(const struct fwnode_handle *fwnode) EXPORT_SYMBOL_GPL(fwnode_device_is_available); /** - * device_get_child_node_count - return the number of child nodes for device - * @dev: Device to count the child nodes for + * fwnode_get_child_node_count - return the number of child nodes for a given firmware node + * @fwnode: Pointer to the parent firmware node * - * Return: the number of child nodes for a given device. + * Return: the number of child nodes for a given firmware node. */ -unsigned int device_get_child_node_count(const struct device *dev) +unsigned int fwnode_get_child_node_count(const struct fwnode_handle *fwnode) { struct fwnode_handle *child; unsigned int count = 0; - device_for_each_child_node(dev, child) + fwnode_for_each_child_node(fwnode, child) count++; return count; } -EXPORT_SYMBOL_GPL(device_get_child_node_count); +EXPORT_SYMBOL_GPL(fwnode_get_child_node_count); bool device_dma_supported(const struct device *dev) { diff --git a/include/linux/property.h b/include/linux/property.h index e214ecd241eb..bc5bfc98176b 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -208,7 +208,12 @@ DEFINE_FREE(fwnode_handle, struct fwnode_handle *, fwnode_handle_put(_T)) int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index); int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name); -unsigned int device_get_child_node_count(const struct device *dev); +unsigned int fwnode_get_child_node_count(const struct fwnode_handle *fwnode); + +static inline unsigned int device_get_child_node_count(const struct device *dev) +{ + return fwnode_get_child_node_count(dev_fwnode(dev)); +} static inline int device_property_read_u8(const struct device *dev, const char *propname, u8 *val) From 4623cc4e9a5f1b7ad7e6599dfc2a5a4d9d4f5d72 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Mar 2025 16:54:52 +0200 Subject: [PATCH 0032/2947] leds: pwm-multicolor: Use fwnode_get_child_node_count() Since fwnode_get_child_node_count() was split from its device property counterpart, we may utilise it in the driver and drop custom implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20250310150835.3139322-3-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-pwm-multicolor.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c index 1c7705bafdfc..e0d7d3c9215c 100644 --- a/drivers/leds/rgb/leds-pwm-multicolor.c +++ b/drivers/leds/rgb/leds-pwm-multicolor.c @@ -107,12 +107,12 @@ static int iterate_subleds(struct device *dev, struct pwm_mc_led *priv, static int led_pwm_mc_probe(struct platform_device *pdev) { - struct fwnode_handle *mcnode, *fwnode; + struct fwnode_handle *mcnode; struct led_init_data init_data = {}; struct led_classdev *cdev; struct mc_subled *subled; struct pwm_mc_led *priv; - int count = 0; + unsigned int count; int ret = 0; mcnode = device_get_named_child_node(&pdev->dev, "multi-led"); @@ -121,8 +121,7 @@ static int led_pwm_mc_probe(struct platform_device *pdev) "expected multi-led node\n"); /* count the nodes inside the multi-led node */ - fwnode_for_each_child_node(mcnode, fwnode) - count++; + count = fwnode_get_child_node_count(mcnode); priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count), GFP_KERNEL); From 53762bb44b0659e79a3e3177372e823ec4afcc8a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Mar 2025 16:54:53 +0200 Subject: [PATCH 0033/2947] leds: ncp5623: Use fwnode_get_child_node_count() Since fwnode_get_child_node_count() was split from its device property counterpart, we may utilise it in the driver and drop custom implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20250310150835.3139322-4-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-ncp5623.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/leds/rgb/leds-ncp5623.c b/drivers/leds/rgb/leds-ncp5623.c index f18156683375..7c7d44623a9e 100644 --- a/drivers/leds/rgb/leds-ncp5623.c +++ b/drivers/leds/rgb/leds-ncp5623.c @@ -155,9 +155,9 @@ static int ncp5623_probe(struct i2c_client *client) struct device *dev = &client->dev; struct fwnode_handle *mc_node, *led_node; struct led_init_data init_data = { }; - int num_subleds = 0; struct ncp5623 *ncp; struct mc_subled *subled_info; + unsigned int num_subleds; u32 color_index; u32 reg; int ret; @@ -172,8 +172,7 @@ static int ncp5623_probe(struct i2c_client *client) if (!mc_node) return -EINVAL; - fwnode_for_each_child_node(mc_node, led_node) - num_subleds++; + num_subleds = fwnode_get_child_node_count(mc_node); subled_info = devm_kcalloc(dev, num_subleds, sizeof(*subled_info), GFP_KERNEL); if (!subled_info) { From 08ca89e98620c08d68b7e7aed6c9294698e214e1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Mar 2025 16:54:54 +0200 Subject: [PATCH 0034/2947] usb: typec: tcpm: Use fwnode_get_child_node_count() Since fwnode_get_child_node_count() was split from its device property counterpart, we may utilise it in the driver and drop custom implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Acked-by: Kyle Tso Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20250310150835.3139322-5-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones --- drivers/usb/typec/tcpm/tcpm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a99db4e025cd..f967ba8e0b63 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7166,7 +7166,7 @@ static void tcpm_fw_get_timings(struct tcpm_port *port, struct fwnode_handle *fw static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { - struct fwnode_handle *capabilities, *child, *caps = NULL; + struct fwnode_handle *capabilities, *caps = NULL; unsigned int nr_src_pdo, nr_snk_pdo; const char *opmode_str; u32 *src_pdo, *snk_pdo; @@ -7232,9 +7232,7 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode if (!capabilities) { port->pd_count = 1; } else { - fwnode_for_each_child_node(capabilities, child) - port->pd_count++; - + port->pd_count = fwnode_get_child_node_count(capabilities); if (!port->pd_count) { ret = -ENODATA; goto put_capabilities; From 93e41f968d7c6ea1cedc6b365917cbb787ef08f6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:54 +0100 Subject: [PATCH 0035/2947] fbdev: Rework fb_blank() Reimplement fb_blank() to return early on errors. No functional changes. Prepares the helper for tracking the blanking state in struct fb_info. Signed-off-by: Thomas Zimmermann Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-2-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/core/fbmem.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 3c568cff2913..39e2b81473ad 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -339,11 +339,13 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) } EXPORT_SYMBOL(fb_set_var); -int -fb_blank(struct fb_info *info, int blank) +int fb_blank(struct fb_info *info, int blank) { struct fb_event event; - int ret = -EINVAL; + int ret; + + if (!info->fbops->fb_blank) + return -EINVAL; if (blank > FB_BLANK_POWERDOWN) blank = FB_BLANK_POWERDOWN; @@ -351,13 +353,13 @@ fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ - if (info->fbops->fb_blank) - ret = info->fbops->fb_blank(blank, info); + ret = info->fbops->fb_blank(blank, info); + if (ret) + return ret; - if (!ret) - fb_notifier_call_chain(FB_EVENT_BLANK, &event); + fb_notifier_call_chain(FB_EVENT_BLANK, &event); - return ret; + return 0; } EXPORT_SYMBOL(fb_blank); From 7e3711eb87c584ed224a7ad7000eba36e6fa3a51 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:55 +0100 Subject: [PATCH 0036/2947] fbdev: Track display blanking state Store the display's blank status in struct fb_info.blank and track it in fb_blank(). As an extra, the status is now available from the sysfs blank attribute. Support for blanking is optional. Therefore framebuffer_alloc() initializes the state to FB_BLANK_UNBLANK (i.e., the display is on). If the fb_blank callback has been set, register_framebuffer() sets the state to FB_BLANK_POWERDOWN. On the first modeset, the call to fb_blank() will update it to _UNBLANK. This is important, as listeners to FB_EVENT_BLANK will now see the display being switched on. Signed-off-by: Thomas Zimmermann Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-3-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/core/fb_info.c | 1 + drivers/video/fbdev/core/fbmem.c | 17 ++++++++++++++++- drivers/video/fbdev/core/fbsysfs.c | 8 ++++---- include/linux/fb.h | 2 ++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/core/fb_info.c b/drivers/video/fbdev/core/fb_info.c index 4847ebe50d7d..52f9bd2c5417 100644 --- a/drivers/video/fbdev/core/fb_info.c +++ b/drivers/video/fbdev/core/fb_info.c @@ -42,6 +42,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) info->device = dev; info->fbcon_rotate_hint = -1; + info->blank = FB_BLANK_UNBLANK; #if IS_ENABLED(CONFIG_FB_BACKLIGHT) mutex_init(&info->bl_curve_mutex); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 39e2b81473ad..5d1529d300b7 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -341,6 +341,7 @@ EXPORT_SYMBOL(fb_set_var); int fb_blank(struct fb_info *info, int blank) { + int old_blank = info->blank; struct fb_event event; int ret; @@ -353,13 +354,19 @@ int fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ + info->blank = blank; + ret = info->fbops->fb_blank(blank, info); if (ret) - return ret; + goto err; fb_notifier_call_chain(FB_EVENT_BLANK, &event); return 0; + +err: + info->blank = old_blank; + return ret; } EXPORT_SYMBOL(fb_blank); @@ -408,6 +415,14 @@ static int do_register_framebuffer(struct fb_info *fb_info) mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); + /* + * With an fb_blank callback present, we assume that the + * display is blank, so that fb_blank() enables it on the + * first modeset. + */ + if (fb_info->fbops->fb_blank) + fb_info->blank = FB_BLANK_POWERDOWN; + fb_device_create(fb_info); if (fb_info->pixmap.addr == NULL) { diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 06d75c767579..b8344c40073b 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -242,11 +242,11 @@ static ssize_t store_blank(struct device *device, return count; } -static ssize_t show_blank(struct device *device, - struct device_attribute *attr, char *buf) +static ssize_t show_blank(struct device *device, struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = dev_get_drvdata(device); - return 0; + struct fb_info *fb_info = dev_get_drvdata(device); + + return sysfs_emit(buf, "%d\n", fb_info->blank); } static ssize_t store_console(struct device *device, diff --git a/include/linux/fb.h b/include/linux/fb.h index cd653862ab99..348aa2e146e2 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -472,6 +472,8 @@ struct fb_info { struct list_head modelist; /* mode list */ struct fb_videomode *mode; /* current mode */ + int blank; /* current blanking; see FB_BLANK_ constants */ + #if IS_ENABLED(CONFIG_FB_BACKLIGHT) /* assigned backlight device */ /* set before framebuffer registration, From dfb4bf1ac40162ff5ea3715a10f6af2dcf3030c5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:56 +0100 Subject: [PATCH 0037/2947] fbdev: Send old blank state in FB_EVENT_BLANK The event FB_EVENT_BLANK sends the new blank state in the event's data field. Also send the old state. It's an additional field in the data array; existing receivers won't notice the difference. The backlight subsystem currently tracks blank state per display per backlight. That is not optimal as it ties backlight code to fbdev. A subsystem should not track internal state of another subsystem. With both, new and old, blank state in FB_EVENT_BLANK, the backlight code will not require its own state tracker any longer. Signed-off-by: Thomas Zimmermann Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-4-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/core/fbmem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 5d1529d300b7..9650b641d8e8 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -343,6 +343,7 @@ int fb_blank(struct fb_info *info, int blank) { int old_blank = info->blank; struct fb_event event; + int data[2]; int ret; if (!info->fbops->fb_blank) @@ -351,8 +352,10 @@ int fb_blank(struct fb_info *info, int blank) if (blank > FB_BLANK_POWERDOWN) blank = FB_BLANK_POWERDOWN; + data[0] = blank; + data[1] = old_blank; event.info = info; - event.data = ␣ + event.data = data; info->blank = blank; From 726491f2038ec71122d45700f3abf36fdb277aaa Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:57 +0100 Subject: [PATCH 0038/2947] backlight: Implement fbdev tracking with blank state from event Look at the blank state provided by FB_EVENT_BLANK to determine whether to enable or disable a backlight. Remove the tracking fields from struct backlight_device. Tracking requires three variables, fb_on, prev_fb_on and the backlight's use_count. If fb_on is true, the display has been unblanked. The backlight needs to be enabled if the display was blanked before (i.e., prev_fb_on is false) or if use_count is still at 0. If fb_on is false, the display has been blanked. In this case, the backlight has to be disabled was unblanked before and the backlight's use_count is greater than 0. This change removes fbdev state tracking from blacklight. All the backlight requires it its own use counter and information about changes to the display. Removing fbdev internals makes backlight drivers easier to integrate into other display drivers, such as DRM. Signed-off-by: Thomas Zimmermann Reviewed-by: "Daniel Thompson (RISCstar)" Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-5-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 14 +++++++------- include/linux/backlight.h | 10 +--------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index f699e5827ccb..bb01f57c4683 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -98,9 +98,9 @@ static int fb_notifier_callback(struct notifier_block *self, struct backlight_device *bd; struct fb_event *evdata = data; struct fb_info *info = evdata->info; + const int *fb_blank = evdata->data; struct backlight_device *fb_bd = fb_bl_device(info); - int node = info->node; - int fb_blank = 0; + bool fb_on, prev_fb_on; /* If we aren't interested in this event, skip it immediately ... */ if (event != FB_EVENT_BLANK) @@ -116,15 +116,15 @@ static int fb_notifier_callback(struct notifier_block *self, if (fb_bd && fb_bd != bd) goto out; - fb_blank = *(int *)evdata->data; - if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) { - bd->fb_bl_on[node] = true; + fb_on = fb_blank[0] == FB_BLANK_UNBLANK; + prev_fb_on = fb_blank[1] == FB_BLANK_UNBLANK; + + if (fb_on && (!prev_fb_on || !bd->use_count)) { if (!bd->use_count++) { bd->props.state &= ~BL_CORE_FBBLANK; backlight_update_status(bd); } - } else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) { - bd->fb_bl_on[node] = false; + } else if (!fb_on && prev_fb_on && bd->use_count) { if (!(--bd->use_count)) { bd->props.state |= BL_CORE_FBBLANK; backlight_update_status(bd); diff --git a/include/linux/backlight.h b/include/linux/backlight.h index f5652e5a9060..03723a5478f8 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -294,15 +294,7 @@ struct backlight_device { struct device dev; /** - * @fb_bl_on: The state of individual fbdev's. - * - * Multiple fbdev's may share one backlight device. The fb_bl_on - * records the state of the individual fbdev. - */ - bool fb_bl_on[FB_MAX]; - - /** - * @use_count: The number of uses of fb_bl_on. + * @use_count: The number of unblanked displays. */ int use_count; }; From 4bfb77f3381627640e97e0e423c93a2ea93e7de7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:58 +0100 Subject: [PATCH 0039/2947] backlight: Move blank-state handling into helper Move the handling of blank-state updates into a separate helper, so that is can be called without the fbdev event. No functional changes. As a minor improvement over the original code, the update replaces manual locking with a guard. Signed-off-by: Thomas Zimmermann Reviewed-by: "Daniel Thompson (RISCstar)" Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-6-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 46 +++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index bb01f57c4683..1c43f579396f 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -80,6 +80,30 @@ static const char *const backlight_scale_types[] = { #if defined(CONFIG_FB_CORE) || (defined(CONFIG_FB_CORE_MODULE) && \ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) +static void backlight_notify_blank(struct backlight_device *bd, + struct device *display_dev, + bool fb_on, bool prev_fb_on) +{ + guard(mutex)(&bd->ops_lock); + + if (!bd->ops) + return; + if (bd->ops->controls_device && !bd->ops->controls_device(bd, display_dev)) + return; + + if (fb_on && (!prev_fb_on || !bd->use_count)) { + if (!bd->use_count++) { + bd->props.state &= ~BL_CORE_FBBLANK; + backlight_update_status(bd); + } + } else if (!fb_on && prev_fb_on && bd->use_count) { + if (!(--bd->use_count)) { + bd->props.state |= BL_CORE_FBBLANK; + backlight_update_status(bd); + } + } +} + /* * fb_notifier_callback * @@ -107,31 +131,15 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); - mutex_lock(&bd->ops_lock); - if (!bd->ops) - goto out; - if (bd->ops->controls_device && !bd->ops->controls_device(bd, info->device)) - goto out; if (fb_bd && fb_bd != bd) - goto out; + return 0; fb_on = fb_blank[0] == FB_BLANK_UNBLANK; prev_fb_on = fb_blank[1] == FB_BLANK_UNBLANK; - if (fb_on && (!prev_fb_on || !bd->use_count)) { - if (!bd->use_count++) { - bd->props.state &= ~BL_CORE_FBBLANK; - backlight_update_status(bd); - } - } else if (!fb_on && prev_fb_on && bd->use_count) { - if (!(--bd->use_count)) { - bd->props.state |= BL_CORE_FBBLANK; - backlight_update_status(bd); - } - } -out: - mutex_unlock(&bd->ops_lock); + backlight_notify_blank(bd, info->device, fb_on, prev_fb_on); + return 0; } From b01beb2f1f6bcda17634a5b529865ffc5a9b795f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:53:59 +0100 Subject: [PATCH 0040/2947] backlight: Replace fb events with a dedicated function call Remove support for fb events from backlight subsystem. Provide the helper backlight_notify_blank_all() instead. Also export the existing helper backlight_notify_blank() to update a single backlight device. In fbdev, call either helper to inform the backlight subsystem of changes to a display's blank state. If the framebuffer device has a specific backlight, only update this one; otherwise update all. v4: - protect blacklight declarations with IS_REACHABLE() (kernel test robot) v3: - declare empty fb_bl_notify_blank() as static inline (kernel test robot) Signed-off-by: Thomas Zimmermann Acked-by: Simona Vetter Reviewed-by: "Daniel Thompson (RISCstar)" Link: https://lore.kernel.org/r/20250321095517.313713-7-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 85 ++++--------------------- drivers/video/fbdev/core/fb_backlight.c | 12 ++++ drivers/video/fbdev/core/fbmem.c | 2 + include/linux/backlight.h | 22 +++++-- include/linux/fb.h | 4 ++ 5 files changed, 46 insertions(+), 79 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 1c43f579396f..9dc93c5e480b 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #ifdef CONFIG_PMAC_BACKLIGHT @@ -57,10 +56,10 @@ * a hot-key to adjust backlight, the driver must notify the backlight * core that brightness has changed using backlight_force_update(). * - * The backlight driver core receives notifications from fbdev and - * if the event is FB_EVENT_BLANK and if the value of blank, from the - * FBIOBLANK ioctrl, results in a change in the backlight state the - * update_status() operation is called. + * Display drives can control the backlight device's status using + * backlight_notify_blank() and backlight_notify_blank_all(). If this + * results in a change in the backlight state the functions call the + * update_status() operation. */ static struct list_head backlight_dev_list; @@ -78,11 +77,8 @@ static const char *const backlight_scale_types[] = { [BACKLIGHT_SCALE_NON_LINEAR] = "non-linear", }; -#if defined(CONFIG_FB_CORE) || (defined(CONFIG_FB_CORE_MODULE) && \ - defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) -static void backlight_notify_blank(struct backlight_device *bd, - struct device *display_dev, - bool fb_on, bool prev_fb_on) +void backlight_notify_blank(struct backlight_device *bd, struct device *display_dev, + bool fb_on, bool prev_fb_on) { guard(mutex)(&bd->ops_lock); @@ -103,68 +99,18 @@ static void backlight_notify_blank(struct backlight_device *bd, } } } +EXPORT_SYMBOL(backlight_notify_blank); -/* - * fb_notifier_callback - * - * This callback gets called when something important happens inside a - * framebuffer driver. The backlight core only cares about FB_BLANK_UNBLANK - * which is reported to the driver using backlight_update_status() - * as a state change. - * - * There may be several fbdev's connected to the backlight device, - * in which case they are kept track of. A state change is only reported - * if there is a change in backlight for the specified fbdev. - */ -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) +void backlight_notify_blank_all(struct device *display_dev, bool fb_on, bool prev_fb_on) { struct backlight_device *bd; - struct fb_event *evdata = data; - struct fb_info *info = evdata->info; - const int *fb_blank = evdata->data; - struct backlight_device *fb_bd = fb_bl_device(info); - bool fb_on, prev_fb_on; - /* If we aren't interested in this event, skip it immediately ... */ - if (event != FB_EVENT_BLANK) - return 0; + guard(mutex)(&backlight_dev_list_mutex); - bd = container_of(self, struct backlight_device, fb_notif); - - if (fb_bd && fb_bd != bd) - return 0; - - fb_on = fb_blank[0] == FB_BLANK_UNBLANK; - prev_fb_on = fb_blank[1] == FB_BLANK_UNBLANK; - - backlight_notify_blank(bd, info->device, fb_on, prev_fb_on); - - return 0; + list_for_each_entry(bd, &backlight_dev_list, entry) + backlight_notify_blank(bd, display_dev, fb_on, prev_fb_on); } - -static int backlight_register_fb(struct backlight_device *bd) -{ - memset(&bd->fb_notif, 0, sizeof(bd->fb_notif)); - bd->fb_notif.notifier_call = fb_notifier_callback; - - return fb_register_client(&bd->fb_notif); -} - -static void backlight_unregister_fb(struct backlight_device *bd) -{ - fb_unregister_client(&bd->fb_notif); -} -#else -static inline int backlight_register_fb(struct backlight_device *bd) -{ - return 0; -} - -static inline void backlight_unregister_fb(struct backlight_device *bd) -{ -} -#endif /* CONFIG_FB_CORE */ +EXPORT_SYMBOL(backlight_notify_blank_all); static void backlight_generate_event(struct backlight_device *bd, enum backlight_update_reason reason) @@ -455,12 +401,6 @@ struct backlight_device *backlight_device_register(const char *name, return ERR_PTR(rc); } - rc = backlight_register_fb(new_bd); - if (rc) { - device_unregister(&new_bd->dev); - return ERR_PTR(rc); - } - new_bd->ops = ops; #ifdef CONFIG_PMAC_BACKLIGHT @@ -547,7 +487,6 @@ void backlight_device_unregister(struct backlight_device *bd) bd->ops = NULL; mutex_unlock(&bd->ops_lock); - backlight_unregister_fb(bd); device_unregister(&bd->dev); } EXPORT_SYMBOL(backlight_device_unregister); diff --git a/drivers/video/fbdev/core/fb_backlight.c b/drivers/video/fbdev/core/fb_backlight.c index 6fdaa9f81be9..dbed9696f4c5 100644 --- a/drivers/video/fbdev/core/fb_backlight.c +++ b/drivers/video/fbdev/core/fb_backlight.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -36,4 +37,15 @@ struct backlight_device *fb_bl_device(struct fb_info *info) return info->bl_dev; } EXPORT_SYMBOL(fb_bl_device); + +void fb_bl_notify_blank(struct fb_info *info, int old_blank) +{ + bool on = info->blank == FB_BLANK_UNBLANK; + bool prev_on = old_blank == FB_BLANK_UNBLANK; + + if (info->bl_dev) + backlight_notify_blank(info->bl_dev, info->device, on, prev_on); + else + backlight_notify_blank_all(info->device, on, prev_on); +} #endif diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 9650b641d8e8..c931f270ac34 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -363,6 +363,8 @@ int fb_blank(struct fb_info *info, int blank) if (ret) goto err; + fb_bl_notify_blank(info, old_blank); + fb_notifier_call_chain(FB_EVENT_BLANK, &event); return 0; diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 03723a5478f8..10e626db7eee 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -12,7 +12,6 @@ #include #include #include -#include #include /** @@ -278,11 +277,6 @@ struct backlight_device { */ const struct backlight_ops *ops; - /** - * @fb_notif: The framebuffer notifier block - */ - struct notifier_block fb_notif; - /** * @entry: List entry of all registered backlight devices */ @@ -400,6 +394,22 @@ struct backlight_device *backlight_device_get_by_type(enum backlight_type type); int backlight_device_set_brightness(struct backlight_device *bd, unsigned long brightness); +#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) +void backlight_notify_blank(struct backlight_device *bd, + struct device *display_dev, + bool fb_on, bool prev_fb_on); +void backlight_notify_blank_all(struct device *display_dev, + bool fb_on, bool prev_fb_on); +#else +static inline void backlight_notify_blank(struct backlight_device *bd, + struct device *display_dev, + bool fb_on, bool prev_fb_on) +{ } +static inline void backlight_notify_blank_all(struct device *display_dev, + bool fb_on, bool prev_fb_on) +{ } +#endif + #define to_backlight_device(obj) container_of(obj, struct backlight_device, dev) /** diff --git a/include/linux/fb.h b/include/linux/fb.h index 348aa2e146e2..835e13d6eba8 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -758,11 +758,15 @@ extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) #if IS_ENABLED(CONFIG_FB_BACKLIGHT) struct backlight_device *fb_bl_device(struct fb_info *info); +void fb_bl_notify_blank(struct fb_info *info, int old_blank); #else static inline struct backlight_device *fb_bl_device(struct fb_info *info) { return NULL; } + +static inline void fb_bl_notify_blank(struct fb_info *info, int old_blank) +{ } #endif static inline struct lcd_device *fb_lcd_device(struct fb_info *info) From e98696cea7e289447a5d2328546b947629301616 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:54:00 +0100 Subject: [PATCH 0041/2947] backlight: lcd: Move event handling into helpers Move the handling of display updates to separate helper functions. There is code for handling fbdev blank events and fbdev mode changes. The code currently runs from fbdev event notifiers, which will be replaced. Signed-off-by: Thomas Zimmermann Reviewed-by: "Daniel Thompson (RISCstar)" Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250321095517.313713-8-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/lcd.c | 38 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 3267acf8dc5b..f57ff8bcc2fa 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -18,6 +18,32 @@ #include #include +static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, + int power) +{ + guard(mutex)(&ld->ops_lock); + + if (!ld->ops || !ld->ops->set_power) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; + + ld->ops->set_power(ld, power); +} + +static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev, + unsigned int width, unsigned int height) +{ + guard(mutex)(&ld->ops_lock); + + if (!ld->ops || !ld->ops->set_mode) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; + + ld->ops->set_mode(ld, width, height); +} + #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) static int to_lcd_power(int fb_blank) @@ -50,25 +76,17 @@ static int fb_notifier_callback(struct notifier_block *self, struct fb_info *info = evdata->info; struct lcd_device *fb_lcd = fb_lcd_device(info); - guard(mutex)(&ld->ops_lock); - - if (!ld->ops) - return 0; - if (ld->ops->controls_device && !ld->ops->controls_device(ld, info->device)) - return 0; if (fb_lcd && fb_lcd != ld) return 0; if (event == FB_EVENT_BLANK) { int power = to_lcd_power(*(int *)evdata->data); - if (ld->ops->set_power) - ld->ops->set_power(ld, power); + lcd_notify_blank(ld, info->device, power); } else { const struct fb_videomode *videomode = evdata->data; - if (ld->ops->set_mode) - ld->ops->set_mode(ld, videomode->xres, videomode->yres); + lcd_notify_mode_change(ld, info->device, videomode->xres, videomode->yres); } return 0; From bc70cc84f5a2ebfd7e7112e9b8837e0c7954fc65 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 21 Mar 2025 10:54:01 +0100 Subject: [PATCH 0042/2947] backlight: lcd: Replace fb events with a dedicated function call Remove support for fb events from the lcd subsystem. Provide the helper lcd_notify_blank_all() instead. In fbdev, call lcd_notify_blank_all() to inform the lcd subsystem of changes to a display's blank state. Fbdev maintains a list of all installed notifiers. Instead of fbdev notifiers, maintain an internal list of lcd devices. v3: - export lcd_notify_mode_change_all() (kernel test robot) v2: - maintain global list of lcd devices - avoid IS_REACHABLE() in source file - use lock guards - initialize lcd list and list mutex Signed-off-by: Thomas Zimmermann Acked-by: Simona Vetter Reviewed-by: "Daniel Thompson (RISCstar)" Link: https://lore.kernel.org/r/20250321095517.313713-9-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/lcd.c | 102 +++++++++---------------------- drivers/video/fbdev/core/fbmem.c | 39 ++++++++++-- include/linux/lcd.h | 21 ++++++- 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index f57ff8bcc2fa..affe5c52471a 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -15,9 +15,11 @@ #include #include #include -#include #include +static DEFINE_MUTEX(lcd_dev_list_mutex); +static LIST_HEAD(lcd_dev_list); + static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, int power) { @@ -31,6 +33,17 @@ static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, ld->ops->set_power(ld, power); } +void lcd_notify_blank_all(struct device *display_dev, int power) +{ + struct lcd_device *ld; + + guard(mutex)(&lcd_dev_list_mutex); + + list_for_each_entry(ld, &lcd_dev_list, entry) + lcd_notify_blank(ld, display_dev, power); +} +EXPORT_SYMBOL(lcd_notify_blank_all); + static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev, unsigned int width, unsigned int height) { @@ -44,75 +57,17 @@ static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display ld->ops->set_mode(ld, width, height); } -#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ - defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) -static int to_lcd_power(int fb_blank) +void lcd_notify_mode_change_all(struct device *display_dev, + unsigned int width, unsigned int height) { - switch (fb_blank) { - case FB_BLANK_UNBLANK: - return LCD_POWER_ON; - /* deprecated; TODO: should become 'off' */ - case FB_BLANK_NORMAL: - return LCD_POWER_REDUCED; - case FB_BLANK_VSYNC_SUSPEND: - return LCD_POWER_REDUCED_VSYNC_SUSPEND; - /* 'off' */ - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - default: - return LCD_POWER_OFF; - } + struct lcd_device *ld; + + guard(mutex)(&lcd_dev_list_mutex); + + list_for_each_entry(ld, &lcd_dev_list, entry) + lcd_notify_mode_change(ld, display_dev, width, height); } - -/* This callback gets called when something important happens inside a - * framebuffer driver. We're looking if that important event is blanking, - * and if it is, we're switching lcd power as well ... - */ -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) -{ - struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif); - struct fb_event *evdata = data; - struct fb_info *info = evdata->info; - struct lcd_device *fb_lcd = fb_lcd_device(info); - - if (fb_lcd && fb_lcd != ld) - return 0; - - if (event == FB_EVENT_BLANK) { - int power = to_lcd_power(*(int *)evdata->data); - - lcd_notify_blank(ld, info->device, power); - } else { - const struct fb_videomode *videomode = evdata->data; - - lcd_notify_mode_change(ld, info->device, videomode->xres, videomode->yres); - } - - return 0; -} - -static int lcd_register_fb(struct lcd_device *ld) -{ - memset(&ld->fb_notif, 0, sizeof(ld->fb_notif)); - ld->fb_notif.notifier_call = fb_notifier_callback; - return fb_register_client(&ld->fb_notif); -} - -static void lcd_unregister_fb(struct lcd_device *ld) -{ - fb_unregister_client(&ld->fb_notif); -} -#else -static int lcd_register_fb(struct lcd_device *ld) -{ - return 0; -} - -static inline void lcd_unregister_fb(struct lcd_device *ld) -{ -} -#endif /* CONFIG_FB */ +EXPORT_SYMBOL(lcd_notify_mode_change_all); static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -263,11 +218,8 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent, return ERR_PTR(rc); } - rc = lcd_register_fb(new_ld); - if (rc) { - device_unregister(&new_ld->dev); - return ERR_PTR(rc); - } + guard(mutex)(&lcd_dev_list_mutex); + list_add(&new_ld->entry, &lcd_dev_list); return new_ld; } @@ -284,10 +236,12 @@ void lcd_device_unregister(struct lcd_device *ld) if (!ld) return; + guard(mutex)(&lcd_dev_list_mutex); + list_del(&ld->entry); + mutex_lock(&ld->ops_lock); ld->ops = NULL; mutex_unlock(&ld->ops_lock); - lcd_unregister_fb(ld); device_unregister(&ld->dev); } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index c931f270ac34..001662c606d7 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -15,6 +15,7 @@ #include #include #include +#include #include