The patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From 463659a08d7999d5461fa45b35b17686189a70ca Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hansverk(a)cisco.com>
Date: Thu, 13 Sep 2018 07:47:29 -0400
Subject: [PATCH] media: hdmi.h: rename ADOBE_RGB to OPRGB and ADOBE_YCC to
OPYCC
These names have been renamed in the CTA-861 standard due to trademark
issues. Replace them here as well so they are in sync with the standard.
Signed-off-by: Hans Verkuil <hansverk(a)cisco.com>
Cc: stable(a)vger.kernel.org
Acked-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index a1f73d998495..f3899cc84e27 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -1357,8 +1357,8 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
switch (format->format.colorspace) {
case V4L2_COLORSPACE_OPRGB:
c = HDMI_COLORIMETRY_EXTENDED;
- ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 :
- HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB;
+ ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 :
+ HDMI_EXTENDED_COLORIMETRY_OPRGB;
break;
case V4L2_COLORSPACE_SMPTE170M:
c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE;
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index 19aabd1fcd2b..4f23e939ead0 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -877,7 +877,7 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
switch (avi->colorimetry) {
case HDMI_COLORIMETRY_EXTENDED:
switch (avi->extended_colorimetry) {
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
+ case HDMI_EXTENDED_COLORIMETRY_OPRGB:
c.colorspace = V4L2_COLORSPACE_OPRGB;
c.xfer_func = V4L2_XFER_FUNC_OPRGB;
break;
@@ -948,7 +948,7 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
c.ycbcr_enc = V4L2_YCBCR_ENC_601;
c.xfer_func = V4L2_XFER_FUNC_SRGB;
break;
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
+ case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
c.colorspace = V4L2_COLORSPACE_OPRGB;
c.ycbcr_enc = V4L2_YCBCR_ENC_601;
c.xfer_func = V4L2_XFER_FUNC_OPRGB;
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 38716eb50408..8a3e8f61b991 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -592,10 +592,10 @@ hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
return "xvYCC 709";
case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
return "sYCC 601";
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
- return "Adobe YCC 601";
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
- return "Adobe RGB";
+ case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
+ return "opYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_OPRGB:
+ return "opRGB";
case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
return "BT.2020 Constant Luminance";
case HDMI_EXTENDED_COLORIMETRY_BT2020:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d271ff23984f..4f3febc0f971 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -101,8 +101,8 @@ enum hdmi_extended_colorimetry {
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601,
HDMI_EXTENDED_COLORIMETRY_XV_YCC_709,
HDMI_EXTENDED_COLORIMETRY_S_YCC_601,
- HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601,
- HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB,
+ HDMI_EXTENDED_COLORIMETRY_OPYCC_601,
+ HDMI_EXTENDED_COLORIMETRY_OPRGB,
/* The following EC values are only defined in CEA-861-F. */
HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM,
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From 258c430456ba5f0005043762e14fc3be35983aaf Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
Date: Fri, 14 Sep 2018 13:13:15 -0400
Subject: [PATCH] media: em28xx: fix handler for vidioc_s_input()
The a->index is not the name of the internal amux entry,
but, instead a value from zero to the maximum number
of audio inputs.
As the actual available inputs depend on each board, build
it dynamically.
This is broken for a really long time. On a quick check,
since at least commit 195a4ef627e1 ("V4L/DVB (6585): Convert
em28xx to video_ioctl2") this was not implemented right.
Fixes: 195a4ef627e1 ("V4L/DVB (6585): Convert em28xx to video_ioctl2")
Cc: stable(a)vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 71c829f31d3b..06a7e09ded6e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3039,6 +3039,9 @@ static int em28xx_hint_board(struct em28xx *dev)
static void em28xx_card_setup(struct em28xx *dev)
{
+ int i, j, idx;
+ bool duplicate_entry;
+
/*
* If the device can be a webcam, seek for a sensor.
* If sensor is not found, then it isn't a webcam.
@@ -3195,6 +3198,32 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+
+ /*
+ * Dynamically generate a list of valid audio inputs for this
+ * specific board, mapping them via enum em28xx_amux.
+ */
+
+ idx = 0;
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ if (!INPUT(i)->type)
+ continue;
+
+ /* Skip already mapped audio inputs */
+ duplicate_entry = false;
+ for (j = 0; j < idx; j++) {
+ if (INPUT(i)->amux == dev->amux_map[j]) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry)
+ continue;
+
+ dev->amux_map[idx++] = INPUT(i)->amux;
+ }
+ for (; idx < MAX_EM28XX_INPUT; idx++)
+ dev->amux_map[idx] = EM28XX_AMUX_UNUSED;
}
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 917602954bfb..fbdfe6762cb2 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1666,6 +1666,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
unsigned int n;
+ int j;
n = i->index;
if (n >= MAX_EM28XX_INPUT)
@@ -1685,6 +1686,12 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (dev->is_webcam)
i->capabilities = 0;
+ /* Dynamically generates an audioset bitmask */
+ i->audioset = 0;
+ for (j = 0; j < MAX_EM28XX_INPUT; j++)
+ if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
+ i->audioset |= 1 << j;
+
return 0;
}
@@ -1710,11 +1717,24 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int em28xx_fill_audio_input(struct em28xx *dev,
+ const char *s,
+ struct v4l2_audio *a,
+ unsigned int index)
{
- struct em28xx *dev = video_drvdata(file);
+ unsigned int idx = dev->amux_map[index];
- switch (a->index) {
+ /*
+ * With msp3400, almost all mappings use the default (amux = 0).
+ * The only one may use a different value is WinTV USB2, where it
+ * can also be SCART1 input.
+ * As it is very doubtful that we would see new boards with msp3400,
+ * let's just reuse the existing switch.
+ */
+ if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
+ idx = EM28XX_AMUX_LINE_IN;
+
+ switch (idx) {
case EM28XX_AMUX_VIDEO:
strscpy(a->name, "Television", sizeof(a->name));
break;
@@ -1739,32 +1759,79 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
case EM28XX_AMUX_PCM_OUT:
strscpy(a->name, "PCM", sizeof(a->name));
break;
+ case EM28XX_AMUX_UNUSED:
default:
return -EINVAL;
}
-
- a->index = dev->ctl_ainput;
+ a->index = index;
a->capability = V4L2_AUDCAP_STEREO;
+ em28xx_videodbg("%s: audio input index %d is '%s'\n",
+ s, a->index, a->name);
+
return 0;
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+
+ if (a->index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+
+ return em28xx_fill_audio_input(dev, __func__, a, a->index);
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+ int i;
+
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (dev->ctl_ainput == dev->amux_map[i])
+ return em28xx_fill_audio_input(dev, __func__, a, i);
+
+ /* Should never happen! */
+ return -EINVAL;
+}
+
static int vidioc_s_audio(struct file *file, void *priv,
const struct v4l2_audio *a)
{
struct em28xx *dev = video_drvdata(file);
+ int idx, i;
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (!INPUT(a->index)->type)
+
+ idx = dev->amux_map[a->index];
+
+ if (idx == EM28XX_AMUX_UNUSED)
+ return -EINVAL;
+
+ dev->ctl_ainput = idx;
+
+ /*
+ * FIXME: This is wrong, as different inputs at em28xx_cards
+ * may have different audio outputs. So, the right thing
+ * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
+ * With the current board definitions, this would work fine,
+ * as, currently, all boards fit.
+ */
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (idx == dev->amux_map[i])
+ break;
+ if (i == MAX_EM28XX_INPUT)
return -EINVAL;
- dev->ctl_ainput = INPUT(a->index)->amux;
- dev->ctl_aoutput = INPUT(a->index)->aout;
+ dev->ctl_aoutput = INPUT(i)->aout;
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+ em28xx_videodbg("%s: set audio input to %d\n", __func__,
+ dev->ctl_ainput);
+
return 0;
}
@@ -2302,6 +2369,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 953caac025f2..a551072e62ed 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -335,6 +335,9 @@ enum em28xx_usb_audio_type {
/**
* em28xx_amux - describes the type of audio input used by em28xx
*
+ * @EM28XX_AMUX_UNUSED:
+ * Used only on em28xx dev->map field, in order to mark an entry
+ * as unused.
* @EM28XX_AMUX_VIDEO:
* On devices without AC97, this is the only value that it is currently
* allowed.
@@ -369,7 +372,8 @@ enum em28xx_usb_audio_type {
* same time, via the alsa mux.
*/
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
+ EM28XX_AMUX_UNUSED = -1,
+ EM28XX_AMUX_VIDEO = 0,
EM28XX_AMUX_LINE_IN,
/* Some less-common mixer setups */
@@ -692,6 +696,8 @@ struct em28xx {
unsigned int ctl_input; // selected input
unsigned int ctl_ainput;// selected audio input
unsigned int ctl_aoutput;// selected audio output
+ enum em28xx_amux amux_map[MAX_EM28XX_INPUT];
+
int mute;
int volume;
The patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From 258c430456ba5f0005043762e14fc3be35983aaf Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
Date: Fri, 14 Sep 2018 13:13:15 -0400
Subject: [PATCH] media: em28xx: fix handler for vidioc_s_input()
The a->index is not the name of the internal amux entry,
but, instead a value from zero to the maximum number
of audio inputs.
As the actual available inputs depend on each board, build
it dynamically.
This is broken for a really long time. On a quick check,
since at least commit 195a4ef627e1 ("V4L/DVB (6585): Convert
em28xx to video_ioctl2") this was not implemented right.
Fixes: 195a4ef627e1 ("V4L/DVB (6585): Convert em28xx to video_ioctl2")
Cc: stable(a)vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 71c829f31d3b..06a7e09ded6e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3039,6 +3039,9 @@ static int em28xx_hint_board(struct em28xx *dev)
static void em28xx_card_setup(struct em28xx *dev)
{
+ int i, j, idx;
+ bool duplicate_entry;
+
/*
* If the device can be a webcam, seek for a sensor.
* If sensor is not found, then it isn't a webcam.
@@ -3195,6 +3198,32 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+
+ /*
+ * Dynamically generate a list of valid audio inputs for this
+ * specific board, mapping them via enum em28xx_amux.
+ */
+
+ idx = 0;
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ if (!INPUT(i)->type)
+ continue;
+
+ /* Skip already mapped audio inputs */
+ duplicate_entry = false;
+ for (j = 0; j < idx; j++) {
+ if (INPUT(i)->amux == dev->amux_map[j]) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry)
+ continue;
+
+ dev->amux_map[idx++] = INPUT(i)->amux;
+ }
+ for (; idx < MAX_EM28XX_INPUT; idx++)
+ dev->amux_map[idx] = EM28XX_AMUX_UNUSED;
}
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 917602954bfb..fbdfe6762cb2 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1666,6 +1666,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
unsigned int n;
+ int j;
n = i->index;
if (n >= MAX_EM28XX_INPUT)
@@ -1685,6 +1686,12 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (dev->is_webcam)
i->capabilities = 0;
+ /* Dynamically generates an audioset bitmask */
+ i->audioset = 0;
+ for (j = 0; j < MAX_EM28XX_INPUT; j++)
+ if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
+ i->audioset |= 1 << j;
+
return 0;
}
@@ -1710,11 +1717,24 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int em28xx_fill_audio_input(struct em28xx *dev,
+ const char *s,
+ struct v4l2_audio *a,
+ unsigned int index)
{
- struct em28xx *dev = video_drvdata(file);
+ unsigned int idx = dev->amux_map[index];
- switch (a->index) {
+ /*
+ * With msp3400, almost all mappings use the default (amux = 0).
+ * The only one may use a different value is WinTV USB2, where it
+ * can also be SCART1 input.
+ * As it is very doubtful that we would see new boards with msp3400,
+ * let's just reuse the existing switch.
+ */
+ if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
+ idx = EM28XX_AMUX_LINE_IN;
+
+ switch (idx) {
case EM28XX_AMUX_VIDEO:
strscpy(a->name, "Television", sizeof(a->name));
break;
@@ -1739,32 +1759,79 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
case EM28XX_AMUX_PCM_OUT:
strscpy(a->name, "PCM", sizeof(a->name));
break;
+ case EM28XX_AMUX_UNUSED:
default:
return -EINVAL;
}
-
- a->index = dev->ctl_ainput;
+ a->index = index;
a->capability = V4L2_AUDCAP_STEREO;
+ em28xx_videodbg("%s: audio input index %d is '%s'\n",
+ s, a->index, a->name);
+
return 0;
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+
+ if (a->index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+
+ return em28xx_fill_audio_input(dev, __func__, a, a->index);
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+ int i;
+
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (dev->ctl_ainput == dev->amux_map[i])
+ return em28xx_fill_audio_input(dev, __func__, a, i);
+
+ /* Should never happen! */
+ return -EINVAL;
+}
+
static int vidioc_s_audio(struct file *file, void *priv,
const struct v4l2_audio *a)
{
struct em28xx *dev = video_drvdata(file);
+ int idx, i;
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (!INPUT(a->index)->type)
+
+ idx = dev->amux_map[a->index];
+
+ if (idx == EM28XX_AMUX_UNUSED)
+ return -EINVAL;
+
+ dev->ctl_ainput = idx;
+
+ /*
+ * FIXME: This is wrong, as different inputs at em28xx_cards
+ * may have different audio outputs. So, the right thing
+ * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
+ * With the current board definitions, this would work fine,
+ * as, currently, all boards fit.
+ */
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (idx == dev->amux_map[i])
+ break;
+ if (i == MAX_EM28XX_INPUT)
return -EINVAL;
- dev->ctl_ainput = INPUT(a->index)->amux;
- dev->ctl_aoutput = INPUT(a->index)->aout;
+ dev->ctl_aoutput = INPUT(i)->aout;
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+ em28xx_videodbg("%s: set audio input to %d\n", __func__,
+ dev->ctl_ainput);
+
return 0;
}
@@ -2302,6 +2369,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 953caac025f2..a551072e62ed 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -335,6 +335,9 @@ enum em28xx_usb_audio_type {
/**
* em28xx_amux - describes the type of audio input used by em28xx
*
+ * @EM28XX_AMUX_UNUSED:
+ * Used only on em28xx dev->map field, in order to mark an entry
+ * as unused.
* @EM28XX_AMUX_VIDEO:
* On devices without AC97, this is the only value that it is currently
* allowed.
@@ -369,7 +372,8 @@ enum em28xx_usb_audio_type {
* same time, via the alsa mux.
*/
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
+ EM28XX_AMUX_UNUSED = -1,
+ EM28XX_AMUX_VIDEO = 0,
EM28XX_AMUX_LINE_IN,
/* Some less-common mixer setups */
@@ -692,6 +696,8 @@ struct em28xx {
unsigned int ctl_input; // selected input
unsigned int ctl_ainput;// selected audio input
unsigned int ctl_aoutput;// selected audio output
+ enum em28xx_amux amux_map[MAX_EM28XX_INPUT];
+
int mute;
int volume;
The patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From 258c430456ba5f0005043762e14fc3be35983aaf Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
Date: Fri, 14 Sep 2018 13:13:15 -0400
Subject: [PATCH] media: em28xx: fix handler for vidioc_s_input()
The a->index is not the name of the internal amux entry,
but, instead a value from zero to the maximum number
of audio inputs.
As the actual available inputs depend on each board, build
it dynamically.
This is broken for a really long time. On a quick check,
since at least commit 195a4ef627e1 ("V4L/DVB (6585): Convert
em28xx to video_ioctl2") this was not implemented right.
Fixes: 195a4ef627e1 ("V4L/DVB (6585): Convert em28xx to video_ioctl2")
Cc: stable(a)vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 71c829f31d3b..06a7e09ded6e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3039,6 +3039,9 @@ static int em28xx_hint_board(struct em28xx *dev)
static void em28xx_card_setup(struct em28xx *dev)
{
+ int i, j, idx;
+ bool duplicate_entry;
+
/*
* If the device can be a webcam, seek for a sensor.
* If sensor is not found, then it isn't a webcam.
@@ -3195,6 +3198,32 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+
+ /*
+ * Dynamically generate a list of valid audio inputs for this
+ * specific board, mapping them via enum em28xx_amux.
+ */
+
+ idx = 0;
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ if (!INPUT(i)->type)
+ continue;
+
+ /* Skip already mapped audio inputs */
+ duplicate_entry = false;
+ for (j = 0; j < idx; j++) {
+ if (INPUT(i)->amux == dev->amux_map[j]) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry)
+ continue;
+
+ dev->amux_map[idx++] = INPUT(i)->amux;
+ }
+ for (; idx < MAX_EM28XX_INPUT; idx++)
+ dev->amux_map[idx] = EM28XX_AMUX_UNUSED;
}
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 917602954bfb..fbdfe6762cb2 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1666,6 +1666,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
unsigned int n;
+ int j;
n = i->index;
if (n >= MAX_EM28XX_INPUT)
@@ -1685,6 +1686,12 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (dev->is_webcam)
i->capabilities = 0;
+ /* Dynamically generates an audioset bitmask */
+ i->audioset = 0;
+ for (j = 0; j < MAX_EM28XX_INPUT; j++)
+ if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
+ i->audioset |= 1 << j;
+
return 0;
}
@@ -1710,11 +1717,24 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int em28xx_fill_audio_input(struct em28xx *dev,
+ const char *s,
+ struct v4l2_audio *a,
+ unsigned int index)
{
- struct em28xx *dev = video_drvdata(file);
+ unsigned int idx = dev->amux_map[index];
- switch (a->index) {
+ /*
+ * With msp3400, almost all mappings use the default (amux = 0).
+ * The only one may use a different value is WinTV USB2, where it
+ * can also be SCART1 input.
+ * As it is very doubtful that we would see new boards with msp3400,
+ * let's just reuse the existing switch.
+ */
+ if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
+ idx = EM28XX_AMUX_LINE_IN;
+
+ switch (idx) {
case EM28XX_AMUX_VIDEO:
strscpy(a->name, "Television", sizeof(a->name));
break;
@@ -1739,32 +1759,79 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
case EM28XX_AMUX_PCM_OUT:
strscpy(a->name, "PCM", sizeof(a->name));
break;
+ case EM28XX_AMUX_UNUSED:
default:
return -EINVAL;
}
-
- a->index = dev->ctl_ainput;
+ a->index = index;
a->capability = V4L2_AUDCAP_STEREO;
+ em28xx_videodbg("%s: audio input index %d is '%s'\n",
+ s, a->index, a->name);
+
return 0;
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+
+ if (a->index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+
+ return em28xx_fill_audio_input(dev, __func__, a, a->index);
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+ int i;
+
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (dev->ctl_ainput == dev->amux_map[i])
+ return em28xx_fill_audio_input(dev, __func__, a, i);
+
+ /* Should never happen! */
+ return -EINVAL;
+}
+
static int vidioc_s_audio(struct file *file, void *priv,
const struct v4l2_audio *a)
{
struct em28xx *dev = video_drvdata(file);
+ int idx, i;
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (!INPUT(a->index)->type)
+
+ idx = dev->amux_map[a->index];
+
+ if (idx == EM28XX_AMUX_UNUSED)
+ return -EINVAL;
+
+ dev->ctl_ainput = idx;
+
+ /*
+ * FIXME: This is wrong, as different inputs at em28xx_cards
+ * may have different audio outputs. So, the right thing
+ * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
+ * With the current board definitions, this would work fine,
+ * as, currently, all boards fit.
+ */
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (idx == dev->amux_map[i])
+ break;
+ if (i == MAX_EM28XX_INPUT)
return -EINVAL;
- dev->ctl_ainput = INPUT(a->index)->amux;
- dev->ctl_aoutput = INPUT(a->index)->aout;
+ dev->ctl_aoutput = INPUT(i)->aout;
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+ em28xx_videodbg("%s: set audio input to %d\n", __func__,
+ dev->ctl_ainput);
+
return 0;
}
@@ -2302,6 +2369,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 953caac025f2..a551072e62ed 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -335,6 +335,9 @@ enum em28xx_usb_audio_type {
/**
* em28xx_amux - describes the type of audio input used by em28xx
*
+ * @EM28XX_AMUX_UNUSED:
+ * Used only on em28xx dev->map field, in order to mark an entry
+ * as unused.
* @EM28XX_AMUX_VIDEO:
* On devices without AC97, this is the only value that it is currently
* allowed.
@@ -369,7 +372,8 @@ enum em28xx_usb_audio_type {
* same time, via the alsa mux.
*/
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
+ EM28XX_AMUX_UNUSED = -1,
+ EM28XX_AMUX_VIDEO = 0,
EM28XX_AMUX_LINE_IN,
/* Some less-common mixer setups */
@@ -692,6 +696,8 @@ struct em28xx {
unsigned int ctl_input; // selected input
unsigned int ctl_ainput;// selected audio input
unsigned int ctl_aoutput;// selected audio output
+ enum em28xx_amux amux_map[MAX_EM28XX_INPUT];
+
int mute;
int volume;
The patch below was submitted to be applied to the 4.18-stable tree.
I fail to see how this patch meets the stable kernel rules as found at
Documentation/process/stable-kernel-rules.rst.
I could be totally wrong, and if so, please respond to
<stable(a)vger.kernel.org> and let me know why this patch should be
applied. Otherwise, it is now dropped from my patch queues, never to be
seen again.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From f94d463f1b7f83d465ed77521821583dbcdaa3c5 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hans.verkuil(a)cisco.com>
Date: Thu, 13 Sep 2018 08:00:39 -0400
Subject: [PATCH] media: cec: remove cec-edid.c
Move cec_get_edid_phys_addr() to cec-adap.c. It's not worth keeping
a separate source for this.
Signed-off-by: Hans Verkuil <hans.verkuil(a)cisco.com>
Cc: <stable(a)vger.kernel.org> # for v4.17 and up
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile
index 29a2ab9e77c5..ad8677d8c896 100644
--- a/drivers/media/cec/Makefile
+++ b/drivers/media/cec/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o
+cec-objs := cec-core.o cec-adap.o cec-api.o
ifeq ($(CONFIG_CEC_NOTIFIER),y)
cec-objs += cec-notifier.o
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 030b2602faf0..829878356e1e 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -62,6 +62,19 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
return adap->log_addrs.primary_device_type[i < 0 ? 0 : i];
}
+u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
+ unsigned int *offset)
+{
+ unsigned int loc = cec_get_edid_spa_location(edid, size);
+
+ if (offset)
+ *offset = loc;
+ if (loc == 0)
+ return CEC_PHYS_ADDR_INVALID;
+ return (edid[loc] << 8) | edid[loc + 1];
+}
+EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
+
/*
* Queue a new event for this filehandle. If ts == 0, then set it
* to the current time.
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
deleted file mode 100644
index e2f54eec0829..000000000000
--- a/drivers/media/cec/cec-edid.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
- *
- * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <media/cec.h>
-
-u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
- unsigned int *offset)
-{
- unsigned int loc = cec_get_edid_spa_location(edid, size);
-
- if (offset)
- *offset = loc;
- if (loc == 0)
- return CEC_PHYS_ADDR_INVALID;
- return (edid[loc] << 8) | edid[loc + 1];
-}
-EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
The patch below was submitted to be applied to the 4.19-stable tree.
I fail to see how this patch meets the stable kernel rules as found at
Documentation/process/stable-kernel-rules.rst.
I could be totally wrong, and if so, please respond to
<stable(a)vger.kernel.org> and let me know why this patch should be
applied. Otherwise, it is now dropped from my patch queues, never to be
seen again.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From f94d463f1b7f83d465ed77521821583dbcdaa3c5 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hans.verkuil(a)cisco.com>
Date: Thu, 13 Sep 2018 08:00:39 -0400
Subject: [PATCH] media: cec: remove cec-edid.c
Move cec_get_edid_phys_addr() to cec-adap.c. It's not worth keeping
a separate source for this.
Signed-off-by: Hans Verkuil <hans.verkuil(a)cisco.com>
Cc: <stable(a)vger.kernel.org> # for v4.17 and up
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung(a)kernel.org>
diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile
index 29a2ab9e77c5..ad8677d8c896 100644
--- a/drivers/media/cec/Makefile
+++ b/drivers/media/cec/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o
+cec-objs := cec-core.o cec-adap.o cec-api.o
ifeq ($(CONFIG_CEC_NOTIFIER),y)
cec-objs += cec-notifier.o
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 030b2602faf0..829878356e1e 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -62,6 +62,19 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
return adap->log_addrs.primary_device_type[i < 0 ? 0 : i];
}
+u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
+ unsigned int *offset)
+{
+ unsigned int loc = cec_get_edid_spa_location(edid, size);
+
+ if (offset)
+ *offset = loc;
+ if (loc == 0)
+ return CEC_PHYS_ADDR_INVALID;
+ return (edid[loc] << 8) | edid[loc + 1];
+}
+EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
+
/*
* Queue a new event for this filehandle. If ts == 0, then set it
* to the current time.
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
deleted file mode 100644
index e2f54eec0829..000000000000
--- a/drivers/media/cec/cec-edid.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
- *
- * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <media/cec.h>
-
-u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
- unsigned int *offset)
-{
- unsigned int loc = cec_get_edid_spa_location(edid, size);
-
- if (offset)
- *offset = loc;
- if (loc == 0)
- return CEC_PHYS_ADDR_INVALID;
- return (edid[loc] << 8) | edid[loc + 1];
-}
-EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
Hi,friend,
This is Daniel Murray and i am from Sinara Group Co.Ltd Group Co.,LTD in Russia.
We are glad to know about your company from the web and we are interested in your products.
Could you kindly send us your Latest catalog and price list for our trial order.
Best Regards,
Daniel Murray
Purchasing Manager
The patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From f9005571701920551bcf54a500973fb61f2e1eda Mon Sep 17 00:00:00 2001
From: Stefano Stabellini <stefanos(a)xilinx.com>
Date: Wed, 31 Oct 2018 16:11:49 -0700
Subject: [PATCH] CONFIG_XEN_PV breaks xen_create_contiguous_region on ARM
xen_create_contiguous_region has now only an implementation if
CONFIG_XEN_PV is defined. However, on ARM we never set CONFIG_XEN_PV but
we do have an implementation of xen_create_contiguous_region which is
required for swiotlb-xen to work correctly (although it just sets
*dma_handle).
Cc: <stable(a)vger.kernel.org> # 4.12
Fixes: 16624390816c ("xen: create xen_create/destroy_contiguous_region() stubs for PVHVM only builds")
Signed-off-by: Stefano Stabellini <stefanos(a)xilinx.com>
Reviewed-by: Juergen Gross <jgross(a)suse.com>
CC: Jeff.Kubascik(a)dornerworks.com
CC: Jarvis.Roach(a)dornerworks.com
CC: Nathan.Studer(a)dornerworks.com
CC: vkuznets(a)redhat.com
CC: boris.ostrovsky(a)oracle.com
CC: jgross(a)suse.com
CC: julien.grall(a)arm.com
Signed-off-by: Juergen Gross <jgross(a)suse.com>
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 18803ff76e27..4969817124a8 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -42,16 +42,12 @@ int xen_setup_shutdown_event(void);
extern unsigned long *xen_contiguous_bitmap;
-#ifdef CONFIG_XEN_PV
+#if defined(CONFIG_XEN_PV) || defined(CONFIG_ARM) || defined(CONFIG_ARM64)
int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
unsigned int address_bits,
dma_addr_t *dma_handle);
void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order);
-
-int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
- xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
- unsigned int domid, bool no_translate, struct page **pages);
#else
static inline int xen_create_contiguous_region(phys_addr_t pstart,
unsigned int order,
@@ -63,7 +59,13 @@ static inline int xen_create_contiguous_region(phys_addr_t pstart,
static inline void xen_destroy_contiguous_region(phys_addr_t pstart,
unsigned int order) { }
+#endif
+#if defined(CONFIG_XEN_PV)
+int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
+ xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
+ unsigned int domid, bool no_translate, struct page **pages);
+#else
static inline int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
xen_pfn_t *pfn, int nr, int *err_ptr,
pgprot_t prot, unsigned int domid,
The patch below does not apply to the 4.18-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From f9005571701920551bcf54a500973fb61f2e1eda Mon Sep 17 00:00:00 2001
From: Stefano Stabellini <stefanos(a)xilinx.com>
Date: Wed, 31 Oct 2018 16:11:49 -0700
Subject: [PATCH] CONFIG_XEN_PV breaks xen_create_contiguous_region on ARM
xen_create_contiguous_region has now only an implementation if
CONFIG_XEN_PV is defined. However, on ARM we never set CONFIG_XEN_PV but
we do have an implementation of xen_create_contiguous_region which is
required for swiotlb-xen to work correctly (although it just sets
*dma_handle).
Cc: <stable(a)vger.kernel.org> # 4.12
Fixes: 16624390816c ("xen: create xen_create/destroy_contiguous_region() stubs for PVHVM only builds")
Signed-off-by: Stefano Stabellini <stefanos(a)xilinx.com>
Reviewed-by: Juergen Gross <jgross(a)suse.com>
CC: Jeff.Kubascik(a)dornerworks.com
CC: Jarvis.Roach(a)dornerworks.com
CC: Nathan.Studer(a)dornerworks.com
CC: vkuznets(a)redhat.com
CC: boris.ostrovsky(a)oracle.com
CC: jgross(a)suse.com
CC: julien.grall(a)arm.com
Signed-off-by: Juergen Gross <jgross(a)suse.com>
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 18803ff76e27..4969817124a8 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -42,16 +42,12 @@ int xen_setup_shutdown_event(void);
extern unsigned long *xen_contiguous_bitmap;
-#ifdef CONFIG_XEN_PV
+#if defined(CONFIG_XEN_PV) || defined(CONFIG_ARM) || defined(CONFIG_ARM64)
int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
unsigned int address_bits,
dma_addr_t *dma_handle);
void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order);
-
-int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
- xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
- unsigned int domid, bool no_translate, struct page **pages);
#else
static inline int xen_create_contiguous_region(phys_addr_t pstart,
unsigned int order,
@@ -63,7 +59,13 @@ static inline int xen_create_contiguous_region(phys_addr_t pstart,
static inline void xen_destroy_contiguous_region(phys_addr_t pstart,
unsigned int order) { }
+#endif
+#if defined(CONFIG_XEN_PV)
+int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
+ xen_pfn_t *pfn, int nr, int *err_ptr, pgprot_t prot,
+ unsigned int domid, bool no_translate, struct page **pages);
+#else
static inline int xen_remap_pfn(struct vm_area_struct *vma, unsigned long addr,
xen_pfn_t *pfn, int nr, int *err_ptr,
pgprot_t prot, unsigned int domid,
The patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From ef739b2175dde9c05594f768cb78149f1ce2ac36 Mon Sep 17 00:00:00 2001
From: Chuck Lever <chuck.lever(a)oracle.com>
Date: Mon, 1 Oct 2018 14:25:14 -0400
Subject: [PATCH] xprtrdma: Reset credit grant properly after a disconnect
On a fresh connection, an RPC/RDMA client is supposed to send only
one RPC Call until it gets a credit grant in the first RPC Reply
from the server [RFC 8166, Section 3.3.3].
There is a bug in the Linux client's credit accounting mechanism
introduced by commit e7ce710a8802 ("xprtrdma: Avoid deadlock when
credit window is reset"). On connect, it simply dumps all pending
RPC Calls onto the new connection.
Servers have been tolerant of this bad behavior. Currently no server
implementation ever changes its credit grant over reconnects, and
servers always repost enough Receives before connections are fully
established.
To correct this issue, ensure that the client resets both the credit
grant _and_ the congestion window when handling a reconnect.
Fixes: e7ce710a8802 ("xprtrdma: Avoid deadlock when credit ... ")
Signed-off-by: Chuck Lever <chuck.lever(a)oracle.com>
Cc: stable(a)kernel.org
Signed-off-by: Anna Schumaker <Anna.Schumaker(a)Netapp.com>
diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c
index a68180090554..b9827665ff35 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c
@@ -248,6 +248,7 @@ static void
xprt_rdma_bc_close(struct rpc_xprt *xprt)
{
dprintk("svcrdma: %s: xprt %p\n", __func__, xprt);
+ xprt->cwnd = RPC_CWNDSHIFT;
}
static void
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 143ce2579ba9..98cbc7b060ba 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -468,6 +468,12 @@ xprt_rdma_close(struct rpc_xprt *xprt)
xprt->reestablish_timeout = 0;
xprt_disconnect_done(xprt);
rpcrdma_ep_disconnect(ep, ia);
+
+ /* Prepare @xprt for the next connection by reinitializing
+ * its credit grant to one (see RFC 8166, Section 3.3.3).
+ */
+ r_xprt->rx_buf.rb_credits = 1;
+ xprt->cwnd = RPC_CWNDSHIFT;
}
/**