From: Grant Peltier grantpeltier93@gmail.com
[ Upstream commit 51fb91ed5a6fa855a74731610cd5435d83d6e17f ]
Per the RAA228228 datasheet, READ_TEMPERATURE_1 is not a supported PMBus command.
Signed-off-by: Grant Peltier grantpeltier93@gmail.com Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/pmbus/isl68137.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 0c622711ef7e0..58aa95a3c010c 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -67,6 +67,7 @@ enum variants { raa_dmpvr1_2rail, raa_dmpvr2_1rail, raa_dmpvr2_2rail, + raa_dmpvr2_2rail_nontc, raa_dmpvr2_3rail, raa_dmpvr2_hv, }; @@ -241,6 +242,10 @@ static int isl68137_probe(struct i2c_client *client, info->pages = 1; info->read_word_data = raa_dmpvr2_read_word_data; break; + case raa_dmpvr2_2rail_nontc: + info->func[0] &= ~PMBUS_HAVE_TEMP; + info->func[1] &= ~PMBUS_HAVE_TEMP; + fallthrough; case raa_dmpvr2_2rail: info->pages = 2; info->read_word_data = raa_dmpvr2_read_word_data; @@ -304,7 +309,7 @@ static const struct i2c_device_id raa_dmpvr_id[] = { {"raa228000", raa_dmpvr2_hv}, {"raa228004", raa_dmpvr2_hv}, {"raa228006", raa_dmpvr2_hv}, - {"raa228228", raa_dmpvr2_2rail}, + {"raa228228", raa_dmpvr2_2rail_nontc}, {"raa229001", raa_dmpvr2_2rail}, {"raa229004", raa_dmpvr2_2rail}, {}
From: Sebastian Parschauer s.parschauer@gmx.de
[ Upstream commit 627a49975bdc3220f360a8237603a6344ee6a588 ]
The PixArt OEM mice are known for disconnecting every minute in runlevel 1 or 3 if they are not always polled. One Lenovo PixArt mouse is already fixed. Got two references for 17ef:602e and three references for 17ef:6019 misbehaving like this. Got one direct bug report for 17ef:6093 from Wyatt Ward (wyatt8740). So add HID_QUIRK_ALWAYS_POLL for all of them.
Link: https://github.com/sriemer/fix-linux-mouse issue 22 Signed-off-by: Sebastian Parschauer s.parschauer@gmx.de Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-quirks.c | 3 +++ 2 files changed, 6 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6f370e020feb3..1f42318a137fb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -727,6 +727,9 @@ #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093
#define USB_VENDOR_ID_LG 0x1fd2 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 934fc0a798d4d..87b57514b92e1 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -105,6 +105,9 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
From: Peilin Ye yepeilin.cs@gmail.com
[ Upstream commit 25a097f5204675550afb879ee18238ca917cba7a ]
`uref->usage_index` is not always being properly checked, causing hiddev_ioctl_usage() to go out of bounds under some cases. Fix it.
Reported-by: syzbot+34ee1b45d88571c2fa8b@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?id=f2aebe90b8c56806b050a20b36f51ed6acabe80... Reviewed-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Peilin Ye yepeilin.cs@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/usbhid/hiddev.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 4140dea693e90..4f97e6c120595 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -519,12 +519,16 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
switch (cmd) { case HIDIOCGUSAGE: + if (uref->usage_index >= field->report_count) + goto inval; uref->value = field->value[uref->usage_index]; if (copy_to_user(user_arg, uref, sizeof(*uref))) goto fault; goto goodreturn;
case HIDIOCSUSAGE: + if (uref->usage_index >= field->report_count) + goto inval; field->value[uref->usage_index] = uref->value; goto goodreturn;
From: Kalyan Thota kalyan_t@codeaurora.org
[ Upstream commit ccc862b957c6413b008fbe458034372847992d7f ]
In TEST_ONLY commit, rm global_state will duplicate the object and request for new reservations, once they pass then the new state will be swapped with the old and will be available for the Atomic Commit.
This patch fixes some of missing links in the resource reservation sequence mentioned above.
1) Creation of duplicate state in test_only commit (Rob) 2) Allocate and release the resources on every modeset. 3) Avoid allocation only when active is false.
In a modeset operation, swap state happens well before disable. Hence clearing reservations in disable will cause failures in modeset enable.
Allow reservations to be cleared/allocated before swap, such that only newly committed resources are pushed to HW.
Changes in v1: - Move the rm release to atomic_check. - Ensure resource allocation and free happens when active is not changed i.e only when mode is changed.(Rob)
Changes in v2: - Handle dpu_kms_get_global_state API failure as it may return EDEADLK (swboyd).
Signed-off-by: Kalyan Thota kalyan_t@codeaurora.org Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 0946a86b37b28..c0cd936314e66 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -586,7 +586,10 @@ static int dpu_encoder_virt_atomic_check( dpu_kms = to_dpu_kms(priv->kms); mode = &crtc_state->mode; adj_mode = &crtc_state->adjusted_mode; - global_state = dpu_kms_get_existing_global_state(dpu_kms); + global_state = dpu_kms_get_global_state(crtc_state->state); + if (IS_ERR(global_state)) + return PTR_ERR(global_state); + trace_dpu_enc_atomic_check(DRMID(drm_enc));
/* @@ -621,12 +624,15 @@ static int dpu_encoder_virt_atomic_check( /* Reserve dynamic resources now. */ if (!ret) { /* - * Avoid reserving resources when mode set is pending. Topology - * info may not be available to complete reservation. + * Release and Allocate resources on every modeset + * Dont allocate when active is false. */ if (drm_atomic_crtc_needs_modeset(crtc_state)) { - ret = dpu_rm_reserve(&dpu_kms->rm, global_state, - drm_enc, crtc_state, topology); + dpu_rm_release(global_state, drm_enc); + + if (!crtc_state->active_changed || crtc_state->active) + ret = dpu_rm_reserve(&dpu_kms->rm, global_state, + drm_enc, crtc_state, topology); } }
@@ -1175,7 +1181,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) struct dpu_encoder_virt *dpu_enc = NULL; struct msm_drm_private *priv; struct dpu_kms *dpu_kms; - struct dpu_global_state *global_state; int i = 0;
if (!drm_enc) { @@ -1194,7 +1199,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); - global_state = dpu_kms_get_existing_global_state(dpu_kms);
trace_dpu_enc_disable(DRMID(drm_enc));
@@ -1224,8 +1228,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n");
- dpu_rm_release(global_state, drm_enc); - mutex_unlock(&dpu_enc->enc_lock); }
From: Kalyan Thota kalyan_t@codeaurora.org
[ Upstream commit 4c978caf08aa155bdeadd9e2d4b026d4ce97ebd0 ]
Plane validation uses an API drm_calc_scale which will return src/dst value as a scale ratio.
when viewing the range on a scale the values should fall in as
Upscale ratio < Unity scale < Downscale ratio for src/dst formula
Fix the min and max scale ratios to suit the API accordingly.
Signed-off-by: Kalyan Thota kalyan_t@codeaurora.org Tested-by: Kristian H. Kristensen hoegsberg@google.com Reviewed-by: Kristian H. Kristensen hoegsberg@google.com Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 3b9c33e694bf4..994d23bad3870 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -866,9 +866,9 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
- min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxdwnscale); + min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxupscale); ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, - pdpu->pipe_sblk->maxupscale << 16, + pdpu->pipe_sblk->maxdwnscale << 16, true, true); if (ret) { DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
From: Rob Clark robdclark@chromium.org
[ Upstream commit 35c719da95c0d28560bff7bafeaf07ebb212665e ]
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c:817 dpu_crtc_enable() error: uninitialized symbol 'request_bandwidth'.
Reported-by: kernel test robot lkp@intel.com Signed-off-by: Rob Clark robdclark@chromium.org Reviewed-by: Sean Paul seanpaul@chromium.org Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 969d95aa873c4..1026e1e5bec10 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -827,7 +827,7 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, { struct dpu_crtc *dpu_crtc; struct drm_encoder *encoder; - bool request_bandwidth; + bool request_bandwidth = false;
if (!crtc) { DPU_ERROR("invalid crtc\n");
From: Samuel Thibault samuel.thibault@ens-lyon.org
[ Upstream commit 2b86d9b8ec6efb86fc5ea44f2d49b1df17f699a1 ]
This was missed while introducing the tty-based serial access.
The only remaining use of wait_for_xmitr with tty-based access is in spk_synth_is_alive_restart to check whether the synth can be restarted. With tty-based this is up to the tty layer to cope with the buffering etc. so we can just say yes.
Signed-off-by: Samuel Thibault samuel.thibault@ens-lyon.org Link: https://lore.kernel.org/r/20200804160637.x3iycau5izywbgzl@function Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/staging/speakup/serialio.c | 8 +++++--- drivers/staging/speakup/spk_priv.h | 1 - drivers/staging/speakup/spk_ttyio.c | 7 +++++++ drivers/staging/speakup/spk_types.h | 1 + drivers/staging/speakup/synth.c | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c index 177a2988641c1..403b01d66367e 100644 --- a/drivers/staging/speakup/serialio.c +++ b/drivers/staging/speakup/serialio.c @@ -32,6 +32,7 @@ static void spk_serial_tiocmset(unsigned int set, unsigned int clear); static unsigned char spk_serial_in(void); static unsigned char spk_serial_in_nowait(void); static void spk_serial_flush_buffer(void); +static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth);
struct spk_io_ops spk_serial_io_ops = { .synth_out = spk_serial_out, @@ -40,6 +41,7 @@ struct spk_io_ops spk_serial_io_ops = { .synth_in = spk_serial_in, .synth_in_nowait = spk_serial_in_nowait, .flush_buffer = spk_serial_flush_buffer, + .wait_for_xmitr = spk_serial_wait_for_xmitr, }; EXPORT_SYMBOL_GPL(spk_serial_io_ops);
@@ -211,7 +213,7 @@ void spk_stop_serial_interrupt(void) } EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt);
-int spk_wait_for_xmitr(struct spk_synth *in_synth) +static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth) { int tmout = SPK_XMITR_TIMEOUT;
@@ -280,7 +282,7 @@ static void spk_serial_flush_buffer(void)
static int spk_serial_out(struct spk_synth *in_synth, const char ch) { - if (in_synth->alive && spk_wait_for_xmitr(in_synth)) { + if (in_synth->alive && spk_serial_wait_for_xmitr(in_synth)) { outb_p(ch, speakup_info.port_tts); return 1; } @@ -295,7 +297,7 @@ const char *spk_serial_synth_immediate(struct spk_synth *synth, while ((ch = *buff)) { if (ch == '\n') ch = synth->procspeech; - if (spk_wait_for_xmitr(synth)) + if (spk_serial_wait_for_xmitr(synth)) outb(ch, speakup_info.port_tts); else return buff; diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h index c75b408387947..0f4bcbe5ddb93 100644 --- a/drivers/staging/speakup/spk_priv.h +++ b/drivers/staging/speakup/spk_priv.h @@ -34,7 +34,6 @@
const struct old_serial_port *spk_serial_init(int index); void spk_stop_serial_interrupt(void); -int spk_wait_for_xmitr(struct spk_synth *in_synth); void spk_serial_release(void); void spk_ttyio_release(void); void spk_ttyio_register_ldisc(void); diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c index 9b95f77f92657..a831ff64f8ba5 100644 --- a/drivers/staging/speakup/spk_ttyio.c +++ b/drivers/staging/speakup/spk_ttyio.c @@ -116,6 +116,7 @@ static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear); static unsigned char spk_ttyio_in(void); static unsigned char spk_ttyio_in_nowait(void); static void spk_ttyio_flush_buffer(void); +static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
struct spk_io_ops spk_ttyio_ops = { .synth_out = spk_ttyio_out, @@ -125,6 +126,7 @@ struct spk_io_ops spk_ttyio_ops = { .synth_in = spk_ttyio_in, .synth_in_nowait = spk_ttyio_in_nowait, .flush_buffer = spk_ttyio_flush_buffer, + .wait_for_xmitr = spk_ttyio_wait_for_xmitr, }; EXPORT_SYMBOL_GPL(spk_ttyio_ops);
@@ -286,6 +288,11 @@ static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear) mutex_unlock(&speakup_tty_mutex); }
+static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth) +{ + return 1; +} + static unsigned char ttyio_in(int timeout) { struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data; diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h index d3272c6d199aa..7398f1196e103 100644 --- a/drivers/staging/speakup/spk_types.h +++ b/drivers/staging/speakup/spk_types.h @@ -158,6 +158,7 @@ struct spk_io_ops { unsigned char (*synth_in)(void); unsigned char (*synth_in_nowait)(void); void (*flush_buffer)(void); + int (*wait_for_xmitr)(struct spk_synth *synth); };
struct spk_synth { diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index 3568bfb89912c..ac47dbac72075 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -159,7 +159,7 @@ int spk_synth_is_alive_restart(struct spk_synth *synth) { if (synth->alive) return 1; - if (spk_wait_for_xmitr(synth) > 0) { + if (synth->io_ops->wait_for_xmitr(synth) > 0) { /* restart */ synth->alive = 1; synth_printf("%s", synth->init);
On Mon, Aug 31, 2020 at 11:28:59AM -0400, Sasha Levin wrote:
From: Samuel Thibault samuel.thibault@ens-lyon.org
[ Upstream commit 2b86d9b8ec6efb86fc5ea44f2d49b1df17f699a1 ]
This was missed while introducing the tty-based serial access.
The only remaining use of wait_for_xmitr with tty-based access is in spk_synth_is_alive_restart to check whether the synth can be restarted. With tty-based this is up to the tty layer to cope with the buffering etc. so we can just say yes.
Signed-off-by: Samuel Thibault samuel.thibault@ens-lyon.org Link: https://lore.kernel.org/r/20200804160637.x3iycau5izywbgzl@function Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org
drivers/staging/speakup/serialio.c | 8 +++++--- drivers/staging/speakup/spk_priv.h | 1 - drivers/staging/speakup/spk_ttyio.c | 7 +++++++ drivers/staging/speakup/spk_types.h | 1 + drivers/staging/speakup/synth.c | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-)
Not needed for 5.8 or older, sorry, this was a 5.9-rc1+ issue only.
thanks,
greg k-h
On Mon, Aug 31, 2020 at 05:33:45PM +0200, Greg Kroah-Hartman wrote:
On Mon, Aug 31, 2020 at 11:28:59AM -0400, Sasha Levin wrote:
From: Samuel Thibault samuel.thibault@ens-lyon.org
[ Upstream commit 2b86d9b8ec6efb86fc5ea44f2d49b1df17f699a1 ]
This was missed while introducing the tty-based serial access.
The only remaining use of wait_for_xmitr with tty-based access is in spk_synth_is_alive_restart to check whether the synth can be restarted. With tty-based this is up to the tty layer to cope with the buffering etc. so we can just say yes.
Signed-off-by: Samuel Thibault samuel.thibault@ens-lyon.org Link: https://lore.kernel.org/r/20200804160637.x3iycau5izywbgzl@function Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org
drivers/staging/speakup/serialio.c | 8 +++++--- drivers/staging/speakup/spk_priv.h | 1 - drivers/staging/speakup/spk_ttyio.c | 7 +++++++ drivers/staging/speakup/spk_types.h | 1 + drivers/staging/speakup/synth.c | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-)
Not needed for 5.8 or older, sorry, this was a 5.9-rc1+ issue only.
Dropped, thanks!
From: John Stultz john.stultz@linaro.org
[ Upstream commit 975efc66d4e654207c17f939eb737ac591ac38fe ]
When booting with heavily modularized config, the serial console may not be able to load until after init when modules that satisfy needed dependencies have time to load.
Unfortunately, as qcom_geni_console_setup is marked as __init, the function may have been freed before we get to run it, causing boot time crashes such as:
[ 6.469057] Unable to handle kernel paging request at virtual address ffffffe645d4e6cc [ 6.481623] Mem abort info: [ 6.484466] ESR = 0x86000007 [ 6.487557] EC = 0x21: IABT (current EL), IL = 32 bits [ 6.492929] SET = 0, FnV = 0g [ 6.496016] EA = 0, S1PTW = 0 [ 6.499202] swapper pgtable: 4k pages, 39-bit VAs, pgdp=000000008151e000 [ 6.501286] ufshcd-qcom 1d84000.ufshc: ufshcd_print_pwr_info:[RX, TX]: gear=[3, 3], lane[2, 2], pwr[FAST MODE, FAST MODE], rate = 2 [ 6.505977] [ffffffe645d4e6cc] pgd=000000017df9f003, p4d=000000017df9f003, pud=000000017df9f003, pmd=000000017df9c003, pte=0000000000000000 [ 6.505990] Internal error: Oops: 86000007 [#1] PREEMPT SMP [ 6.505995] Modules linked in: zl10353 zl10039 zl10036 zd1301_demod xc5000 xc4000 ves1x93 ves1820 tuner_xc2028 tuner_simple tuner_types tua9001 tua6100 1 [ 6.506152] isl6405 [ 6.518104] ufshcd-qcom 1d84000.ufshc: ufshcd_find_max_sup_active_icc_level: Regulator capability was not set, actvIccLevel=0 [ 6.530549] horus3a helene fc2580 fc0013 fc0012 fc0011 ec100 e4000 dvb_pll ds3000 drxk drxd drx39xyj dib9000 dib8000 dib7000p dib7000m dib3000mc dibx003 [ 6.624271] CPU: 7 PID: 148 Comm: kworker/7:2 Tainted: G W 5.8.0-mainline-12021-g6defd37ba1cd #3455 [ 6.624273] Hardware name: Thundercomm Dragonboard 845c (DT) [ 6.624290] Workqueue: events deferred_probe_work_func [ 6.624296] pstate: 40c00005 (nZcv daif +PAN +UAO BTYPE=--) [ 6.624307] pc : qcom_geni_console_setup+0x0/0x110 [ 6.624316] lr : try_enable_new_console+0xa0/0x140 [ 6.624318] sp : ffffffc010843a30 [ 6.624320] x29: ffffffc010843a30 x28: ffffffe645c3e7d0 [ 6.624325] x27: ffffff80f8022180 x26: ffffffc010843b28 [ 6.637937] x25: 0000000000000000 x24: ffffffe6462a2000 [ 6.637941] x23: ffffffe646398000 x22: 0000000000000000 [ 6.637945] x21: 0000000000000000 x20: ffffffe6462a5ce8 [ 6.637952] x19: ffffffe646398e38 x18: ffffffffffffffff [ 6.680296] x17: 0000000000000000 x16: ffffffe64492b900 [ 6.680300] x15: ffffffe6461e9d08 x14: 69202930203d2064 [ 6.680305] x13: 7561625f65736162 x12: 202c363331203d20 [ 6.696434] x11: 0000000000000030 x10: 0101010101010101 [ 6.696438] x9 : 4d4d20746120304d x8 : 7f7f7f7f7f7f7f7f [ 6.707249] x7 : feff4c524c787373 x6 : 0000000000008080 [ 6.707253] x5 : 0000000000000000 x4 : 8080000000000000 [ 6.707257] x3 : 0000000000000000 x2 : ffffffe645d4e6cc [ 6.744223] qcom_geni_serial 898000.serial: dev_pm_opp_set_rate: failed to find OPP for freq 102400000 (-34) [ 6.744966] x1 : fffffffefe74e174 x0 : ffffffe6462a5ce8 [ 6.753580] qcom_geni_serial 898000.serial: dev_pm_opp_set_rate: failed to find OPP for freq 102400000 (-34) [ 6.761634] Call trace: [ 6.761639] qcom_geni_console_setup+0x0/0x110 [ 6.761645] register_console+0x29c/0x2f8 [ 6.767981] Bluetooth: hci0: Frame reassembly failed (-84) [ 6.775252] uart_add_one_port+0x438/0x500 [ 6.775258] qcom_geni_serial_probe+0x2c4/0x4a8 [ 6.775266] platform_drv_probe+0x58/0xa8 [ 6.855359] really_probe+0xec/0x398 [ 6.855362] driver_probe_device+0x5c/0xb8 [ 6.855367] __device_attach_driver+0x98/0xb8 [ 7.184945] bus_for_each_drv+0x74/0xd8 [ 7.188825] __device_attach+0xec/0x148 [ 7.192705] device_initial_probe+0x24/0x30 [ 7.196937] bus_probe_device+0x9c/0xa8 [ 7.200816] deferred_probe_work_func+0x7c/0xb8 [ 7.205398] process_one_work+0x20c/0x4b0 [ 7.209456] worker_thread+0x48/0x460 [ 7.213157] kthread+0x14c/0x158 [ 7.216432] ret_from_fork+0x10/0x18 [ 7.220049] Code: bad PC value [ 7.223139] ---[ end trace 73f3b21e251d5a70 ]---
Thus this patch removes the __init avoiding crash in such configs.
Cc: Andy Gross agross@kernel.org Cc: Jiri Slaby jirislaby@kernel.org Cc: Saravana Kannan saravanak@google.com Cc: Todd Kjos tkjos@google.com Cc: Amit Pundir amit.pundir@linaro.org Cc: linux-arm-msm@vger.kernel.org Cc: linux-serial@vger.kernel.org Suggested-by: Saravana Kannan saravanak@google.com Signed-off-by: John Stultz john.stultz@linaro.org Reviewed-by: Bjorn Andersson bjorn.andersson@linaro.org Link: https://lore.kernel.org/r/20200811025044.70626-1-john.stultz@linaro.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/tty/serial/qcom_geni_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 457c0bf8cbf83..ffdf6da016c21 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1047,7 +1047,7 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) }
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE -static int __init qcom_geni_console_setup(struct console *co, char *options) +static int qcom_geni_console_setup(struct console *co, char *options) { struct uart_port *uport; struct qcom_geni_serial_port *port;
From: Krishna Manikandan mkrishn@codeaurora.org
[ Upstream commit 9d5cbf5fe46e350715389d89d0c350d83289a102 ]
Define shutdown callback for display drm driver, so as to disable all the CRTCS when shutdown notification is received by the driver.
This change will turn off the timing engine so that no display transactions are requested while mmu translations are getting disabled during reboot sequence.
Signed-off-by: Krishna Manikandan mkrishn@codeaurora.org
Changes in v2: - Remove NULL check from msm_pdev_shutdown (Stephen Boyd) - Change commit text to reflect when this issue was uncovered (Sai Prakash Ranjan)
Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/msm_drv.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f6ce40bf36998..b4d61af7a104e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1328,6 +1328,13 @@ static int msm_pdev_remove(struct platform_device *pdev) return 0; }
+static void msm_pdev_shutdown(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + + drm_atomic_helper_shutdown(drm); +} + static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 }, { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, @@ -1340,6 +1347,7 @@ MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, .remove = msm_pdev_remove, + .shutdown = msm_pdev_shutdown, .driver = { .name = "msm", .of_match_table = dt_match,
From: Tom Rix trix@redhat.com
[ Upstream commit cecf7560f00a8419396a2ed0f6e5d245ccb4feac ]
clang static analysis reports this representative problem
applesmc.c:758:10: warning: 1st function call argument is an uninitialized value left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
buffer is filled by the earlier call
ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, ...
This problem is reported because a goto skips the status check. Other similar problems use data from applesmc_read_key before checking the status. So move the checks to before the use.
Signed-off-by: Tom Rix trix@redhat.com Reviewed-by: Henrik Rydberg rydberg@bitmath.org Link: https://lore.kernel.org/r/20200820131932.10590-1-trix@redhat.com Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/applesmc.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 3166184093157..a18887990f4a2 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -753,15 +753,18 @@ static ssize_t applesmc_light_show(struct device *dev, }
ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length); + if (ret) + goto out; /* newer macbooks report a single 10-bit bigendian value */ if (data_length == 10) { left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2; goto out; } left = buffer[2]; + + ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length); if (ret) goto out; - ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length); right = buffer[2];
out: @@ -810,12 +813,11 @@ static ssize_t applesmc_show_fan_speed(struct device *dev, to_index(attr));
ret = applesmc_read_key(newkey, buffer, 2); - speed = ((buffer[0] << 8 | buffer[1]) >> 2); - if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed); + + speed = ((buffer[0] << 8 | buffer[1]) >> 2); + return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed); }
static ssize_t applesmc_store_fan_speed(struct device *dev, @@ -851,12 +853,11 @@ static ssize_t applesmc_show_fan_manual(struct device *dev, u8 buffer[2];
ret = applesmc_read_key(FANS_MANUAL, buffer, 2); - manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01; - if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual); + + manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01; + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual); }
static ssize_t applesmc_store_fan_manual(struct device *dev, @@ -872,10 +873,11 @@ static ssize_t applesmc_store_fan_manual(struct device *dev, return -EINVAL;
ret = applesmc_read_key(FANS_MANUAL, buffer, 2); - val = (buffer[0] << 8 | buffer[1]); if (ret) goto out;
+ val = (buffer[0] << 8 | buffer[1]); + if (input) val = val | (0x01 << to_index(attr)); else @@ -951,13 +953,12 @@ static ssize_t applesmc_key_count_show(struct device *dev, u32 count;
ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4); - count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) + - ((u32)buffer[2]<<8) + buffer[3]; - if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count); + + count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) + + ((u32)buffer[2]<<8) + buffer[3]; + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count); }
static ssize_t applesmc_key_at_index_read_show(struct device *dev,
From: Keith Busch kbusch@kernel.org
[ Upstream commit c41ad98bebb8f4f0335b3c50dbb7583a6149dce4 ]
Zoned block devices reuse the chunk_sectors queue limit to define zone boundaries. If a such a device happens to also report an optimal boundary, do not use that to define the chunk_sectors as that may intermittently interfere with io splitting and zone size queries.
Signed-off-by: Keith Busch kbusch@kernel.org Signed-off-by: Sagi Grimberg sagi@grimberg.me Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/nvme/host/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f38548e6d55ec..6ea0bab621df3 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1975,7 +1975,7 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) } }
- if (iob) + if (iob && !blk_queue_is_zoned(ns->queue)) blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(iob)); nvme_update_disk_info(disk, ns, id); #ifdef CONFIG_NVME_MULTIPATH
On Mon, Aug 31, 2020 at 11:29:03AM -0400, Sasha Levin wrote:
From: Keith Busch kbusch@kernel.org
[ Upstream commit c41ad98bebb8f4f0335b3c50dbb7583a6149dce4 ]
Zoned block devices reuse the chunk_sectors queue limit to define zone boundaries. If a such a device happens to also report an optimal boundary, do not use that to define the chunk_sectors as that may intermittently interfere with io splitting and zone size queries.
Signed-off-by: Keith Busch kbusch@kernel.org Signed-off-by: Sagi Grimberg sagi@grimberg.me Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org
You can safely drop this from stable: nvme zoned devices were only introduced to linux in 5.9.
On Mon, Aug 31, 2020 at 09:38:18AM -0600, Keith Busch wrote:
On Mon, Aug 31, 2020 at 11:29:03AM -0400, Sasha Levin wrote:
From: Keith Busch kbusch@kernel.org
[ Upstream commit c41ad98bebb8f4f0335b3c50dbb7583a6149dce4 ]
Zoned block devices reuse the chunk_sectors queue limit to define zone boundaries. If a such a device happens to also report an optimal boundary, do not use that to define the chunk_sectors as that may intermittently interfere with io splitting and zone size queries.
Signed-off-by: Keith Busch kbusch@kernel.org Signed-off-by: Sagi Grimberg sagi@grimberg.me Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org
You can safely drop this from stable: nvme zoned devices were only introduced to linux in 5.9.
Dropped, thanks!
From: Amit Engel amit.engel@dell.com
[ Upstream commit 0d3b6a8d213a30387b5104b2fb25376d18636f23 ]
Based on nvme spec, when keep alive timeout is set to zero the keep-alive timer should be disabled.
Signed-off-by: Amit Engel amit.engel@dell.com Signed-off-by: Sagi Grimberg sagi@grimberg.me Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/nvme/target/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 6e2f623e472e9..58b035cc67a01 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -396,6 +396,9 @@ static void nvmet_keep_alive_timer(struct work_struct *work)
static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl) { + if (unlikely(ctrl->kato == 0)) + return; + pr_debug("ctrl %d start keep-alive timer for %d secs\n", ctrl->cntlid, ctrl->kato);
@@ -405,6 +408,9 @@ static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
static void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl) { + if (unlikely(ctrl->kato == 0)) + return; + pr_debug("ctrl %d stop keep-alive\n", ctrl->cntlid);
cancel_delayed_work_sync(&ctrl->ka_work);
From: Rob Clark robdclark@chromium.org
[ Upstream commit 43906812eaab06423f56af5cca9a9fcdbb4ac454 ]
This has roughly the same effect as drm_atomic_helper_wait_for_vblanks(), basically just ensuring that vblank accounting is enabled so that we get valid timestamp/seqn on pageflip events.
Signed-off-by: Rob Clark robdclark@chromium.org Tested-by: Stephen Boyd swboyd@chromium.org Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/msm_atomic.c | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 5ccfad794c6a5..561bfa48841c3 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -27,6 +27,34 @@ int msm_atomic_prepare_fb(struct drm_plane *plane, return msm_framebuffer_prepare(new_state->fb, kms->aspace); }
+/* + * Helpers to control vblanks while we flush.. basically just to ensure + * that vblank accounting is switched on, so we get valid seqn/timestamp + * on pageflip events (if requested) + */ + +static void vblank_get(struct msm_kms *kms, unsigned crtc_mask) +{ + struct drm_crtc *crtc; + + for_each_crtc_mask(kms->dev, crtc, crtc_mask) { + if (!crtc->state->active) + continue; + drm_crtc_vblank_get(crtc); + } +} + +static void vblank_put(struct msm_kms *kms, unsigned crtc_mask) +{ + struct drm_crtc *crtc; + + for_each_crtc_mask(kms->dev, crtc, crtc_mask) { + if (!crtc->state->active) + continue; + drm_crtc_vblank_put(crtc); + } +} + static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) { unsigned crtc_mask = BIT(crtc_idx); @@ -44,6 +72,8 @@ static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
kms->funcs->enable_commit(kms);
+ vblank_get(kms, crtc_mask); + /* * Flush hardware updates: */ @@ -58,6 +88,8 @@ static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) kms->funcs->wait_flush(kms, crtc_mask); trace_msm_atomic_wait_flush_finish(crtc_mask);
+ vblank_put(kms, crtc_mask); + mutex_lock(&kms->commit_lock); kms->funcs->complete_commit(kms, crtc_mask); mutex_unlock(&kms->commit_lock); @@ -221,6 +253,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) */ kms->pending_crtc_mask &= ~crtc_mask;
+ vblank_get(kms, crtc_mask); + /* * Flush hardware updates: */ @@ -235,6 +269,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) kms->funcs->wait_flush(kms, crtc_mask); trace_msm_atomic_wait_flush_finish(crtc_mask);
+ vblank_put(kms, crtc_mask); + mutex_lock(&kms->commit_lock); kms->funcs->complete_commit(kms, crtc_mask); mutex_unlock(&kms->commit_lock);
From: Ofir Bitton obitton@habana.ai
[ Upstream commit f1aae40e8dbd2655e3b10cae381a1e8292b19d57 ]
In case the driver fails to configure the PCI controller iATU, it needs to unmap the PCI bars before exiting so if the driver is removed, the bars won't be left mapped.
Signed-off-by: Ofir Bitton obitton@habana.ai Reviewed-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/pci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/habanalabs/pci.c b/drivers/misc/habanalabs/pci.c index 9f634ef6f5b37..77022c0b42027 100644 --- a/drivers/misc/habanalabs/pci.c +++ b/drivers/misc/habanalabs/pci.c @@ -378,15 +378,17 @@ int hl_pci_init(struct hl_device *hdev) rc = hdev->asic_funcs->init_iatu(hdev); if (rc) { dev_err(hdev->dev, "Failed to initialize iATU\n"); - goto disable_device; + goto unmap_pci_bars; }
rc = hl_pci_set_dma_mask(hdev); if (rc) - goto disable_device; + goto unmap_pci_bars;
return 0;
+unmap_pci_bars: + hl_pci_bars_unmap(hdev); disable_device: pci_clear_master(pdev); pci_disable_device(pdev);
From: Ofir Bitton obitton@habana.ai
[ Upstream commit bc75be24fa88ef10eecaff2b2a9ada8189e5ab5d ]
During command buffer parsing, driver extracts packet id from user buffer. Driver must validate this packet id, since it is being used in order to extract information from internal structures.
Signed-off-by: Ofir Bitton obitton@habana.ai Reviewed-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/gaudi/gaudi.c | 35 +++++++++++++++++++++++++++ drivers/misc/habanalabs/goya/goya.c | 31 ++++++++++++++++++++++++ 2 files changed, 66 insertions(+)
diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 637a9d608707f..0261f60df5633 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -154,6 +154,29 @@ static const u16 gaudi_packet_sizes[MAX_PACKET_ID] = { [PACKET_LOAD_AND_EXE] = sizeof(struct packet_load_and_exe) };
+static inline bool validate_packet_id(enum packet_id id) +{ + switch (id) { + case PACKET_WREG_32: + case PACKET_WREG_BULK: + case PACKET_MSG_LONG: + case PACKET_MSG_SHORT: + case PACKET_CP_DMA: + case PACKET_REPEAT: + case PACKET_MSG_PROT: + case PACKET_FENCE: + case PACKET_LIN_DMA: + case PACKET_NOP: + case PACKET_STOP: + case PACKET_ARB_POINT: + case PACKET_WAIT: + case PACKET_LOAD_AND_EXE: + return true; + default: + return false; + } +} + static const char * const gaudi_tpc_interrupts_cause[GAUDI_NUM_OF_TPC_INTR_CAUSE] = { "tpc_address_exceed_slm", @@ -3859,6 +3882,12 @@ static int gaudi_validate_cb(struct hl_device *hdev, PACKET_HEADER_PACKET_ID_MASK) >> PACKET_HEADER_PACKET_ID_SHIFT);
+ if (!validate_packet_id(pkt_id)) { + dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id); + rc = -EINVAL; + break; + } + pkt_size = gaudi_packet_sizes[pkt_id]; cb_parsed_length += pkt_size; if (cb_parsed_length > parser->user_cb_size) { @@ -4082,6 +4111,12 @@ static int gaudi_patch_cb(struct hl_device *hdev, PACKET_HEADER_PACKET_ID_MASK) >> PACKET_HEADER_PACKET_ID_SHIFT);
+ if (!validate_packet_id(pkt_id)) { + dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id); + rc = -EINVAL; + break; + } + pkt_size = gaudi_packet_sizes[pkt_id]; cb_parsed_length += pkt_size; if (cb_parsed_length > parser->user_cb_size) { diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 88460b2138d88..c179085ced7b8 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -139,6 +139,25 @@ static u16 goya_packet_sizes[MAX_PACKET_ID] = { [PACKET_STOP] = sizeof(struct packet_stop) };
+static inline bool validate_packet_id(enum packet_id id) +{ + switch (id) { + case PACKET_WREG_32: + case PACKET_WREG_BULK: + case PACKET_MSG_LONG: + case PACKET_MSG_SHORT: + case PACKET_CP_DMA: + case PACKET_MSG_PROT: + case PACKET_FENCE: + case PACKET_LIN_DMA: + case PACKET_NOP: + case PACKET_STOP: + return true; + default: + return false; + } +} + static u64 goya_mmu_regs[GOYA_MMU_REGS_NUM] = { mmDMA_QM_0_GLBL_NON_SECURE_PROPS, mmDMA_QM_1_GLBL_NON_SECURE_PROPS, @@ -3381,6 +3400,12 @@ static int goya_validate_cb(struct hl_device *hdev, PACKET_HEADER_PACKET_ID_MASK) >> PACKET_HEADER_PACKET_ID_SHIFT);
+ if (!validate_packet_id(pkt_id)) { + dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id); + rc = -EINVAL; + break; + } + pkt_size = goya_packet_sizes[pkt_id]; cb_parsed_length += pkt_size; if (cb_parsed_length > parser->user_cb_size) { @@ -3616,6 +3641,12 @@ static int goya_patch_cb(struct hl_device *hdev, PACKET_HEADER_PACKET_ID_MASK) >> PACKET_HEADER_PACKET_ID_SHIFT);
+ if (!validate_packet_id(pkt_id)) { + dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id); + rc = -EINVAL; + break; + } + pkt_size = goya_packet_sizes[pkt_id]; cb_parsed_length += pkt_size; if (cb_parsed_length > parser->user_cb_size) {
From: Ofir Bitton obitton@habana.ai
[ Upstream commit f44d23b9095abd91dad9f5f3add2a3149833ec83 ]
Once clock gating is set we enable clock gating according to mask, we should also disable clock gating according to relevant bits.
Signed-off-by: Ofir Bitton obitton@habana.ai Reviewed-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/gaudi/gaudi.c | 44 +++++++++++++-------------- 1 file changed, 21 insertions(+), 23 deletions(-)
diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 0261f60df5633..8b6cf722ddf8e 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -2564,6 +2564,7 @@ static void gaudi_set_clock_gating(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; u32 qman_offset; + bool enable; int i;
/* In case we are during debug session, don't enable the clock gate @@ -2573,46 +2574,43 @@ static void gaudi_set_clock_gating(struct hl_device *hdev) return;
for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) { - if (!(hdev->clock_gating_mask & - (BIT_ULL(gaudi_dma_assignment[i])))) - continue; + enable = !!(hdev->clock_gating_mask & + (BIT_ULL(gaudi_dma_assignment[i])));
qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET; - WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, QMAN_CGM1_PWR_GATE_EN); + WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, + enable ? QMAN_CGM1_PWR_GATE_EN : 0); WREG32(mmDMA0_QM_CGM_CFG + qman_offset, - QMAN_UPPER_CP_CGM_PWR_GATE_EN); + enable ? QMAN_UPPER_CP_CGM_PWR_GATE_EN : 0); }
for (i = GAUDI_HBM_DMA_1 ; i < GAUDI_DMA_MAX ; i++) { - if (!(hdev->clock_gating_mask & - (BIT_ULL(gaudi_dma_assignment[i])))) - continue; + enable = !!(hdev->clock_gating_mask & + (BIT_ULL(gaudi_dma_assignment[i])));
qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET; - WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, QMAN_CGM1_PWR_GATE_EN); + WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, + enable ? QMAN_CGM1_PWR_GATE_EN : 0); WREG32(mmDMA0_QM_CGM_CFG + qman_offset, - QMAN_COMMON_CP_CGM_PWR_GATE_EN); + enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0); }
- if (hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0))) { - WREG32(mmMME0_QM_CGM_CFG1, QMAN_CGM1_PWR_GATE_EN); - WREG32(mmMME0_QM_CGM_CFG, QMAN_COMMON_CP_CGM_PWR_GATE_EN); - } + enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0))); + WREG32(mmMME0_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0); + WREG32(mmMME0_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
- if (hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2))) { - WREG32(mmMME2_QM_CGM_CFG1, QMAN_CGM1_PWR_GATE_EN); - WREG32(mmMME2_QM_CGM_CFG, QMAN_COMMON_CP_CGM_PWR_GATE_EN); - } + enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2))); + WREG32(mmMME2_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0); + WREG32(mmMME2_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
for (i = 0, qman_offset = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) { - if (!(hdev->clock_gating_mask & - (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i)))) - continue; + enable = !!(hdev->clock_gating_mask & + (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i)));
WREG32(mmTPC0_QM_CGM_CFG1 + qman_offset, - QMAN_CGM1_PWR_GATE_EN); + enable ? QMAN_CGM1_PWR_GATE_EN : 0); WREG32(mmTPC0_QM_CGM_CFG + qman_offset, - QMAN_COMMON_CP_CGM_PWR_GATE_EN); + enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
qman_offset += TPC_QMAN_OFFSET; }
From: Ofir Bitton obitton@habana.ai
[ Upstream commit 36545279f076afeb77104f5ffeab850da3b6d107 ]
Allocation size can go up to 64bit but truncated to 32bit, we should make sure it is not truncated and validate no address overflow.
Signed-off-by: Ofir Bitton obitton@habana.ai Reviewed-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/gaudi/gaudi_coresight.c | 8 +++++++- drivers/misc/habanalabs/goya/goya_coresight.c | 8 +++++++- drivers/misc/habanalabs/habanalabs.h | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c index bf0e062d7b874..cc3d03549a6e4 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c @@ -523,7 +523,7 @@ static int gaudi_config_etf(struct hl_device *hdev, }
static bool gaudi_etr_validate_address(struct hl_device *hdev, u64 addr, - u32 size, bool *is_host) + u64 size, bool *is_host) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; @@ -535,6 +535,12 @@ static bool gaudi_etr_validate_address(struct hl_device *hdev, u64 addr, return false; }
+ if (addr > (addr + size)) { + dev_err(hdev->dev, + "ETR buffer size %llu overflow\n", size); + return false; + } + /* PMMU and HPMMU addresses are equal, check only one of them */ if ((gaudi->hw_cap_initialized & HW_CAP_MMU) && hl_mem_area_inside_range(addr, size, diff --git a/drivers/misc/habanalabs/goya/goya_coresight.c b/drivers/misc/habanalabs/goya/goya_coresight.c index 1258724ea5106..c23a9fcb74b57 100644 --- a/drivers/misc/habanalabs/goya/goya_coresight.c +++ b/drivers/misc/habanalabs/goya/goya_coresight.c @@ -358,11 +358,17 @@ static int goya_config_etf(struct hl_device *hdev, }
static int goya_etr_validate_address(struct hl_device *hdev, u64 addr, - u32 size) + u64 size) { struct asic_fixed_properties *prop = &hdev->asic_prop; u64 range_start, range_end;
+ if (addr > (addr + size)) { + dev_err(hdev->dev, + "ETR buffer size %llu overflow\n", size); + return false; + } + if (hdev->mmu_enable) { range_start = prop->dmmu.start_addr; range_end = prop->dmmu.end_addr; diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h index 194d833526964..feedf3194ea6c 100644 --- a/drivers/misc/habanalabs/habanalabs.h +++ b/drivers/misc/habanalabs/habanalabs.h @@ -1587,7 +1587,7 @@ struct hl_ioctl_desc { * * Return: true if the area is inside the valid range, false otherwise. */ -static inline bool hl_mem_area_inside_range(u64 address, u32 size, +static inline bool hl_mem_area_inside_range(u64 address, u64 size, u64 range_start_address, u64 range_end_address) { u64 end_address = address + size;
From: Oded Gabbay oded.gabbay@gmail.com
[ Upstream commit 58361aae4b0eed388680a89ac153d27177f40510 ]
In Gaudi, the default max power setting is different between PCI and PMC cards. Therefore, the driver need to set the default after knowing what is the card type.
The current code has a bug where it limits the maximum power of the PMC card to 200W after a reset occurs.
Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/device.c | 7 ++++++- drivers/misc/habanalabs/gaudi/gaudi.c | 11 ++++++++++- drivers/misc/habanalabs/gaudi/gaudiP.h | 3 ++- drivers/misc/habanalabs/habanalabs.h | 5 ++++- drivers/misc/habanalabs/sysfs.c | 7 ++++--- 5 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/misc/habanalabs/device.c b/drivers/misc/habanalabs/device.c index 59608d1bac880..baa4e66d4c457 100644 --- a/drivers/misc/habanalabs/device.c +++ b/drivers/misc/habanalabs/device.c @@ -1027,7 +1027,7 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset, goto out_err; }
- hl_set_max_power(hdev, hdev->max_power); + hl_set_max_power(hdev); } else { rc = hdev->asic_funcs->soft_reset_late_init(hdev); if (rc) { @@ -1268,6 +1268,11 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) goto out_disabled; }
+ /* Need to call this again because the max power might change, + * depending on card type for certain ASICs + */ + hl_set_max_power(hdev); + /* * hl_hwmon_init() must be called after device_late_init(), because only * there we get the information from the device about which diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 8b6cf722ddf8e..ca183733847b6 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -447,7 +447,7 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) prop->num_of_events = GAUDI_EVENT_SIZE; prop->tpc_enabled_mask = TPC_ENABLED_MASK;
- prop->max_power_default = MAX_POWER_DEFAULT; + prop->max_power_default = MAX_POWER_DEFAULT_PCI;
prop->cb_pool_cb_cnt = GAUDI_CB_POOL_CB_CNT; prop->cb_pool_cb_size = GAUDI_CB_POOL_CB_SIZE; @@ -6241,6 +6241,15 @@ static int gaudi_armcp_info_get(struct hl_device *hdev) strncpy(prop->armcp_info.card_name, GAUDI_DEFAULT_CARD_NAME, CARD_NAME_MAX_LEN);
+ hdev->card_type = le32_to_cpu(hdev->asic_prop.armcp_info.card_type); + + if (hdev->card_type == armcp_card_type_pci) + prop->max_power_default = MAX_POWER_DEFAULT_PCI; + else if (hdev->card_type == armcp_card_type_pmc) + prop->max_power_default = MAX_POWER_DEFAULT_PMC; + + hdev->max_power = prop->max_power_default; + return 0; }
diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 41a8d9bff6bf9..00f1efeaa8832 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -41,7 +41,8 @@
#define GAUDI_MAX_CLK_FREQ 2200000000ull /* 2200 MHz */
-#define MAX_POWER_DEFAULT 200000 /* 200W */ +#define MAX_POWER_DEFAULT_PCI 200000 /* 200W */ +#define MAX_POWER_DEFAULT_PMC 350000 /* 350W */
#define GAUDI_CPU_TIMEOUT_USEC 15000000 /* 15s */
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h index feedf3194ea6c..1072f300252a4 100644 --- a/drivers/misc/habanalabs/habanalabs.h +++ b/drivers/misc/habanalabs/habanalabs.h @@ -1408,6 +1408,8 @@ struct hl_device_idle_busy_ts { * details. * @in_reset: is device in reset flow. * @curr_pll_profile: current PLL profile. + * @card_type: Various ASICs have several card types. This indicates the card + * type of the current device. * @cs_active_cnt: number of active command submissions on this device (active * means already in H/W queues) * @major: habanalabs kernel driver major. @@ -1503,6 +1505,7 @@ struct hl_device { u64 clock_gating_mask; atomic_t in_reset; enum hl_pll_frequency curr_pll_profile; + enum armcp_card_types card_type; int cs_active_cnt; u32 major; u32 high_pll; @@ -1792,7 +1795,7 @@ int hl_get_pwm_info(struct hl_device *hdev, void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long value); u64 hl_get_max_power(struct hl_device *hdev); -void hl_set_max_power(struct hl_device *hdev, u64 value); +void hl_set_max_power(struct hl_device *hdev); int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, diff --git a/drivers/misc/habanalabs/sysfs.c b/drivers/misc/habanalabs/sysfs.c index 70b6b1863c2ef..87dadb53ac59d 100644 --- a/drivers/misc/habanalabs/sysfs.c +++ b/drivers/misc/habanalabs/sysfs.c @@ -81,7 +81,7 @@ u64 hl_get_max_power(struct hl_device *hdev) return result; }
-void hl_set_max_power(struct hl_device *hdev, u64 value) +void hl_set_max_power(struct hl_device *hdev) { struct armcp_packet pkt; int rc; @@ -90,7 +90,7 @@ void hl_set_max_power(struct hl_device *hdev, u64 value)
pkt.ctl = cpu_to_le32(ARMCP_PACKET_MAX_POWER_SET << ARMCP_PKT_CTL_OPCODE_SHIFT); - pkt.value = cpu_to_le64(value); + pkt.value = cpu_to_le64(hdev->max_power);
rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL); @@ -316,7 +316,7 @@ static ssize_t max_power_store(struct device *dev, }
hdev->max_power = value; - hl_set_max_power(hdev, value); + hl_set_max_power(hdev);
out: return count; @@ -419,6 +419,7 @@ int hl_sysfs_init(struct hl_device *hdev) hdev->pm_mng_profile = PM_AUTO; else hdev->pm_mng_profile = PM_MANUAL; + hdev->max_power = hdev->asic_prop.max_power_default;
hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group);
From: Ofir Bitton obitton@habana.ai
[ Upstream commit bce382a8bb080ed5f2f3a06754526dc58b91cca2 ]
We must validate FW size in order not to corrupt memory in case a malicious FW file will be present in system.
Signed-off-by: Ofir Bitton obitton@habana.ai Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/firmware_if.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/misc/habanalabs/firmware_if.c b/drivers/misc/habanalabs/firmware_if.c index d27841cb5bcb3..345c228a7971e 100644 --- a/drivers/misc/habanalabs/firmware_if.c +++ b/drivers/misc/habanalabs/firmware_if.c @@ -13,6 +13,7 @@ #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/slab.h>
+#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ /** * hl_fw_load_fw_to_device() - Load F/W code to device's memory. * @hdev: pointer to hl_device structure. @@ -45,6 +46,14 @@ int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
+ if (fw_size > FW_FILE_MAX_SIZE) { + dev_err(hdev->dev, + "FW file size %zu exceeds maximum of %u bytes\n", + fw_size, FW_FILE_MAX_SIZE); + rc = -EINVAL; + goto out; + } + fw_data = (const u64 *) fw->data;
memcpy_toio(dst, fw_data, fw_size);
From: Ofir Bitton obitton@habana.ai
[ Upstream commit 0839152f8c1efc1cc2d515d1ff1e253ca9402ad3 ]
vmalloc can return different return code than NULL and a valid pointer. We must validate it in order to dereference a non valid pointer.
Signed-off-by: Ofir Bitton obitton@habana.ai Signed-off-by: Oded Gabbay oded.gabbay@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/memory.c | 9 +++++++-- drivers/misc/habanalabs/mmu.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/misc/habanalabs/memory.c b/drivers/misc/habanalabs/memory.c index 47da84a177197..e30b1b1877efa 100644 --- a/drivers/misc/habanalabs/memory.c +++ b/drivers/misc/habanalabs/memory.c @@ -66,6 +66,11 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, num_pgs = (args->alloc.mem_size + (page_size - 1)) >> page_shift; total_size = num_pgs << page_shift;
+ if (!total_size) { + dev_err(hdev->dev, "Cannot allocate 0 bytes\n"); + return -EINVAL; + } + contiguous = args->flags & HL_MEM_CONTIGUOUS;
if (contiguous) { @@ -93,7 +98,7 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, phys_pg_pack->contiguous = contiguous;
phys_pg_pack->pages = kvmalloc_array(num_pgs, sizeof(u64), GFP_KERNEL); - if (!phys_pg_pack->pages) { + if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) { rc = -ENOMEM; goto pages_arr_err; } @@ -683,7 +688,7 @@ static int init_phys_pg_pack_from_userptr(struct hl_ctx *ctx,
phys_pg_pack->pages = kvmalloc_array(total_npages, sizeof(u64), GFP_KERNEL); - if (!phys_pg_pack->pages) { + if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) { rc = -ENOMEM; goto page_pack_arr_mem_err; } diff --git a/drivers/misc/habanalabs/mmu.c b/drivers/misc/habanalabs/mmu.c index a290d6b49d788..eb582bd4937ba 100644 --- a/drivers/misc/habanalabs/mmu.c +++ b/drivers/misc/habanalabs/mmu.c @@ -450,7 +450,7 @@ int hl_mmu_init(struct hl_device *hdev) hdev->mmu_shadow_hop0 = kvmalloc_array(prop->max_asid, prop->mmu_hop_table_size, GFP_KERNEL | __GFP_ZERO); - if (!hdev->mmu_shadow_hop0) { + if (ZERO_OR_NULL_PTR(hdev->mmu_shadow_hop0)) { rc = -ENOMEM; goto err_pool_add; }
From: Dmitry Baryshkov dmitry.baryshkov@linaro.org
[ Upstream commit f5749d6181fa7df5ae741788e5d96f593d3a60b6 ]
New Qualcomm firmware has changed a way it reports back the 'started' event. Support new register values.
Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 1d330204c465c..2dd1cf1ffbe25 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -207,6 +207,16 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu) { int ret; u32 val; + u32 mask, reset_val; + + val = gmu_read(gmu, REG_A6XX_GMU_CM3_DTCM_START + 0xff8); + if (val <= 0x20010004) { + mask = 0xffffffff; + reset_val = 0xbabeface; + } else { + mask = 0x1ff; + reset_val = 0x100; + }
gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
@@ -218,7 +228,7 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu) gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0);
ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val, - val == 0xbabeface, 100, 10000); + (val & mask) == reset_val, 100, 10000);
if (ret) DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
From: Bob Peterson rpeterso@redhat.com
[ Upstream commit 462582b99b6079a6fbcdfc65bac49f5c2a27cfff ]
When a log flush fails due to io errors, it signals the failure but does not clean up after itself very well. This is because buffers are added to the transaction tr_buf and tr_databuf queue, but the io error causes gfs2_log_flush to bypass the "after_commit" functions responsible for dequeueing the bd elements. If the bd elements are added to the ail list before the error, function ail_drain takes care of dequeueing them. But if they haven't gotten that far, the elements are forgotten and make the transactions unable to be freed.
This patch introduces new function trans_drain which drains the bd elements from the transaction so they can be freed properly.
Signed-off-by: Bob Peterson rpeterso@redhat.com Signed-off-by: Andreas Gruenbacher agruenba@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/gfs2/log.c | 31 +++++++++++++++++++++++++++++++ fs/gfs2/trans.c | 1 + 2 files changed, 32 insertions(+)
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index a76e55bc28ebf..27f467a0f008e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -901,6 +901,36 @@ static void empty_ail1_list(struct gfs2_sbd *sdp) } }
+/** + * drain_bd - drain the buf and databuf queue for a failed transaction + * @tr: the transaction to drain + * + * When this is called, we're taking an error exit for a log write that failed + * but since we bypassed the after_commit functions, we need to remove the + * items from the buf and databuf queue. + */ +static void trans_drain(struct gfs2_trans *tr) +{ + struct gfs2_bufdata *bd; + struct list_head *head; + + if (!tr) + return; + + head = &tr->tr_buf; + while (!list_empty(head)) { + bd = list_first_entry(head, struct gfs2_bufdata, bd_list); + list_del_init(&bd->bd_list); + kmem_cache_free(gfs2_bufdata_cachep, bd); + } + head = &tr->tr_databuf; + while (!list_empty(head)) { + bd = list_first_entry(head, struct gfs2_bufdata, bd_list); + list_del_init(&bd->bd_list); + kmem_cache_free(gfs2_bufdata_cachep, bd); + } +} + /** * gfs2_log_flush - flush incore transaction(s) * @sdp: the filesystem @@ -1005,6 +1035,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
out: if (gfs2_withdrawn(sdp)) { + trans_drain(tr); /** * If the tr_list is empty, we're withdrawing during a log * flush that targets a transaction, but the transaction was diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index a3dfa3aa87ad9..d897dd73c5999 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -52,6 +52,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, tr->tr_reserved += gfs2_struct2blk(sdp, revokes); INIT_LIST_HEAD(&tr->tr_databuf); INIT_LIST_HEAD(&tr->tr_buf); + INIT_LIST_HEAD(&tr->tr_list); INIT_LIST_HEAD(&tr->tr_ail1_list); INIT_LIST_HEAD(&tr->tr_ail2_list);
From: Vineeth Pillai viremana@linux.microsoft.com
[ Upstream commit 90b125f4cd2697f949f5877df723a0b710693dd0 ]
If for any reason, host timesync messages were not processed by the guest, hv_ptp_gettime() returns a stale value and the caller (clock_gettime, PTP ioctl etc) has no means to know this now. Return an error so that the caller knows about this.
Signed-off-by: Vineeth Pillai viremana@linux.microsoft.com Reviewed-by: Michael Kelley mikelley@microsoft.com Link: https://lore.kernel.org/r/20200821152523.99364-1-viremana@linux.microsoft.co... Signed-off-by: Wei Liu wei.liu@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hv/hv_util.c | 46 +++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-)
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 92ee0fe4c919e..1f86e8d9b018d 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -282,26 +282,52 @@ static struct { spinlock_t lock; } host_ts;
-static struct timespec64 hv_get_adj_host_time(void) +static inline u64 reftime_to_ns(u64 reftime) { - struct timespec64 ts; - u64 newtime, reftime; + return (reftime - WLTIMEDELTA) * 100; +} + +/* + * Hard coded threshold for host timesync delay: 600 seconds + */ +static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64)NSEC_PER_SEC; + +static int hv_get_adj_host_time(struct timespec64 *ts) +{ + u64 newtime, reftime, timediff_adj; unsigned long flags; + int ret = 0;
spin_lock_irqsave(&host_ts.lock, flags); reftime = hv_read_reference_counter(); - newtime = host_ts.host_time + (reftime - host_ts.ref_time); - ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100); + + /* + * We need to let the caller know that last update from host + * is older than the max allowable threshold. clock_gettime() + * and PTP ioctl do not have a documented error that we could + * return for this specific case. Use ESTALE to report this. + */ + timediff_adj = reftime - host_ts.ref_time; + if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH) { + pr_warn_once("TIMESYNC IC: Stale time stamp, %llu nsecs old\n", + (timediff_adj * 100)); + ret = -ESTALE; + } + + newtime = host_ts.host_time + timediff_adj; + *ts = ns_to_timespec64(reftime_to_ns(newtime)); spin_unlock_irqrestore(&host_ts.lock, flags);
- return ts; + return ret; }
static void hv_set_host_time(struct work_struct *work) { - struct timespec64 ts = hv_get_adj_host_time();
- do_settimeofday64(&ts); + struct timespec64 ts; + + if (!hv_get_adj_host_time(&ts)) + do_settimeofday64(&ts); }
/* @@ -622,9 +648,7 @@ static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts) { - *ts = hv_get_adj_host_time(); - - return 0; + return hv_get_adj_host_time(ts); }
static struct ptp_clock_info ptp_hyperv_info = {
From: Vineeth Pillai viremana@linux.microsoft.com
[ Upstream commit b46b4a8a57c377b72a98c7930a9f6969d2d4784e ]
There could be instances where a system stall prevents the timesync packets to be consumed. And this might lead to more than one packet pending in the ring buffer. Current code empties one packet per callback and it might be a stale one. So drain all the packets from ring buffer on each callback.
Signed-off-by: Vineeth Pillai viremana@linux.microsoft.com Reviewed-by: Michael Kelley mikelley@microsoft.com Link: https://lore.kernel.org/r/20200821152849.99517-1-viremana@linux.microsoft.co... Signed-off-by: Wei Liu wei.liu@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hv/hv_util.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 1f86e8d9b018d..a4e8d96513c22 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -387,10 +387,23 @@ static void timesync_onchannelcallback(void *context) struct ictimesync_ref_data *refdata; u8 *time_txf_buf = util_timesynch.recv_buffer;
- vmbus_recvpacket(channel, time_txf_buf, - HV_HYP_PAGE_SIZE, &recvlen, &requestid); + /* + * Drain the ring buffer and use the last packet to update + * host_ts + */ + while (1) { + int ret = vmbus_recvpacket(channel, time_txf_buf, + HV_HYP_PAGE_SIZE, &recvlen, + &requestid); + if (ret) { + pr_warn_once("TimeSync IC pkt recv failed (Err: %d)\n", + ret); + break; + } + + if (!recvlen) + break;
- if (recvlen > 0) { icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[ sizeof(struct vmbuspipe_hdr)];
From: Jeff Layton jlayton@kernel.org
[ Upstream commit ebce3eb2f7ef9f6ef01a60874ebd232450107c9a ]
Tuan and Ulrich mentioned that they were hitting a problem on s390x, which has a 32-bit ino_t value, even though it's a 64-bit arch (for historical reasons).
I think the current handling of inode numbers in the ceph driver is wrong. It tries to use 32-bit inode numbers on 32-bit arches, but that's actually not a problem. 32-bit arches can deal with 64-bit inode numbers just fine when userland code is compiled with LFS support (the common case these days).
What we really want to do is just use 64-bit numbers everywhere, unless someone has mounted with the ino32 mount option. In that case, we want to ensure that we hash the inode number down to something that will fit in 32 bits before presenting the value to userland.
Add new helper functions that do this, and only do the conversion before presenting these values to userland in getattr and readdir.
The inode table hashvalue is changed to just cast the inode number to unsigned long, as low-order bits are the most likely to vary anyway.
While it's not strictly required, we do want to put something in inode->i_ino. Instead of basing it on BITS_PER_LONG, however, base it on the size of the ino_t type.
NOTE: This is a user-visible change on 32-bit arches:
1/ inode numbers will be seen to have changed between kernel versions. 32-bit arches will see large inode numbers now instead of the hashed ones they saw before.
2/ any really old software not built with LFS support may start failing stat() calls with -EOVERFLOW on inode numbers >2^32. Nothing much we can do about these, but hopefully the intersection of people running such code on ceph will be very small.
The workaround for both problems is to mount with "-o ino32".
[ idryomov: changelog tweak ]
URL: https://tracker.ceph.com/issues/46828 Reported-by: Ulrich Weigand Ulrich.Weigand@de.ibm.com Reported-and-Tested-by: Tuan Hoang1 Tuan.Hoang1@ibm.com Signed-off-by: Jeff Layton jlayton@kernel.org Reviewed-by: "Yan, Zheng" zyan@redhat.com Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/ceph/caps.c | 14 ++++----- fs/ceph/debugfs.c | 4 +-- fs/ceph/dir.c | 31 ++++++++----------- fs/ceph/file.c | 4 +-- fs/ceph/inode.c | 19 ++++++------ fs/ceph/mds_client.h | 2 +- fs/ceph/quota.c | 4 +-- fs/ceph/super.h | 73 +++++++++++++++++++++++--------------------- 8 files changed, 74 insertions(+), 77 deletions(-)
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 972c13aa42259..1206a481c5fc7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -886,8 +886,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) int have = ci->i_snap_caps;
if ((have & mask) == mask) { - dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s" - " (mask %s)\n", ci->vfs_inode.i_ino, + dout("__ceph_caps_issued_mask ino 0x%llx snap issued %s" + " (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(have), ceph_cap_string(mask)); return 1; @@ -898,8 +898,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) if (!__cap_is_valid(cap)) continue; if ((cap->issued & mask) == mask) { - dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s" - " (mask %s)\n", ci->vfs_inode.i_ino, cap, + dout("__ceph_caps_issued_mask ino 0x%llx cap %p issued %s" + " (mask %s)\n", ceph_ino(&ci->vfs_inode), cap, ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch) @@ -910,8 +910,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) /* does a combination of caps satisfy mask? */ have |= cap->issued; if ((have & mask) == mask) { - dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s" - " (mask %s)\n", ci->vfs_inode.i_ino, + dout("__ceph_caps_issued_mask ino 0x%llx combo issued %s" + " (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch) { @@ -2870,7 +2870,7 @@ int ceph_get_caps(struct file *filp, int need, int want, struct cap_wait cw; DEFINE_WAIT_FUNC(wait, woken_wake_function);
- cw.ino = inode->i_ino; + cw.ino = ceph_ino(inode); cw.tgid = current->tgid; cw.need = need; cw.want = want; diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 070ed84813406..74747d8d48619 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -212,7 +212,7 @@ static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) { struct seq_file *s = p;
- seq_printf(s, "0x%-17lx%-17s%-17s\n", inode->i_ino, + seq_printf(s, "0x%-17llx%-17s%-17s\n", ceph_ino(inode), ceph_cap_string(cap->issued), ceph_cap_string(cap->implemented)); return 0; @@ -257,7 +257,7 @@ static int caps_show(struct seq_file *s, void *p)
spin_lock(&mdsc->caps_list_lock); list_for_each_entry(cw, &mdsc->cap_wait_list, list) { - seq_printf(s, "%-13d0x%-17lx%-17s%-17s\n", cw->tgid, cw->ino, + seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino, ceph_cap_string(cw->need), ceph_cap_string(cw->want)); } diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 060bdcc5ce32c..040eaad9d0631 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -259,9 +259,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx, dentry, dentry, d_inode(dentry)); ctx->pos = di->offset; if (!dir_emit(ctx, dentry->d_name.name, - dentry->d_name.len, - ceph_translate_ino(dentry->d_sb, - d_inode(dentry)->i_ino), + dentry->d_name.len, ceph_present_inode(d_inode(dentry)), d_inode(dentry)->i_mode >> 12)) { dput(dentry); err = 0; @@ -324,18 +322,21 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) /* always start with . and .. */ if (ctx->pos == 0) { dout("readdir off 0 -> '.'\n"); - if (!dir_emit(ctx, ".", 1, - ceph_translate_ino(inode->i_sb, inode->i_ino), + if (!dir_emit(ctx, ".", 1, ceph_present_inode(inode), inode->i_mode >> 12)) return 0; ctx->pos = 1; } if (ctx->pos == 1) { - ino_t ino = parent_ino(file->f_path.dentry); + u64 ino; + struct dentry *dentry = file->f_path.dentry; + + spin_lock(&dentry->d_lock); + ino = ceph_present_inode(dentry->d_parent->d_inode); + spin_unlock(&dentry->d_lock); + dout("readdir off 1 -> '..'\n"); - if (!dir_emit(ctx, "..", 2, - ceph_translate_ino(inode->i_sb, ino), - inode->i_mode >> 12)) + if (!dir_emit(ctx, "..", 2, ino, inode->i_mode >> 12)) return 0; ctx->pos = 2; } @@ -507,9 +508,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) } for (; i < rinfo->dir_nr; i++) { struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i; - struct ceph_vino vino; - ino_t ino; - u32 ftype;
BUG_ON(rde->offset < ctx->pos);
@@ -519,13 +517,10 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) rde->name_len, rde->name, &rde->inode.in);
BUG_ON(!rde->inode.in); - ftype = le32_to_cpu(rde->inode.in->mode) >> 12; - vino.ino = le64_to_cpu(rde->inode.in->ino); - vino.snap = le64_to_cpu(rde->inode.in->snapid); - ino = ceph_vino_to_ino(vino);
if (!dir_emit(ctx, rde->name, rde->name_len, - ceph_translate_ino(inode->i_sb, ino), ftype)) { + ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)), + le32_to_cpu(rde->inode.in->mode) >> 12)) { dout("filldir stopping us...\n"); return 0; } @@ -1161,7 +1156,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
if (try_async && op == CEPH_MDS_OP_UNLINK && (req->r_dir_caps = get_caps_for_async_unlink(dir, dentry))) { - dout("async unlink on %lu/%.*s caps=%s", dir->i_ino, + dout("async unlink on %llu/%.*s caps=%s", ceph_ino(dir), dentry->d_name.len, dentry->d_name.name, ceph_cap_string(req->r_dir_caps)); set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 160644ddaeed7..26172bb90a459 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -630,8 +630,8 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, } else { struct dentry *dn;
- dout("%s d_adding new inode 0x%llx to 0x%lx/%s\n", __func__, - vino.ino, dir->i_ino, dentry->d_name.name); + dout("%s d_adding new inode 0x%llx to 0x%llx/%s\n", __func__, + vino.ino, ceph_ino(dir), dentry->d_name.name); ceph_dir_clear_ordered(dir); ceph_init_inode_acls(inode, as_ctx); if (inode->i_state & I_NEW) { diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 357c937699d56..d163fa96cb401 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -41,8 +41,10 @@ static void ceph_inode_work(struct work_struct *work); */ static int ceph_set_ino_cb(struct inode *inode, void *data) { - ceph_inode(inode)->i_vino = *(struct ceph_vino *)data; - inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data); + struct ceph_inode_info *ci = ceph_inode(inode); + + ci->i_vino = *(struct ceph_vino *)data; + inode->i_ino = ceph_vino_to_ino_t(ci->i_vino); inode_set_iversion_raw(inode, 0); return 0; } @@ -50,17 +52,14 @@ static int ceph_set_ino_cb(struct inode *inode, void *data) struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino) { struct inode *inode; - ino_t t = ceph_vino_to_ino(vino);
- inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino); + inode = iget5_locked(sb, (unsigned long)vino.ino, ceph_ino_compare, + ceph_set_ino_cb, &vino); if (!inode) return ERR_PTR(-ENOMEM); - if (inode->i_state & I_NEW) - dout("get_inode created new inode %p %llx.%llx ino %llx\n", - inode, ceph_vinop(inode), (u64)inode->i_ino);
- dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino, - vino.snap, inode); + dout("get_inode on %llu=%llx.%llx got %p new %d\n", ceph_present_inode(inode), + ceph_vinop(inode), inode, !!(inode->i_state & I_NEW)); return inode; }
@@ -2378,7 +2377,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat, }
generic_fillattr(inode, stat); - stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino); + stat->ino = ceph_present_inode(inode);
/* * btime on newly-allocated inodes is 0, so if this is still set to diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 5e0c4073a6bea..63c9cd1c28d6c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -369,7 +369,7 @@ struct ceph_quotarealm_inode {
struct cap_wait { struct list_head list; - unsigned long ino; + u64 ino; pid_t tgid; int need; int want; diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 198ddde5c1e6a..cc2c4d40b0222 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -23,12 +23,12 @@ static inline bool ceph_has_realms_with_quotas(struct inode *inode) { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct super_block *sb = mdsc->fsc->sb; + struct inode *root = d_inode(sb->s_root);
if (atomic64_read(&mdsc->quotarealms_count) > 0) return true; /* if root is the real CephFS root, we don't have quota realms */ - if (sb->s_root->d_inode && - (sb->s_root->d_inode->i_ino == CEPH_INO_ROOT)) + if (root && ceph_ino(root) == CEPH_INO_ROOT) return false; /* otherwise, we can't know for sure */ return true; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 5a6cdd39bc103..2af3e06a6d0ce 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -457,15 +457,7 @@ ceph_vino(const struct inode *inode) return ceph_inode(inode)->i_vino; }
-/* - * ino_t is <64 bits on many architectures, blech. - * - * i_ino (kernel inode) st_ino (userspace) - * i386 32 32 - * x86_64+ino32 64 32 - * x86_64 64 64 - */ -static inline u32 ceph_ino_to_ino32(__u64 vino) +static inline u32 ceph_ino_to_ino32(u64 vino) { u32 ino = vino & 0xffffffff; ino ^= vino >> 32; @@ -475,34 +467,17 @@ static inline u32 ceph_ino_to_ino32(__u64 vino) }
/* - * kernel i_ino value + * Inode numbers in cephfs are 64 bits, but inode->i_ino is 32-bits on + * some arches. We generally do not use this value inside the ceph driver, but + * we do want to set it to something, so that generic vfs code has an + * appropriate value for tracepoints and the like. */ -static inline ino_t ceph_vino_to_ino(struct ceph_vino vino) +static inline ino_t ceph_vino_to_ino_t(struct ceph_vino vino) { -#if BITS_PER_LONG == 32 - return ceph_ino_to_ino32(vino.ino); -#else + if (sizeof(ino_t) == sizeof(u32)) + return ceph_ino_to_ino32(vino.ino); return (ino_t)vino.ino; -#endif -} - -/* - * user-visible ino (stat, filldir) - */ -#if BITS_PER_LONG == 32 -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{ - return ino; -} -#else -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{ - if (ceph_test_mount_opt(ceph_sb_to_client(sb), INO32)) - ino = ceph_ino_to_ino32(ino); - return ino; } -#endif -
/* for printf-style formatting */ #define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap @@ -511,11 +486,34 @@ static inline u64 ceph_ino(struct inode *inode) { return ceph_inode(inode)->i_vino.ino; } + static inline u64 ceph_snap(struct inode *inode) { return ceph_inode(inode)->i_vino.snap; }
+/** + * ceph_present_ino - format an inode number for presentation to userland + * @sb: superblock where the inode lives + * @ino: inode number to (possibly) convert + * + * If the user mounted with the ino32 option, then the 64-bit value needs + * to be converted to something that can fit inside 32 bits. Note that + * internal kernel code never uses this value, so this is entirely for + * userland consumption. + */ +static inline u64 ceph_present_ino(struct super_block *sb, u64 ino) +{ + if (unlikely(ceph_test_mount_opt(ceph_sb_to_client(sb), INO32))) + return ceph_ino_to_ino32(ino); + return ino; +} + +static inline u64 ceph_present_inode(struct inode *inode) +{ + return ceph_present_ino(inode->i_sb, ceph_ino(inode)); +} + static inline int ceph_ino_compare(struct inode *inode, void *data) { struct ceph_vino *pvino = (struct ceph_vino *)data; @@ -524,11 +522,16 @@ static inline int ceph_ino_compare(struct inode *inode, void *data) ci->i_vino.snap == pvino->snap; }
+ static inline struct inode *ceph_find_inode(struct super_block *sb, struct ceph_vino vino) { - ino_t t = ceph_vino_to_ino(vino); - return ilookup5(sb, t, ceph_ino_compare, &vino); + /* + * NB: The hashval will be run through the fs/inode.c hash function + * anyway, so there is no need to squash the inode number down to + * 32-bits first. Just use low-order bits on arches with 32-bit long. + */ + return ilookup5(sb, (unsigned long)vino.ino, ceph_ino_compare, &vino); }
On Mon, Aug 31, 2020 at 5:30 PM Sasha Levin sashal@kernel.org wrote:
From: Jeff Layton jlayton@kernel.org
[ Upstream commit ebce3eb2f7ef9f6ef01a60874ebd232450107c9a ]
Tuan and Ulrich mentioned that they were hitting a problem on s390x, which has a 32-bit ino_t value, even though it's a 64-bit arch (for historical reasons).
I think the current handling of inode numbers in the ceph driver is wrong. It tries to use 32-bit inode numbers on 32-bit arches, but that's actually not a problem. 32-bit arches can deal with 64-bit inode numbers just fine when userland code is compiled with LFS support (the common case these days).
What we really want to do is just use 64-bit numbers everywhere, unless someone has mounted with the ino32 mount option. In that case, we want to ensure that we hash the inode number down to something that will fit in 32 bits before presenting the value to userland.
Add new helper functions that do this, and only do the conversion before presenting these values to userland in getattr and readdir.
The inode table hashvalue is changed to just cast the inode number to unsigned long, as low-order bits are the most likely to vary anyway.
While it's not strictly required, we do want to put something in inode->i_ino. Instead of basing it on BITS_PER_LONG, however, base it on the size of the ino_t type.
NOTE: This is a user-visible change on 32-bit arches:
1/ inode numbers will be seen to have changed between kernel versions. 32-bit arches will see large inode numbers now instead of the hashed ones they saw before.
2/ any really old software not built with LFS support may start failing stat() calls with -EOVERFLOW on inode numbers >2^32. Nothing much we can do about these, but hopefully the intersection of people running such code on ceph will be very small.
The workaround for both problems is to mount with "-o ino32".
[ idryomov: changelog tweak ]
URL: https://tracker.ceph.com/issues/46828 Reported-by: Ulrich Weigand Ulrich.Weigand@de.ibm.com Reported-and-Tested-by: Tuan Hoang1 Tuan.Hoang1@ibm.com Signed-off-by: Jeff Layton jlayton@kernel.org Reviewed-by: "Yan, Zheng" zyan@redhat.com Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org
fs/ceph/caps.c | 14 ++++----- fs/ceph/debugfs.c | 4 +-- fs/ceph/dir.c | 31 ++++++++----------- fs/ceph/file.c | 4 +-- fs/ceph/inode.c | 19 ++++++------ fs/ceph/mds_client.h | 2 +- fs/ceph/quota.c | 4 +-- fs/ceph/super.h | 73 +++++++++++++++++++++++--------------------- 8 files changed, 74 insertions(+), 77 deletions(-)
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 972c13aa42259..1206a481c5fc7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -886,8 +886,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) int have = ci->i_snap_caps;
if ((have & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino,
dout("__ceph_caps_issued_mask ino 0x%llx snap issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(have), ceph_cap_string(mask)); return 1;
@@ -898,8 +898,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) if (!__cap_is_valid(cap)) continue; if ((cap->issued & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino, cap,
dout("__ceph_caps_issued_mask ino 0x%llx cap %p issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), cap, ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch)
@@ -910,8 +910,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) /* does a combination of caps satisfy mask? */ have |= cap->issued; if ((have & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino,
dout("__ceph_caps_issued_mask ino 0x%llx combo issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch) {
@@ -2870,7 +2870,7 @@ int ceph_get_caps(struct file *filp, int need, int want, struct cap_wait cw; DEFINE_WAIT_FUNC(wait, woken_wake_function);
cw.ino = inode->i_ino;
cw.ino = ceph_ino(inode); cw.tgid = current->tgid; cw.need = need; cw.want = want;
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 070ed84813406..74747d8d48619 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -212,7 +212,7 @@ static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) { struct seq_file *s = p;
seq_printf(s, "0x%-17lx%-17s%-17s\n", inode->i_ino,
seq_printf(s, "0x%-17llx%-17s%-17s\n", ceph_ino(inode), ceph_cap_string(cap->issued), ceph_cap_string(cap->implemented)); return 0;
@@ -257,7 +257,7 @@ static int caps_show(struct seq_file *s, void *p)
spin_lock(&mdsc->caps_list_lock); list_for_each_entry(cw, &mdsc->cap_wait_list, list) {
seq_printf(s, "%-13d0x%-17lx%-17s%-17s\n", cw->tgid, cw->ino,
seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino, ceph_cap_string(cw->need), ceph_cap_string(cw->want)); }
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 060bdcc5ce32c..040eaad9d0631 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -259,9 +259,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx, dentry, dentry, d_inode(dentry)); ctx->pos = di->offset; if (!dir_emit(ctx, dentry->d_name.name,
dentry->d_name.len,
ceph_translate_ino(dentry->d_sb,
d_inode(dentry)->i_ino),
dentry->d_name.len, ceph_present_inode(d_inode(dentry)), d_inode(dentry)->i_mode >> 12)) { dput(dentry); err = 0;
@@ -324,18 +322,21 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) /* always start with . and .. */ if (ctx->pos == 0) { dout("readdir off 0 -> '.'\n");
if (!dir_emit(ctx, ".", 1,
ceph_translate_ino(inode->i_sb, inode->i_ino),
if (!dir_emit(ctx, ".", 1, ceph_present_inode(inode), inode->i_mode >> 12)) return 0; ctx->pos = 1; } if (ctx->pos == 1) {
ino_t ino = parent_ino(file->f_path.dentry);
u64 ino;
struct dentry *dentry = file->f_path.dentry;
spin_lock(&dentry->d_lock);
ino = ceph_present_inode(dentry->d_parent->d_inode);
spin_unlock(&dentry->d_lock);
dout("readdir off 1 -> '..'\n");
if (!dir_emit(ctx, "..", 2,
ceph_translate_ino(inode->i_sb, ino),
inode->i_mode >> 12))
if (!dir_emit(ctx, "..", 2, ino, inode->i_mode >> 12)) return 0; ctx->pos = 2; }
@@ -507,9 +508,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) } for (; i < rinfo->dir_nr; i++) { struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
struct ceph_vino vino;
ino_t ino;
u32 ftype; BUG_ON(rde->offset < ctx->pos);
@@ -519,13 +517,10 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) rde->name_len, rde->name, &rde->inode.in);
BUG_ON(!rde->inode.in);
ftype = le32_to_cpu(rde->inode.in->mode) >> 12;
vino.ino = le64_to_cpu(rde->inode.in->ino);
vino.snap = le64_to_cpu(rde->inode.in->snapid);
ino = ceph_vino_to_ino(vino); if (!dir_emit(ctx, rde->name, rde->name_len,
ceph_translate_ino(inode->i_sb, ino), ftype)) {
ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)),
le32_to_cpu(rde->inode.in->mode) >> 12)) { dout("filldir stopping us...\n"); return 0; }
@@ -1161,7 +1156,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
if (try_async && op == CEPH_MDS_OP_UNLINK && (req->r_dir_caps = get_caps_for_async_unlink(dir, dentry))) {
dout("async unlink on %lu/%.*s caps=%s", dir->i_ino,
dout("async unlink on %llu/%.*s caps=%s", ceph_ino(dir), dentry->d_name.len, dentry->d_name.name, ceph_cap_string(req->r_dir_caps)); set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 160644ddaeed7..26172bb90a459 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -630,8 +630,8 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, } else { struct dentry *dn;
dout("%s d_adding new inode 0x%llx to 0x%lx/%s\n", __func__,
vino.ino, dir->i_ino, dentry->d_name.name);
dout("%s d_adding new inode 0x%llx to 0x%llx/%s\n", __func__,
vino.ino, ceph_ino(dir), dentry->d_name.name); ceph_dir_clear_ordered(dir); ceph_init_inode_acls(inode, as_ctx); if (inode->i_state & I_NEW) {
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 357c937699d56..d163fa96cb401 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -41,8 +41,10 @@ static void ceph_inode_work(struct work_struct *work); */ static int ceph_set_ino_cb(struct inode *inode, void *data) {
ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
struct ceph_inode_info *ci = ceph_inode(inode);
ci->i_vino = *(struct ceph_vino *)data;
inode->i_ino = ceph_vino_to_ino_t(ci->i_vino); inode_set_iversion_raw(inode, 0); return 0;
} @@ -50,17 +52,14 @@ static int ceph_set_ino_cb(struct inode *inode, void *data) struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino) { struct inode *inode;
ino_t t = ceph_vino_to_ino(vino);
inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino);
inode = iget5_locked(sb, (unsigned long)vino.ino, ceph_ino_compare,
ceph_set_ino_cb, &vino); if (!inode) return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW)
dout("get_inode created new inode %p %llx.%llx ino %llx\n",
inode, ceph_vinop(inode), (u64)inode->i_ino);
dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino,
vino.snap, inode);
dout("get_inode on %llu=%llx.%llx got %p new %d\n", ceph_present_inode(inode),
ceph_vinop(inode), inode, !!(inode->i_state & I_NEW)); return inode;
}
@@ -2378,7 +2377,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat, }
generic_fillattr(inode, stat);
stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
stat->ino = ceph_present_inode(inode); /* * btime on newly-allocated inodes is 0, so if this is still set to
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 5e0c4073a6bea..63c9cd1c28d6c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -369,7 +369,7 @@ struct ceph_quotarealm_inode {
struct cap_wait { struct list_head list;
unsigned long ino;
u64 ino; pid_t tgid; int need; int want;
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 198ddde5c1e6a..cc2c4d40b0222 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -23,12 +23,12 @@ static inline bool ceph_has_realms_with_quotas(struct inode *inode) { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct super_block *sb = mdsc->fsc->sb;
struct inode *root = d_inode(sb->s_root); if (atomic64_read(&mdsc->quotarealms_count) > 0) return true; /* if root is the real CephFS root, we don't have quota realms */
if (sb->s_root->d_inode &&
(sb->s_root->d_inode->i_ino == CEPH_INO_ROOT))
if (root && ceph_ino(root) == CEPH_INO_ROOT) return false; /* otherwise, we can't know for sure */ return true;
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 5a6cdd39bc103..2af3e06a6d0ce 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -457,15 +457,7 @@ ceph_vino(const struct inode *inode) return ceph_inode(inode)->i_vino; }
-/*
- ino_t is <64 bits on many architectures, blech.
i_ino (kernel inode) st_ino (userspace)
- i386 32 32
- x86_64+ino32 64 32
- x86_64 64 64
- */
-static inline u32 ceph_ino_to_ino32(__u64 vino) +static inline u32 ceph_ino_to_ino32(u64 vino) { u32 ino = vino & 0xffffffff; ino ^= vino >> 32; @@ -475,34 +467,17 @@ static inline u32 ceph_ino_to_ino32(__u64 vino) }
/*
- kernel i_ino value
- Inode numbers in cephfs are 64 bits, but inode->i_ino is 32-bits on
- some arches. We generally do not use this value inside the ceph driver, but
- we do want to set it to something, so that generic vfs code has an
*/
- appropriate value for tracepoints and the like.
-static inline ino_t ceph_vino_to_ino(struct ceph_vino vino) +static inline ino_t ceph_vino_to_ino_t(struct ceph_vino vino) { -#if BITS_PER_LONG == 32
return ceph_ino_to_ino32(vino.ino);
-#else
if (sizeof(ino_t) == sizeof(u32))
return ceph_ino_to_ino32(vino.ino); return (ino_t)vino.ino;
-#endif -}
-/*
- user-visible ino (stat, filldir)
- */
-#if BITS_PER_LONG == 32 -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{
return ino;
-} -#else -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{
if (ceph_test_mount_opt(ceph_sb_to_client(sb), INO32))
ino = ceph_ino_to_ino32(ino);
return ino;
} -#endif
/* for printf-style formatting */ #define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap @@ -511,11 +486,34 @@ static inline u64 ceph_ino(struct inode *inode) { return ceph_inode(inode)->i_vino.ino; }
static inline u64 ceph_snap(struct inode *inode) { return ceph_inode(inode)->i_vino.snap; }
+/**
- ceph_present_ino - format an inode number for presentation to userland
- @sb: superblock where the inode lives
- @ino: inode number to (possibly) convert
- If the user mounted with the ino32 option, then the 64-bit value needs
- to be converted to something that can fit inside 32 bits. Note that
- internal kernel code never uses this value, so this is entirely for
- userland consumption.
- */
+static inline u64 ceph_present_ino(struct super_block *sb, u64 ino) +{
if (unlikely(ceph_test_mount_opt(ceph_sb_to_client(sb), INO32)))
return ceph_ino_to_ino32(ino);
return ino;
+}
+static inline u64 ceph_present_inode(struct inode *inode) +{
return ceph_present_ino(inode->i_sb, ceph_ino(inode));
+}
static inline int ceph_ino_compare(struct inode *inode, void *data) { struct ceph_vino *pvino = (struct ceph_vino *)data; @@ -524,11 +522,16 @@ static inline int ceph_ino_compare(struct inode *inode, void *data) ci->i_vino.snap == pvino->snap; }
static inline struct inode *ceph_find_inode(struct super_block *sb, struct ceph_vino vino) {
ino_t t = ceph_vino_to_ino(vino);
return ilookup5(sb, t, ceph_ino_compare, &vino);
/*
* NB: The hashval will be run through the fs/inode.c hash function
* anyway, so there is no need to squash the inode number down to
* 32-bits first. Just use low-order bits on arches with 32-bit long.
*/
return ilookup5(sb, (unsigned long)vino.ino, ceph_ino_compare, &vino);
}
-- 2.25.1
Hi Sasha,
This is a user-visible change and wasn't marked for stable for that reason. Please drop it.
Thanks,
Ilya
On Mon, Aug 31, 2020 at 06:08:32PM +0200, Ilya Dryomov wrote:
On Mon, Aug 31, 2020 at 5:30 PM Sasha Levin sashal@kernel.org wrote:
From: Jeff Layton jlayton@kernel.org
[ Upstream commit ebce3eb2f7ef9f6ef01a60874ebd232450107c9a ]
Tuan and Ulrich mentioned that they were hitting a problem on s390x, which has a 32-bit ino_t value, even though it's a 64-bit arch (for historical reasons).
I think the current handling of inode numbers in the ceph driver is wrong. It tries to use 32-bit inode numbers on 32-bit arches, but that's actually not a problem. 32-bit arches can deal with 64-bit inode numbers just fine when userland code is compiled with LFS support (the common case these days).
What we really want to do is just use 64-bit numbers everywhere, unless someone has mounted with the ino32 mount option. In that case, we want to ensure that we hash the inode number down to something that will fit in 32 bits before presenting the value to userland.
Add new helper functions that do this, and only do the conversion before presenting these values to userland in getattr and readdir.
The inode table hashvalue is changed to just cast the inode number to unsigned long, as low-order bits are the most likely to vary anyway.
While it's not strictly required, we do want to put something in inode->i_ino. Instead of basing it on BITS_PER_LONG, however, base it on the size of the ino_t type.
NOTE: This is a user-visible change on 32-bit arches:
1/ inode numbers will be seen to have changed between kernel versions. 32-bit arches will see large inode numbers now instead of the hashed ones they saw before.
2/ any really old software not built with LFS support may start failing stat() calls with -EOVERFLOW on inode numbers >2^32. Nothing much we can do about these, but hopefully the intersection of people running such code on ceph will be very small.
The workaround for both problems is to mount with "-o ino32".
[ idryomov: changelog tweak ]
URL: https://tracker.ceph.com/issues/46828 Reported-by: Ulrich Weigand Ulrich.Weigand@de.ibm.com Reported-and-Tested-by: Tuan Hoang1 Tuan.Hoang1@ibm.com Signed-off-by: Jeff Layton jlayton@kernel.org Reviewed-by: "Yan, Zheng" zyan@redhat.com Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org
fs/ceph/caps.c | 14 ++++----- fs/ceph/debugfs.c | 4 +-- fs/ceph/dir.c | 31 ++++++++----------- fs/ceph/file.c | 4 +-- fs/ceph/inode.c | 19 ++++++------ fs/ceph/mds_client.h | 2 +- fs/ceph/quota.c | 4 +-- fs/ceph/super.h | 73 +++++++++++++++++++++++--------------------- 8 files changed, 74 insertions(+), 77 deletions(-)
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 972c13aa42259..1206a481c5fc7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -886,8 +886,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) int have = ci->i_snap_caps;
if ((have & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino,
dout("__ceph_caps_issued_mask ino 0x%llx snap issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(have), ceph_cap_string(mask)); return 1;
@@ -898,8 +898,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) if (!__cap_is_valid(cap)) continue; if ((cap->issued & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino, cap,
dout("__ceph_caps_issued_mask ino 0x%llx cap %p issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), cap, ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch)
@@ -910,8 +910,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) /* does a combination of caps satisfy mask? */ have |= cap->issued; if ((have & mask) == mask) {
dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s"
" (mask %s)\n", ci->vfs_inode.i_ino,
dout("__ceph_caps_issued_mask ino 0x%llx combo issued %s"
" (mask %s)\n", ceph_ino(&ci->vfs_inode), ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch) {
@@ -2870,7 +2870,7 @@ int ceph_get_caps(struct file *filp, int need, int want, struct cap_wait cw; DEFINE_WAIT_FUNC(wait, woken_wake_function);
cw.ino = inode->i_ino;
cw.ino = ceph_ino(inode); cw.tgid = current->tgid; cw.need = need; cw.want = want;
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 070ed84813406..74747d8d48619 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -212,7 +212,7 @@ static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) { struct seq_file *s = p;
seq_printf(s, "0x%-17lx%-17s%-17s\n", inode->i_ino,
seq_printf(s, "0x%-17llx%-17s%-17s\n", ceph_ino(inode), ceph_cap_string(cap->issued), ceph_cap_string(cap->implemented)); return 0;
@@ -257,7 +257,7 @@ static int caps_show(struct seq_file *s, void *p)
spin_lock(&mdsc->caps_list_lock); list_for_each_entry(cw, &mdsc->cap_wait_list, list) {
seq_printf(s, "%-13d0x%-17lx%-17s%-17s\n", cw->tgid, cw->ino,
seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino, ceph_cap_string(cw->need), ceph_cap_string(cw->want)); }
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 060bdcc5ce32c..040eaad9d0631 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -259,9 +259,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx, dentry, dentry, d_inode(dentry)); ctx->pos = di->offset; if (!dir_emit(ctx, dentry->d_name.name,
dentry->d_name.len,
ceph_translate_ino(dentry->d_sb,
d_inode(dentry)->i_ino),
dentry->d_name.len, ceph_present_inode(d_inode(dentry)), d_inode(dentry)->i_mode >> 12)) { dput(dentry); err = 0;
@@ -324,18 +322,21 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) /* always start with . and .. */ if (ctx->pos == 0) { dout("readdir off 0 -> '.'\n");
if (!dir_emit(ctx, ".", 1,
ceph_translate_ino(inode->i_sb, inode->i_ino),
if (!dir_emit(ctx, ".", 1, ceph_present_inode(inode), inode->i_mode >> 12)) return 0; ctx->pos = 1; } if (ctx->pos == 1) {
ino_t ino = parent_ino(file->f_path.dentry);
u64 ino;
struct dentry *dentry = file->f_path.dentry;
spin_lock(&dentry->d_lock);
ino = ceph_present_inode(dentry->d_parent->d_inode);
spin_unlock(&dentry->d_lock);
dout("readdir off 1 -> '..'\n");
if (!dir_emit(ctx, "..", 2,
ceph_translate_ino(inode->i_sb, ino),
inode->i_mode >> 12))
if (!dir_emit(ctx, "..", 2, ino, inode->i_mode >> 12)) return 0; ctx->pos = 2; }
@@ -507,9 +508,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) } for (; i < rinfo->dir_nr; i++) { struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
struct ceph_vino vino;
ino_t ino;
u32 ftype; BUG_ON(rde->offset < ctx->pos);
@@ -519,13 +517,10 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) rde->name_len, rde->name, &rde->inode.in);
BUG_ON(!rde->inode.in);
ftype = le32_to_cpu(rde->inode.in->mode) >> 12;
vino.ino = le64_to_cpu(rde->inode.in->ino);
vino.snap = le64_to_cpu(rde->inode.in->snapid);
ino = ceph_vino_to_ino(vino); if (!dir_emit(ctx, rde->name, rde->name_len,
ceph_translate_ino(inode->i_sb, ino), ftype)) {
ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)),
le32_to_cpu(rde->inode.in->mode) >> 12)) { dout("filldir stopping us...\n"); return 0; }
@@ -1161,7 +1156,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
if (try_async && op == CEPH_MDS_OP_UNLINK && (req->r_dir_caps = get_caps_for_async_unlink(dir, dentry))) {
dout("async unlink on %lu/%.*s caps=%s", dir->i_ino,
dout("async unlink on %llu/%.*s caps=%s", ceph_ino(dir), dentry->d_name.len, dentry->d_name.name, ceph_cap_string(req->r_dir_caps)); set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 160644ddaeed7..26172bb90a459 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -630,8 +630,8 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, } else { struct dentry *dn;
dout("%s d_adding new inode 0x%llx to 0x%lx/%s\n", __func__,
vino.ino, dir->i_ino, dentry->d_name.name);
dout("%s d_adding new inode 0x%llx to 0x%llx/%s\n", __func__,
vino.ino, ceph_ino(dir), dentry->d_name.name); ceph_dir_clear_ordered(dir); ceph_init_inode_acls(inode, as_ctx); if (inode->i_state & I_NEW) {
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 357c937699d56..d163fa96cb401 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -41,8 +41,10 @@ static void ceph_inode_work(struct work_struct *work); */ static int ceph_set_ino_cb(struct inode *inode, void *data) {
ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
struct ceph_inode_info *ci = ceph_inode(inode);
ci->i_vino = *(struct ceph_vino *)data;
inode->i_ino = ceph_vino_to_ino_t(ci->i_vino); inode_set_iversion_raw(inode, 0); return 0;
} @@ -50,17 +52,14 @@ static int ceph_set_ino_cb(struct inode *inode, void *data) struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino) { struct inode *inode;
ino_t t = ceph_vino_to_ino(vino);
inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino);
inode = iget5_locked(sb, (unsigned long)vino.ino, ceph_ino_compare,
ceph_set_ino_cb, &vino); if (!inode) return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW)
dout("get_inode created new inode %p %llx.%llx ino %llx\n",
inode, ceph_vinop(inode), (u64)inode->i_ino);
dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino,
vino.snap, inode);
dout("get_inode on %llu=%llx.%llx got %p new %d\n", ceph_present_inode(inode),
ceph_vinop(inode), inode, !!(inode->i_state & I_NEW)); return inode;
}
@@ -2378,7 +2377,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat, }
generic_fillattr(inode, stat);
stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
stat->ino = ceph_present_inode(inode); /* * btime on newly-allocated inodes is 0, so if this is still set to
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 5e0c4073a6bea..63c9cd1c28d6c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -369,7 +369,7 @@ struct ceph_quotarealm_inode {
struct cap_wait { struct list_head list;
unsigned long ino;
u64 ino; pid_t tgid; int need; int want;
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 198ddde5c1e6a..cc2c4d40b0222 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -23,12 +23,12 @@ static inline bool ceph_has_realms_with_quotas(struct inode *inode) { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct super_block *sb = mdsc->fsc->sb;
struct inode *root = d_inode(sb->s_root); if (atomic64_read(&mdsc->quotarealms_count) > 0) return true; /* if root is the real CephFS root, we don't have quota realms */
if (sb->s_root->d_inode &&
(sb->s_root->d_inode->i_ino == CEPH_INO_ROOT))
if (root && ceph_ino(root) == CEPH_INO_ROOT) return false; /* otherwise, we can't know for sure */ return true;
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 5a6cdd39bc103..2af3e06a6d0ce 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -457,15 +457,7 @@ ceph_vino(const struct inode *inode) return ceph_inode(inode)->i_vino; }
-/*
- ino_t is <64 bits on many architectures, blech.
i_ino (kernel inode) st_ino (userspace)
- i386 32 32
- x86_64+ino32 64 32
- x86_64 64 64
- */
-static inline u32 ceph_ino_to_ino32(__u64 vino) +static inline u32 ceph_ino_to_ino32(u64 vino) { u32 ino = vino & 0xffffffff; ino ^= vino >> 32; @@ -475,34 +467,17 @@ static inline u32 ceph_ino_to_ino32(__u64 vino) }
/*
- kernel i_ino value
- Inode numbers in cephfs are 64 bits, but inode->i_ino is 32-bits on
- some arches. We generally do not use this value inside the ceph driver, but
- we do want to set it to something, so that generic vfs code has an
*/
- appropriate value for tracepoints and the like.
-static inline ino_t ceph_vino_to_ino(struct ceph_vino vino) +static inline ino_t ceph_vino_to_ino_t(struct ceph_vino vino) { -#if BITS_PER_LONG == 32
return ceph_ino_to_ino32(vino.ino);
-#else
if (sizeof(ino_t) == sizeof(u32))
return ceph_ino_to_ino32(vino.ino); return (ino_t)vino.ino;
-#endif -}
-/*
- user-visible ino (stat, filldir)
- */
-#if BITS_PER_LONG == 32 -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{
return ino;
-} -#else -static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino) -{
if (ceph_test_mount_opt(ceph_sb_to_client(sb), INO32))
ino = ceph_ino_to_ino32(ino);
return ino;
} -#endif
/* for printf-style formatting */ #define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap @@ -511,11 +486,34 @@ static inline u64 ceph_ino(struct inode *inode) { return ceph_inode(inode)->i_vino.ino; }
static inline u64 ceph_snap(struct inode *inode) { return ceph_inode(inode)->i_vino.snap; }
+/**
- ceph_present_ino - format an inode number for presentation to userland
- @sb: superblock where the inode lives
- @ino: inode number to (possibly) convert
- If the user mounted with the ino32 option, then the 64-bit value needs
- to be converted to something that can fit inside 32 bits. Note that
- internal kernel code never uses this value, so this is entirely for
- userland consumption.
- */
+static inline u64 ceph_present_ino(struct super_block *sb, u64 ino) +{
if (unlikely(ceph_test_mount_opt(ceph_sb_to_client(sb), INO32)))
return ceph_ino_to_ino32(ino);
return ino;
+}
+static inline u64 ceph_present_inode(struct inode *inode) +{
return ceph_present_ino(inode->i_sb, ceph_ino(inode));
+}
static inline int ceph_ino_compare(struct inode *inode, void *data) { struct ceph_vino *pvino = (struct ceph_vino *)data; @@ -524,11 +522,16 @@ static inline int ceph_ino_compare(struct inode *inode, void *data) ci->i_vino.snap == pvino->snap; }
static inline struct inode *ceph_find_inode(struct super_block *sb, struct ceph_vino vino) {
ino_t t = ceph_vino_to_ino(vino);
return ilookup5(sb, t, ceph_ino_compare, &vino);
/*
* NB: The hashval will be run through the fs/inode.c hash function
* anyway, so there is no need to squash the inode number down to
* 32-bits first. Just use low-order bits on arches with 32-bit long.
*/
return ilookup5(sb, (unsigned long)vino.ino, ceph_ino_compare, &vino);
}
-- 2.25.1
Hi Sasha,
This is a user-visible change and wasn't marked for stable for that reason. Please drop it.
Dropped, thanks!
From: Jeff Layton jlayton@kernel.org
[ Upstream commit 496ceaf12432b3d136dcdec48424312e71359ea7 ]
Leases don't currently work correctly on kcephfs, as they are not broken when caps are revoked. They could eventually be implemented similarly to how we did them in libcephfs, but for now don't allow them.
[ idryomov: no need for simple_nosetlease() in ceph_dir_fops and ceph_snapdir_fops ]
Signed-off-by: Jeff Layton jlayton@kernel.org Reviewed-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/ceph/file.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 26172bb90a459..c53c1499f7c58 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -2506,6 +2506,7 @@ const struct file_operations ceph_file_fops = { .mmap = ceph_mmap, .fsync = ceph_fsync, .lock = ceph_lock, + .setlease = simple_nosetlease, .flock = ceph_flock, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write,
From: Ray Jui ray.jui@broadcom.com
[ Upstream commit 0204081128d582965e9e39ca83ee6e4f7d27142b ]
Fix undefined behaviour in the iProc I2C driver by using 'BIT' marcro.
Reported-by: Wolfram Sang wsa@kernel.org Signed-off-by: Ray Jui ray.jui@broadcom.com Acked-by: Florian Fainelli f.fainelli@gmail.com [wsa: in commit msg, don't say 'checkpatch' but name the issue] Signed-off-by: Wolfram Sang wsa@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/i2c/busses/i2c-bcm-iproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 688e928188214..d8295b1c379d1 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -720,7 +720,7 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
/* mark the last byte */ if (!process_call && (i == msg->len - 1)) - val |= 1 << M_TX_WR_STATUS_SHIFT; + val |= BIT(M_TX_WR_STATUS_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val); } @@ -738,7 +738,7 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c, */ addr = i2c_8bit_addr_from_msg(msg); /* mark it the last byte out */ - val = addr | (1 << M_TX_WR_STATUS_SHIFT); + val = addr | BIT(M_TX_WR_STATUS_SHIFT); iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val); }
From: Tomi Valkeinen tomi.valkeinen@ti.com
[ Upstream commit 7fd5b25499bcec157dd4de9a713425efcf4571cd ]
After commit 92cc68e35863c1c61c449efa2b2daef6e9926048 ("drm/vblank: Use spin_(un)lock_irq() in drm_crtc_vblank_on()") omapdrm locking is broken:
WARNING: inconsistent lock state 5.8.0-rc2-00483-g92cc68e35863 #13 Tainted: G W -------------------------------- inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. swapper/0/0 [HC1[1]:SC0[0]:HE0:SE1] takes: ea98222c (&dev->event_lock#2){?.+.}-{2:2}, at: drm_handle_vblank+0x4c/0x520 [drm] {HARDIRQ-ON-W} state was registered at: trace_hardirqs_on+0x9c/0x1ec _raw_spin_unlock_irq+0x20/0x58 omap_crtc_atomic_enable+0x54/0xa0 [omapdrm] drm_atomic_helper_commit_modeset_enables+0x218/0x270 [drm_kms_helper] omap_atomic_commit_tail+0x48/0xc4 [omapdrm] commit_tail+0x9c/0x190 [drm_kms_helper] drm_atomic_helper_commit+0x154/0x188 [drm_kms_helper] drm_client_modeset_commit_atomic+0x228/0x268 [drm] drm_client_modeset_commit_locked+0x60/0x1d0 [drm] drm_client_modeset_commit+0x24/0x40 [drm] drm_fb_helper_restore_fbdev_mode_unlocked+0x54/0xa8 [drm_kms_helper] drm_fb_helper_set_par+0x2c/0x5c [drm_kms_helper] drm_fb_helper_hotplug_event.part.0+0xa0/0xbc [drm_kms_helper] drm_kms_helper_hotplug_event+0x24/0x30 [drm_kms_helper] output_poll_execute+0x1a8/0x1c0 [drm_kms_helper] process_one_work+0x268/0x800 worker_thread+0x30/0x4e0 kthread+0x164/0x190 ret_from_fork+0x14/0x20
The reason for this is that omapdrm calls drm_crtc_vblank_on() while holding event_lock taken with spin_lock_irq().
It is not clear why drm_crtc_vblank_on() and drm_crtc_vblank_get() are called while holding event_lock. I don't see any problem with moving those calls outside the lock, which is what this patch does.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ti.com Link: https://patchwork.freedesktop.org/patch/msgid/20200819103021.440288-1-tomi.v... Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/omapdrm/omap_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index fce7e944a280b..dbf91b3fd6f08 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -451,11 +451,12 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc, if (omap_state->manually_updated) return;
- spin_lock_irq(&crtc->dev->event_lock); drm_crtc_vblank_on(crtc); + ret = drm_crtc_vblank_get(crtc); WARN_ON(ret != 0);
+ spin_lock_irq(&crtc->dev->event_lock); omap_crtc_arm_event(crtc); spin_unlock_irq(&crtc->dev->event_lock); }
From: Paul Cercueil paul@crapouillou.net
[ Upstream commit 821fc9e261f3af235752f46e59084467cfd440c4 ]
All the wakeup sources we possibly want will go through the interrupt controller, so the parent IRQ must not be masked during suspend, or there won't be any way to wake up the system.
Signed-off-by: Paul Cercueil paul@crapouillou.net Signed-off-by: Marc Zyngier maz@kernel.org Link: https://lore.kernel.org/r/20200819180602.136969-1-paul@crapouillou.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/irqchip/irq-ingenic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c index 9f3da4260ca65..b61a8901ef722 100644 --- a/drivers/irqchip/irq-ingenic.c +++ b/drivers/irqchip/irq-ingenic.c @@ -125,7 +125,7 @@ static int __init ingenic_intc_of_init(struct device_node *node, irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK); }
- if (request_irq(parent_irq, intc_cascade, 0, + if (request_irq(parent_irq, intc_cascade, IRQF_NO_SUSPEND, "SoC intc cascade interrupt", NULL)) pr_err("Failed to register SoC intc cascade interrupt\n"); return 0;
From: Peter Zijlstra peterz@infradead.org
[ Upstream commit 49d9c5936314e44d314c605c39cce0fd947f9c3a ]
Match the pattern elsewhere in this file.
Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Reviewed-by: Steven Rostedt (VMware) rostedt@goodmis.org Reviewed-by: Thomas Gleixner tglx@linutronix.de Acked-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Tested-by: Marco Elver elver@google.com Link: https://lkml.kernel.org/r/20200821085348.251340558@infradead.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/cpuidle/cpuidle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 87197319ab069..2fe4f3cdf54d7 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -153,7 +153,8 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, */ stop_critical_timings(); drv->states[index].enter_s2idle(dev, drv, index); - WARN_ON(!irqs_disabled()); + if (WARN_ON_ONCE(!irqs_disabled())) + local_irq_disable(); /* * timekeeping_resume() that will be called by tick_unfreeze() for the * first CPU executing it calls functions containing RCU read-side
From: Hou Pu houpu@bytedance.com
[ Upstream commit acb19e17c5134dd78668c429ecba5b481f038e6a ]
If we configured io timeout of nbd0 to 100s. Later after we finished using it, we configured nbd0 again and set the io timeout to 0. We expect it would timeout after 30 seconds and keep retry. But in fact we could not change the timeout when we set it to 0. the timeout is still the original 100s.
So change the timeout to default 30s when we set it to zero. It also behaves same as commit 2da22da57348 ("nbd: fix zero cmd timeout handling v2").
It becomes more important if we were reconfigure a nbd device and the io timeout it set to zero. Because it could take 30s to detect the new socket and thus io could be completed more quickly compared to 100s.
Signed-off-by: Hou Pu houpu@bytedance.com Reviewed-by: Josef Bacik josef@toxicpanda.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/block/nbd.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index ce7e9f223b20b..bc9dc1f847e19 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1360,6 +1360,8 @@ static void nbd_set_cmd_timeout(struct nbd_device *nbd, u64 timeout) nbd->tag_set.timeout = timeout * HZ; if (timeout) blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ); + else + blk_queue_rq_timeout(nbd->disk->queue, 30 * HZ); }
/* Must be called with config_lock held */
From: Sven Schnelle svens@linux.ibm.com
[ Upstream commit 1196f12a2c960951d02262af25af0bb1775ebcc2 ]
Since commit a21ee6055c30 ("lockdep: Change hardirq{s_enabled,_context} to per-cpu variables") the lockdep code itself uses percpu variables. This leads to recursions because the percpu macros are calling preempt_enable() which might call trace_preempt_on().
Signed-off-by: Sven Schnelle svens@linux.ibm.com Reviewed-by: Vasily Gorbik gor@linux.ibm.com Signed-off-by: Vasily Gorbik gor@linux.ibm.com Signed-off-by: Sasha Levin sashal@kernel.org --- arch/s390/include/asm/percpu.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index 50b4ce8cddfdc..918f0ba4f4d20 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h @@ -29,7 +29,7 @@ typedef typeof(pcp) pcp_op_T__; \ pcp_op_T__ old__, new__, prev__; \ pcp_op_T__ *ptr__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ prev__ = *ptr__; \ do { \ @@ -37,7 +37,7 @@ new__ = old__ op (val); \ prev__ = cmpxchg(ptr__, old__, new__); \ } while (prev__ != old__); \ - preempt_enable(); \ + preempt_enable_notrace(); \ new__; \ })
@@ -68,7 +68,7 @@ typedef typeof(pcp) pcp_op_T__; \ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ if (__builtin_constant_p(val__) && \ ((szcast)val__ > -129) && ((szcast)val__ < 128)) { \ @@ -84,7 +84,7 @@ : [val__] "d" (val__) \ : "cc"); \ } \ - preempt_enable(); \ + preempt_enable_notrace(); \ }
#define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int) @@ -95,14 +95,14 @@ typedef typeof(pcp) pcp_op_T__; \ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ op " %[old__],%[val__],%[ptr__]\n" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ : [val__] "d" (val__) \ : "cc"); \ - preempt_enable(); \ + preempt_enable_notrace(); \ old__ + val__; \ })
@@ -114,14 +114,14 @@ typedef typeof(pcp) pcp_op_T__; \ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ op " %[old__],%[val__],%[ptr__]\n" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ : [val__] "d" (val__) \ : "cc"); \ - preempt_enable(); \ + preempt_enable_notrace(); \ }
#define this_cpu_and_4(pcp, val) arch_this_cpu_to_op(pcp, val, "lan") @@ -136,10 +136,10 @@ typedef typeof(pcp) pcp_op_T__; \ pcp_op_T__ ret__; \ pcp_op_T__ *ptr__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ ret__ = cmpxchg(ptr__, oval, nval); \ - preempt_enable(); \ + preempt_enable_notrace(); \ ret__; \ })
@@ -152,10 +152,10 @@ ({ \ typeof(pcp) *ptr__; \ typeof(pcp) ret__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ ret__ = xchg(ptr__, nval); \ - preempt_enable(); \ + preempt_enable_notrace(); \ ret__; \ })
@@ -171,11 +171,11 @@ typeof(pcp1) *p1__; \ typeof(pcp2) *p2__; \ int ret__; \ - preempt_disable(); \ + preempt_disable_notrace(); \ p1__ = raw_cpu_ptr(&(pcp1)); \ p2__ = raw_cpu_ptr(&(pcp2)); \ ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__); \ - preempt_enable(); \ + preempt_enable_notrace(); \ ret__; \ })
From: Tong Zhang ztong0001@gmail.com
[ Upstream commit ed9ab229fea24cbcab17f484297dc8344afb7ea9 ]
core_link_read_dpcd returns only DC_OK(1) and DC_ERROR_UNEXPECTED(-1), the caller should check error using DC_OK instead of checking against 0
Signed-off-by: Tong Zhang ztong0001@gmail.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 91cd884d6f257..7728fd71d1f3a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -4346,9 +4346,9 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link, link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) return false;
- if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK, + if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK, dpcd_backlight_get.raw, - sizeof(union dpcd_source_backlight_get))) + sizeof(union dpcd_source_backlight_get)) != DC_OK) return false;
*backlight_millinits_avg = @@ -4387,9 +4387,9 @@ bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_milli link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) return false;
- if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, + if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, (uint8_t *) backlight_millinits, - sizeof(uint32_t))) + sizeof(uint32_t)) != DC_OK) return false;
return true;
From: Nicholas Kazlauskas nicholas.kazlauskas@amd.com
[ Upstream commit 168f09cdadbd547c2b202246ef9a8183da725f13 ]
[Why] These aren't stable on some platform configurations when driving multiple displays, especially on higher resolution.
In particular the delay in asserting p-state and validating from x86 outweights any power or performance benefit from the hardware composition.
Under some configurations this will manifest itself as extreme stutter or unresponsiveness especially when combined with cursor movement.
[How] Disable these for now. Exposing overlays to userspace doesn't guarantee that they'll be able to use them in any and all configurations and it's part of the DRM contract to have userspace gracefully handle validation failures when they occur.
Valdiation occurs as part of DC and this in particular affects RV, so disable this in dcn10_global_validation.
Signed-off-by: Nicholas Kazlauskas nicholas.kazlauskas@amd.com Reviewed-by: Hersen Wu hersenxs.wu@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 17d5cb422025e..8939541ad7afc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1213,6 +1213,7 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont bool video_large = false; bool desktop_large = false; bool dcc_disabled = false; + bool mpo_enabled = false;
for (i = 0; i < context->stream_count; i++) { if (context->stream_status[i].plane_count == 0) @@ -1221,6 +1222,9 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont if (context->stream_status[i].plane_count > 2) return DC_FAIL_UNSUPPORTED_1;
+ if (context->stream_status[i].plane_count > 1) + mpo_enabled = true; + for (j = 0; j < context->stream_status[i].plane_count; j++) { struct dc_plane_state *plane = context->stream_status[i].plane_states[j]; @@ -1244,6 +1248,10 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont } }
+ /* Disable MPO in multi-display configurations. */ + if (context->stream_count > 1 && mpo_enabled) + return DC_FAIL_UNSUPPORTED_1; + /* * Workaround: On DCN10 there is UMC issue that causes underflow when * playing 4k video on 4k desktop with video downscaled and single channel
From: Furquan Shaikh furquan@google.com
[ Upstream commit 5896585512e5156482335e902f7c7393b940da51 ]
In `amdgpu_dm_update_backlight_caps()`, there is a local `amdgpu_dm_backlight_caps` object that is filled in by `amdgpu_acpi_get_backlight_caps()`. However, this object is uninitialized before the call and hence the subsequent check for aux_support can fail since it is not initialized by `amdgpu_acpi_get_backlight_caps()` as well. This change initializes this local `amdgpu_dm_backlight_caps` object to 0.
Reviewed-by: Christian König christian.koenig@amd.com Signed-off-by: Furquan Shaikh furquan@google.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0a39a8558b294..0682fd363cb50 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2844,6 +2844,8 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm) #if defined(CONFIG_ACPI) struct amdgpu_dm_backlight_caps caps;
+ memset(&caps, 0, sizeof(caps)); + if (dm->backlight_caps.caps_valid) return;
From: Jaehyun Chung jaehyun.chung@amd.com
[ Upstream commit b61f05622ace5b9498ae279cdfd1c9f0c1ce3f75 ]
[Why] Revert HDCP disable sequence change that blanks stream before disabling HDCP. PSP and HW teams are currently investigating the root cause of why HDCP cannot be disabled before stream blank, which is expected to work without issues.
Signed-off-by: Jaehyun Chung jaehyun.chung@amd.com Reviewed-by: Wenjing Liu Wenjing.Liu@amd.com Acked-by: Eryk Brol eryk.brol@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 31aa31c280ee6..bdddb46727b1f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3265,10 +3265,10 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) core_link_set_avmute(pipe_ctx, true); }
- dc->hwss.blank_stream(pipe_ctx); #if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, true); #endif + dc->hwss.blank_stream(pipe_ctx);
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx);
From: Samson Tam Samson.Tam@amd.com
[ Upstream commit efbde23a3b0164cef27fd394e7d548f46af5b51d ]
[Why] dongle_type is set during dongle connection but for passive dongles, dongle_type is not set. If user starts with an active dongle and then switches to a passive dongle, it will still report as an active dongle. Trying to emulate the wrong connecter type results in display not lighting up.
[How] Set dpcd_caps.dongle_type for passive dongles in detect_dp().
Signed-off-by: Samson Tam Samson.Tam@amd.com Reviewed-by: Joshua Aberback Joshua.Aberback@amd.com Acked-by: Eryk Brol eryk.brol@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index bdddb46727b1f..885beb0bcc199 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -767,6 +767,7 @@ static bool detect_dp(struct dc_link *link, sink_caps->signal = dp_passive_dongle_detection(link->ddc, sink_caps, audio_support); + link->dpcd_caps.dongle_type = sink_caps->dongle_type; }
return true;
From: Brandon Syu Brandon.Syu@amd.com
[ Upstream commit cba4b52e431e5de3d8012281cfe194f1c39a9052 ]
[Why] When system enters s3/s0i3, backlight PWM would set user level.
[How] ABM disable function add keep current gain to avoid it.
Signed-off-by: Brandon Syu Brandon.Syu@amd.com Reviewed-by: Josip Pavic Josip.Pavic@amd.com Acked-by: Eryk Brol eryk.brol@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dc_stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 49aad691e687e..ccac2315a903a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -222,7 +222,7 @@ struct dc_stream_state { union stream_update_flags update_flags; };
-#define ABM_LEVEL_IMMEDIATE_DISABLE 0xFFFFFFFF +#define ABM_LEVEL_IMMEDIATE_DISABLE 255
struct dc_stream_update { struct dc_stream_state *stream;
From: Wayne Lin Wayne.Lin@amd.com
[ Upstream commit ef67d792a2fc578319399f605fbec2f99ecc06ea ]
[Why] In dm_dp_aux_transfer() now, we forget to handle AUX_WR fail cases. We suppose every write wil get done successfully and hence some AUX commands might not sent out indeed.
[How] Check if AUX_WR success. If not, retry it.
Signed-off-by: Wayne Lin Wayne.Lin@amd.com Reviewed-by: Hersen Wu hersenxs.wu@amd.com Acked-by: Rodrigo Siqueira Rodrigo.Siqueira@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index e5ecc5affa1eb..5098fc98cc255 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -67,7 +67,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, &operation_result);
- if (payload.write) + if (payload.write && result >= 0) result = msg->size;
if (result < 0)
From: Dinghao Liu dinghao.liu@zju.edu.cn
[ Upstream commit b67a468a4ccef593cd8df6a02ba3d167b77f0c81 ]
When amdgpu_display_modeset_create_props() fails, state and state->context should be freed to prevent memleak. It's the same when amdgpu_dm_audio_init() fails.
Signed-off-by: Dinghao Liu dinghao.liu@zju.edu.cn Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0682fd363cb50..580c17c95a1d8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2822,12 +2822,18 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) &dm_atomic_state_funcs);
r = amdgpu_display_modeset_create_props(adev); - if (r) + if (r) { + dc_release_state(state->context); + kfree(state); return r; + }
r = amdgpu_dm_audio_init(adev); - if (r) + if (r) { + dc_release_state(state->context); + kfree(state); return r; + }
return 0; }
From: Simon Leiner simon@leiner.me
[ Upstream commit d742db70033c745e410523e00522ee0cfe2aa416 ]
On some architectures (like ARM), virt_to_gfn cannot be used for vmalloc'd memory because of its reliance on virt_to_phys. This patch introduces a check for vmalloc'd addresses and obtains the PFN using vmalloc_to_pfn in that case.
Signed-off-by: Simon Leiner simon@leiner.me Reviewed-by: Stefano Stabellini sstabellini@kernel.org Link: https://lore.kernel.org/r/20200825093153.35500-1-simon@leiner.me Signed-off-by: Juergen Gross jgross@suse.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/xen/xenbus/xenbus_client.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 786fbb7d8be06..907bcbb93afbf 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -379,8 +379,14 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, int i, j;
for (i = 0; i < nr_pages; i++) { - err = gnttab_grant_foreign_access(dev->otherend_id, - virt_to_gfn(vaddr), 0); + unsigned long gfn; + + if (is_vmalloc_addr(vaddr)) + gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr)); + else + gfn = virt_to_gfn(vaddr); + + err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0); if (err < 0) { xenbus_dev_fatal(dev, err, "granting access to ring page");
From: Linus Torvalds torvalds@linux-foundation.org
[ Upstream commit 0a4c56c80f90797e9b9f8426c6aae4c0cf1c9785 ]
Commit ef91bb196b0d ("kernel.h: Silence sparse warning in lower_32_bits") caused new warnings to show in the fsldma driver, but that commit was not to blame: it only exposed some very incorrect code that tried to take the low 32 bits of an address.
That made no sense for multiple reasons, the most notable one being that that code was intentionally limited to only 32-bit ppc builds, so "only low 32 bits of an address" was completely nonsensical. There were no high bits to mask off to begin with.
But even more importantly fropm a correctness standpoint, turning the address into an integer then caused the subsequent address arithmetic to be completely wrong too, and the "+1" actually incremented the address by one, rather than by four.
Which again was incorrect, since the code was reading two 32-bit values and trying to make a 64-bit end result of it all. Surprisingly, the iowrite64() did not suffer from the same odd and incorrect model.
This code has never worked, but it's questionable whether anybody cared: of the two users that actually read the 64-bit value (by way of some C preprocessor hackery and eventually the 'get_cdar()' inline function), one of them explicitly ignored the value, and the other one might just happen to work despite the incorrect value being read.
This patch at least makes it not fail the build any more, and makes the logic superficially sane. Whether it makes any difference to the code _working_ or not shall remain a mystery.
Compile-tested-by: Guenter Roeck linux@roeck-us.net Reviewed-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/dma/fsldma.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 56f18ae992332..308bed0a560ac 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -205,10 +205,10 @@ struct fsldma_chan { #else static u64 fsl_ioread64(const u64 __iomem *addr) { - u32 fsl_addr = lower_32_bits(addr); - u64 fsl_addr_hi = (u64)in_le32((u32 *)(fsl_addr + 1)) << 32; + u32 val_lo = in_le32((u32 __iomem *)addr); + u32 val_hi = in_le32((u32 __iomem *)addr + 1);
- return fsl_addr_hi | in_le32((u32 *)fsl_addr); + return ((u64)val_hi << 32) + val_lo; }
static void fsl_iowrite64(u64 val, u64 __iomem *addr) @@ -219,10 +219,10 @@ static void fsl_iowrite64(u64 val, u64 __iomem *addr)
static u64 fsl_ioread64be(const u64 __iomem *addr) { - u32 fsl_addr = lower_32_bits(addr); - u64 fsl_addr_hi = (u64)in_be32((u32 *)fsl_addr) << 32; + u32 val_hi = in_be32((u32 __iomem *)addr); + u32 val_lo = in_be32((u32 __iomem *)addr + 1);
- return fsl_addr_hi | in_be32((u32 *)(fsl_addr + 1)); + return ((u64)val_hi << 32) + val_lo; }
static void fsl_iowrite64be(u64 val, u64 __iomem *addr)
linux-stable-mirror@lists.linaro.org