Merge b2ebe6c3ff ("drm/amd/display: Update Cursor request mode to the beginning prefetch always") into android14-6.1-lts

Steps on the way to 6.1.135

Resolves merge conflicts in:
	drivers/bluetooth/btqca.c

Change-Id: Ib76d6c88366d035cd32424ee75895b36d2848419
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-04-30 07:02:55 +00:00
47 changed files with 597 additions and 174 deletions

View File

@@ -119,6 +119,7 @@
#define QCOM_CPU_PART_KRYO 0x200 #define QCOM_CPU_PART_KRYO 0x200
#define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800 #define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800
#define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801 #define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801
#define QCOM_CPU_PART_KRYO_3XX_GOLD 0x802
#define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803 #define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803
#define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804 #define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804
#define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805 #define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805
@@ -188,6 +189,7 @@
#define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) #define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO)
#define MIDR_QCOM_KRYO_2XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD) #define MIDR_QCOM_KRYO_2XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD)
#define MIDR_QCOM_KRYO_2XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER) #define MIDR_QCOM_KRYO_2XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER)
#define MIDR_QCOM_KRYO_3XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_GOLD)
#define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER) #define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER)
#define MIDR_QCOM_KRYO_4XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD) #define MIDR_QCOM_KRYO_4XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD)
#define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER) #define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER)

View File

@@ -787,7 +787,7 @@ static void init_amd_k8(struct cpuinfo_x86 *c)
* (model = 0x14) and later actually support it. * (model = 0x14) and later actually support it.
* (AMD Erratum #110, docId: 25759). * (AMD Erratum #110, docId: 25759).
*/ */
if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM)) { if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM) && !cpu_has(c, X86_FEATURE_HYPERVISOR)) {
clear_cpu_cap(c, X86_FEATURE_LAHF_LM); clear_cpu_cap(c, X86_FEATURE_LAHF_LM);
if (!rdmsrl_amd_safe(0xc001100d, &value)) { if (!rdmsrl_amd_safe(0xc001100d, &value)) {
value &= ~BIT_64(32); value &= ~BIT_64(32);

View File

@@ -592,6 +592,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
.driver_data = board_ahci_yes_fbs }, .driver_data = board_ahci_yes_fbs },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
.driver_data = board_ahci_yes_fbs }, .driver_data = board_ahci_yes_fbs },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215),
.driver_data = board_ahci_yes_fbs },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
.driver_data = board_ahci_yes_fbs }, .driver_data = board_ahci_yes_fbs },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235), { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235),

View File

@@ -1510,8 +1510,15 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev,
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET; tf.command = ATA_CMD_PACKET;
/* is it pointless to prefer PIO for "safety reasons"? */ /*
if (ap->flags & ATA_FLAG_PIO_DMA) { * Do not use DMA if the connected device only supports PIO, even if the
* port prefers PIO commands via DMA.
*
* Ideally, we should call atapi_check_dma() to check if it is safe for
* the LLD to use DMA for REQUEST_SENSE, but we don't have a qc.
* Since we can't check the command, perhaps we should only use pio?
*/
if ((ap->flags & ATA_FLAG_PIO_DMA) && !(dev->flags & ATA_DFLAG_PIO)) {
tf.protocol = ATAPI_PROT_DMA; tf.protocol = ATAPI_PROT_DMA;
tf.feature |= ATAPI_PKT_DMA; tf.feature |= ATAPI_PKT_DMA;
} else { } else {

View File

@@ -223,10 +223,16 @@ static int pxa_ata_probe(struct platform_device *pdev)
ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, cmd_res->start, ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, cmd_res->start,
resource_size(cmd_res)); resource_size(cmd_res));
if (!ap->ioaddr.cmd_addr)
return -ENOMEM;
ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
resource_size(ctl_res)); resource_size(ctl_res));
if (!ap->ioaddr.ctl_addr)
return -ENOMEM;
ap->ioaddr.bmdma_addr = devm_ioremap(&pdev->dev, dma_res->start, ap->ioaddr.bmdma_addr = devm_ioremap(&pdev->dev, dma_res->start,
resource_size(dma_res)); resource_size(dma_res));
if (!ap->ioaddr.bmdma_addr)
return -ENOMEM;
/* /*
* Adjust register offsets * Adjust register offsets

View File

@@ -1118,9 +1118,14 @@ static int pdc20621_prog_dimm0(struct ata_host *host)
mmio += PDC_CHIP0_OFS; mmio += PDC_CHIP0_OFS;
for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++) for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++)
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
pdc_i2c_read_data[i].reg, pdc_i2c_read_data[i].reg,
&spd0[pdc_i2c_read_data[i].ofs]); &spd0[pdc_i2c_read_data[i].ofs])) {
dev_err(host->dev,
"Failed in i2c read at index %d: device=%#x, reg=%#x\n",
i, PDC_DIMM0_SPD_DEV_ADDRESS, pdc_i2c_read_data[i].reg);
return -EIO;
}
data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4); data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
@@ -1285,6 +1290,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
/* Programming DIMM0 Module Control Register (index_CID0:80h) */ /* Programming DIMM0 Module Control Register (index_CID0:80h) */
size = pdc20621_prog_dimm0(host); size = pdc20621_prog_dimm0(host);
if (size < 0)
return size;
dev_dbg(host->dev, "Local DIMM Size = %dMB\n", size); dev_dbg(host->dev, "Local DIMM Size = %dMB\n", size);
/* Programming DIMM Module Global Control Register (index_CID0:88h) */ /* Programming DIMM Module Global Control Register (index_CID0:88h) */

View File

@@ -709,12 +709,13 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
hu->proto = p; hu->proto = p;
set_bit(HCI_UART_PROTO_READY, &hu->flags);
err = hci_uart_register_dev(hu); err = hci_uart_register_dev(hu);
if (err) { if (err) {
return err; return err;
} }
set_bit(HCI_UART_PROTO_READY, &hu->flags);
return 0; return 0;
} }

View File

@@ -1947,20 +1947,11 @@ static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx)
dc->hwss.get_position(&pipe_ctx, 1, &position); dc->hwss.get_position(&pipe_ctx, 1, &position);
vpos = position.vertical_count; vpos = position.vertical_count;
/* Avoid wraparound calculation issues */
vupdate_start += stream->timing.v_total;
vupdate_end += stream->timing.v_total;
vpos += stream->timing.v_total;
if (vpos <= vupdate_start) { if (vpos <= vupdate_start) {
/* VPOS is in VACTIVE or back porch. */ /* VPOS is in VACTIVE or back porch. */
lines_to_vupdate = vupdate_start - vpos; lines_to_vupdate = vupdate_start - vpos;
} else if (vpos > vupdate_end) {
/* VPOS is in the front porch. */
return;
} else { } else {
/* VPOS is in VUPDATE. */ lines_to_vupdate = stream->timing.v_total - vpos + vupdate_start;
lines_to_vupdate = 0;
} }
/* Calculate time until VUPDATE in microseconds. */ /* Calculate time until VUPDATE in microseconds. */
@@ -1968,13 +1959,18 @@ static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx)
stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz;
us_to_vupdate = lines_to_vupdate * us_per_line; us_to_vupdate = lines_to_vupdate * us_per_line;
/* Stall out until the cursor update completes. */
if (vupdate_end < vupdate_start)
vupdate_end += stream->timing.v_total;
/* Position is in the range of vupdate start and end*/
if (lines_to_vupdate > stream->timing.v_total - vupdate_end + vupdate_start)
us_to_vupdate = 0;
/* 70 us is a conservative estimate of cursor update time*/ /* 70 us is a conservative estimate of cursor update time*/
if (us_to_vupdate > 70) if (us_to_vupdate > 70)
return; return;
/* Stall out until the cursor update completes. */
if (vupdate_end < vupdate_start)
vupdate_end += stream->timing.v_total;
us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line;
udelay(us_to_vupdate + us_vupdate); udelay(us_to_vupdate + us_vupdate);
} }

View File

@@ -44,7 +44,7 @@ void hubp31_set_unbounded_requesting(struct hubp *hubp, bool enable)
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
REG_UPDATE(DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, enable); REG_UPDATE(DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, enable);
REG_UPDATE(CURSOR_CONTROL, CURSOR_REQ_MODE, enable); REG_UPDATE(CURSOR_CONTROL, CURSOR_REQ_MODE, 1);
} }
void hubp31_soft_reset(struct hubp *hubp, bool reset) void hubp31_soft_reset(struct hubp *hubp, bool reset)

View File

@@ -1389,7 +1389,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
mode = &new_crtc_state->mode; mode = &new_crtc_state->mode;
adjusted_mode = &new_crtc_state->adjusted_mode; adjusted_mode = &new_crtc_state->adjusted_mode;
if (!new_crtc_state->mode_changed) if (!new_crtc_state->mode_changed && !new_crtc_state->connectors_changed)
continue; continue;
drm_dbg_atomic(dev, "modeset on [ENCODER:%d:%s]\n", drm_dbg_atomic(dev, "modeset on [ENCODER:%d:%s]\n",

View File

@@ -21,6 +21,7 @@
#include "usbhid.h" #include "usbhid.h"
#define PID_EFFECTS_MAX 64 #define PID_EFFECTS_MAX 64
#define PID_INFINITE 0xffff
/* Report usage table used to put reports into an array */ /* Report usage table used to put reports into an array */
@@ -261,10 +262,22 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
static int pidff_needs_set_envelope(struct ff_envelope *envelope, static int pidff_needs_set_envelope(struct ff_envelope *envelope,
struct ff_envelope *old) struct ff_envelope *old)
{ {
return envelope->attack_level != old->attack_level || bool needs_new_envelope;
envelope->fade_level != old->fade_level || needs_new_envelope = envelope->attack_level != 0 ||
envelope->fade_level != 0 ||
envelope->attack_length != 0 ||
envelope->fade_length != 0;
if (!needs_new_envelope)
return false;
if (!old)
return needs_new_envelope;
return envelope->attack_level != old->attack_level ||
envelope->fade_level != old->fade_level ||
envelope->attack_length != old->attack_length || envelope->attack_length != old->attack_length ||
envelope->fade_length != old->fade_length; envelope->fade_length != old->fade_length;
} }
/* /*
@@ -301,7 +314,12 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
pidff->set_effect_type->value[0] = pidff->set_effect_type->value[0] =
pidff->create_new_effect_type->value[0]; pidff->create_new_effect_type->value[0];
pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
/* Convert infinite length from Linux API (0)
to PID standard (NULL) if needed */
pidff->set_effect[PID_DURATION].value[0] =
effect->replay.length == 0 ? PID_INFINITE : effect->replay.length;
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
effect->trigger.interval; effect->trigger.interval;
@@ -574,11 +592,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect); pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_constant(effect, old)) if (!old || pidff_needs_set_constant(effect, old))
pidff_set_constant_force_report(pidff, effect); pidff_set_constant_force_report(pidff, effect);
if (!old || if (pidff_needs_set_envelope(&effect->u.constant.envelope,
pidff_needs_set_envelope(&effect->u.constant.envelope, old ? &old->u.constant.envelope : NULL))
&old->u.constant.envelope)) pidff_set_envelope_report(pidff, &effect->u.constant.envelope);
pidff_set_envelope_report(pidff,
&effect->u.constant.envelope);
break; break;
case FF_PERIODIC: case FF_PERIODIC:
@@ -613,11 +629,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect); pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_periodic(effect, old)) if (!old || pidff_needs_set_periodic(effect, old))
pidff_set_periodic_report(pidff, effect); pidff_set_periodic_report(pidff, effect);
if (!old || if (pidff_needs_set_envelope(&effect->u.periodic.envelope,
pidff_needs_set_envelope(&effect->u.periodic.envelope, old ? &old->u.periodic.envelope : NULL))
&old->u.periodic.envelope)) pidff_set_envelope_report(pidff, &effect->u.periodic.envelope);
pidff_set_envelope_report(pidff,
&effect->u.periodic.envelope);
break; break;
case FF_RAMP: case FF_RAMP:
@@ -631,11 +645,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect); pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_ramp(effect, old)) if (!old || pidff_needs_set_ramp(effect, old))
pidff_set_ramp_force_report(pidff, effect); pidff_set_ramp_force_report(pidff, effect);
if (!old || if (pidff_needs_set_envelope(&effect->u.ramp.envelope,
pidff_needs_set_envelope(&effect->u.ramp.envelope, old ? &old->u.ramp.envelope : NULL))
&old->u.ramp.envelope)) pidff_set_envelope_report(pidff, &effect->u.ramp.envelope);
pidff_set_envelope_report(pidff,
&effect->u.ramp.envelope);
break; break;
case FF_SPRING: case FF_SPRING:
@@ -758,6 +770,11 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
struct hid_report *report, int count, int strict) struct hid_report *report, int count, int strict)
{ {
if (!report) {
pr_debug("pidff_find_fields, null report\n");
return -1;
}
int i, j, k, found; int i, j, k, found;
for (k = 0; k < count; k++) { for (k = 0; k < count; k++) {
@@ -871,6 +888,11 @@ static int pidff_reports_ok(struct pidff_device *pidff)
static struct hid_field *pidff_find_special_field(struct hid_report *report, static struct hid_field *pidff_find_special_field(struct hid_report *report,
int usage, int enforce_min) int usage, int enforce_min)
{ {
if (!report) {
pr_debug("pidff_find_special_field, null report\n");
return NULL;
}
int i; int i;
for (i = 0; i < report->maxfield; i++) { for (i = 0; i < report->maxfield; i++) {

View File

@@ -1268,15 +1268,6 @@ static int mtk_iommu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
mutex_init(&data->mutex); mutex_init(&data->mutex);
ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
"mtk-iommu.%pa", &ioaddr);
if (ret)
goto out_link_remove;
ret = iommu_device_register(&data->iommu, &mtk_iommu_ops, dev);
if (ret)
goto out_sysfs_remove;
if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) { if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) {
list_add_tail(&data->list, data->plat_data->hw_list); list_add_tail(&data->list, data->plat_data->hw_list);
data->hw_list = data->plat_data->hw_list; data->hw_list = data->plat_data->hw_list;
@@ -1286,19 +1277,28 @@ static int mtk_iommu_probe(struct platform_device *pdev)
data->hw_list = &data->hw_list_head; data->hw_list = &data->hw_list_head;
} }
ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
"mtk-iommu.%pa", &ioaddr);
if (ret)
goto out_list_del;
ret = iommu_device_register(&data->iommu, &mtk_iommu_ops, dev);
if (ret)
goto out_sysfs_remove;
if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match); ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
if (ret) if (ret)
goto out_list_del; goto out_device_unregister;
} }
return ret; return ret;
out_list_del: out_device_unregister:
list_del(&data->list);
iommu_device_unregister(&data->iommu); iommu_device_unregister(&data->iommu);
out_sysfs_remove: out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu); iommu_device_sysfs_remove(&data->iommu);
out_link_remove: out_list_del:
list_del(&data->list);
if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
device_link_remove(data->smicomm_dev, dev); device_link_remove(data->smicomm_dev, dev);
out_runtime_disable: out_runtime_disable:

View File

@@ -2574,6 +2574,91 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
} }
} }
static void dw_mci_push_data64_32(struct dw_mci *host, void *buf, int cnt)
{
struct mmc_data *data = host->data;
int init_cnt = cnt;
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
if (host->part_buf_count == 8) {
mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
host->part_buf_count = 0;
}
}
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
if (unlikely((unsigned long)buf & 0x7)) {
while (cnt >= 8) {
u64 aligned_buf[16];
int len = min(cnt & -8, (int)sizeof(aligned_buf));
int items = len >> 3;
int i;
/* memcpy from input buffer into aligned buffer */
memcpy(aligned_buf, buf, len);
buf += len;
cnt -= len;
/* push data from aligned buffer into fifo */
for (i = 0; i < items; ++i)
mci_fifo_l_writeq(host->fifo_reg, aligned_buf[i]);
}
} else
#endif
{
u64 *pdata = buf;
for (; cnt >= 8; cnt -= 8)
mci_fifo_l_writeq(host->fifo_reg, *pdata++);
buf = pdata;
}
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
/* Push data if we have reached the expected data length */
if ((data->bytes_xfered + init_cnt) ==
(data->blksz * data->blocks))
mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
}
}
static void dw_mci_pull_data64_32(struct dw_mci *host, void *buf, int cnt)
{
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
if (unlikely((unsigned long)buf & 0x7)) {
while (cnt >= 8) {
/* pull data from fifo into aligned buffer */
u64 aligned_buf[16];
int len = min(cnt & -8, (int)sizeof(aligned_buf));
int items = len >> 3;
int i;
for (i = 0; i < items; ++i)
aligned_buf[i] = mci_fifo_l_readq(host->fifo_reg);
/* memcpy from aligned buffer into output buffer */
memcpy(buf, aligned_buf, len);
buf += len;
cnt -= len;
}
} else
#endif
{
u64 *pdata = buf;
for (; cnt >= 8; cnt -= 8)
*pdata++ = mci_fifo_l_readq(host->fifo_reg);
buf = pdata;
}
if (cnt) {
host->part_buf = mci_fifo_l_readq(host->fifo_reg);
dw_mci_pull_final_bytes(host, buf, cnt);
}
}
static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
{ {
int len; int len;
@@ -3374,8 +3459,13 @@ int dw_mci_probe(struct dw_mci *host)
width = 16; width = 16;
host->data_shift = 1; host->data_shift = 1;
} else if (i == 2) { } else if (i == 2) {
host->push_data = dw_mci_push_data64; if ((host->quirks & DW_MMC_QUIRK_FIFO64_32)) {
host->pull_data = dw_mci_pull_data64; host->push_data = dw_mci_push_data64_32;
host->pull_data = dw_mci_pull_data64_32;
} else {
host->push_data = dw_mci_push_data64;
host->pull_data = dw_mci_pull_data64;
}
width = 64; width = 64;
host->data_shift = 3; host->data_shift = 3;
} else { } else {

View File

@@ -280,6 +280,8 @@ struct dw_mci_board {
/* Support for longer data read timeout */ /* Support for longer data read timeout */
#define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0) #define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0)
/* Force 32-bit access to the FIFO */
#define DW_MMC_QUIRK_FIFO64_32 BIT(1)
#define DW_MMC_240A 0x240a #define DW_MMC_240A 0x240a
#define DW_MMC_280A 0x280a #define DW_MMC_280A 0x280a
@@ -471,6 +473,31 @@ struct dw_mci_board {
#define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value) #define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value)
#define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value) #define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value)
/*
* Some dw_mmc devices have 64-bit FIFOs, but expect them to be
* accessed using two 32-bit accesses. If such controller is used
* with a 64-bit kernel, this has to be done explicitly.
*/
static inline u64 mci_fifo_l_readq(void __iomem *addr)
{
u64 ans;
u32 proxy[2];
proxy[0] = mci_fifo_readl(addr);
proxy[1] = mci_fifo_readl(addr + 4);
memcpy(&ans, proxy, 8);
return ans;
}
static inline void mci_fifo_l_writeq(void __iomem *addr, u64 value)
{
u32 proxy[2];
memcpy(proxy, &value, 8);
mci_fifo_writel(addr, proxy[0]);
mci_fifo_writel(addr + 4, proxy[1]);
}
/* Register access macros */ /* Register access macros */
#define mci_readl(dev, reg) \ #define mci_readl(dev, reg) \
readl_relaxed((dev)->regs + SDMMC_##reg) readl_relaxed((dev)->regs + SDMMC_##reg)

View File

@@ -515,6 +515,11 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
unsigned char *data; unsigned char *data;
int islcp; int islcp;
/* Ensure we can safely access protocol field and LCP code */
if (!pskb_may_pull(skb, 3)) {
kfree_skb(skb);
return NULL;
}
data = skb->data; data = skb->data;
proto = get_unaligned_be16(data); proto = get_unaligned_be16(data);

View File

@@ -21,6 +21,7 @@ static const struct usb_device_id mt76x2u_device_table[] = {
{ USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */
{ USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */
{ USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */
{ USB_DEVICE(0x2357, 0x0137) }, /* TP-Link TL-WDN6200 */
{ }, { },
}; };

View File

@@ -478,7 +478,7 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
if (targetport) { if (targetport) {
tport = targetport->private; tport = targetport->private;
spin_lock(&tport->lock); spin_lock(&tport->lock);
list_add_tail(&tport->ls_list, &tls_req->ls_list); list_add_tail(&tls_req->ls_list, &tport->ls_list);
spin_unlock(&tport->lock); spin_unlock(&tport->lock);
queue_work(nvmet_wq, &tport->ls_work); queue_work(nvmet_wq, &tport->ls_work);
} }

View File

@@ -340,12 +340,10 @@ armpmu_add(struct perf_event *event, int flags)
if (idx < 0) if (idx < 0)
return idx; return idx;
/* /* The newly-allocated counter should be empty */
* If there is an event in the counter we are going to use then make WARN_ON_ONCE(hw_events->events[idx]);
* sure it is disabled.
*/
event->hw.idx = idx; event->hw.idx = idx;
armpmu->disable(event);
hw_events->events[idx] = event; hw_events->events[idx] = event;
hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;

View File

@@ -4112,7 +4112,7 @@ static void validate_options(void)
*/ */
static int __init st_setup(char *str) static int __init st_setup(char *str)
{ {
int i, len, ints[5]; int i, len, ints[ARRAY_SIZE(parms) + 1];
char *stp; char *stp;
stp = get_options(str, ARRAY_SIZE(ints), ints); stp = get_options(str, ARRAY_SIZE(ints), ints);

View File

@@ -6797,12 +6797,25 @@ static int ext4_release_dquot(struct dquot *dquot)
{ {
int ret, err; int ret, err;
handle_t *handle; handle_t *handle;
bool freeze_protected = false;
/*
* Trying to sb_start_intwrite() in a running transaction
* can result in a deadlock. Further, running transactions
* are already protected from freezing.
*/
if (!ext4_journal_current_handle()) {
sb_start_intwrite(dquot->dq_sb);
freeze_protected = true;
}
handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
if (IS_ERR(handle)) { if (IS_ERR(handle)) {
/* Release dquot anyway to avoid endless cycle in dqput() */ /* Release dquot anyway to avoid endless cycle in dqput() */
dquot_release(dquot); dquot_release(dquot);
if (freeze_protected)
sb_end_intwrite(dquot->dq_sb);
return PTR_ERR(handle); return PTR_ERR(handle);
} }
ret = dquot_release(dquot); ret = dquot_release(dquot);
@@ -6813,6 +6826,10 @@ static int ext4_release_dquot(struct dquot *dquot)
err = ext4_journal_stop(handle); err = ext4_journal_stop(handle);
if (!ret) if (!ret)
ret = err; ret = err;
if (freeze_protected)
sb_end_intwrite(dquot->dq_sb);
return ret; return ret;
} }

View File

@@ -1127,15 +1127,24 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
{ {
struct inode *ea_inode; struct inode *ea_inode;
struct ext4_xattr_entry *entry; struct ext4_xattr_entry *entry;
struct ext4_iloc iloc;
bool dirty = false; bool dirty = false;
unsigned int ea_ino; unsigned int ea_ino;
int err; int err;
int credits; int credits;
void *end;
if (block_csum)
end = (void *)bh->b_data + bh->b_size;
else {
ext4_get_inode_loc(parent, &iloc);
end = (void *)ext4_raw_inode(&iloc) + EXT4_SB(parent->i_sb)->s_inode_size;
}
/* One credit for dec ref on ea_inode, one for orphan list addition, */ /* One credit for dec ref on ea_inode, one for orphan list addition, */
credits = 2 + extra_credits; credits = 2 + extra_credits;
for (entry = first; !IS_LAST_ENTRY(entry); for (entry = first; (void *)entry < end && !IS_LAST_ENTRY(entry);
entry = EXT4_XATTR_NEXT(entry)) { entry = EXT4_XATTR_NEXT(entry)) {
if (!entry->e_value_inum) if (!entry->e_value_inum)
continue; continue;

View File

@@ -698,8 +698,12 @@ retry:
if (err == -ENOENT) if (err == -ENOENT)
return; return;
if (err == -EFSCORRUPTED)
goto stop_checkpoint;
if (err == -ENOMEM || ++count <= DEFAULT_RETRY_IO_COUNT) if (err == -ENOMEM || ++count <= DEFAULT_RETRY_IO_COUNT)
goto retry; goto retry;
stop_checkpoint:
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_UPDATE_INODE); f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_UPDATE_INODE);
return; return;
} }

View File

@@ -1114,7 +1114,14 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from)
trace_f2fs_truncate_inode_blocks_enter(inode, from); trace_f2fs_truncate_inode_blocks_enter(inode, from);
level = get_node_path(inode, from, offset, noffset); level = get_node_path(inode, from, offset, noffset);
if (level < 0) { if (level <= 0) {
if (!level) {
level = -EFSCORRUPTED;
f2fs_err(sbi, "%s: inode ino=%lx has corrupted node block, from:%lu addrs:%u",
__func__, inode->i_ino,
from, ADDRS_PER_INODE(inode));
set_sbi_flag(sbi, SBI_NEED_FSCK);
}
trace_f2fs_truncate_inode_blocks_exit(inode, level); trace_f2fs_truncate_inode_blocks_exit(inode, level);
return level; return level;
} }

View File

@@ -361,17 +361,25 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
old_fds = old_fdt->fd; old_fds = old_fdt->fd;
new_fds = new_fdt->fd; new_fds = new_fdt->fd;
/*
* We may be racing against fd allocation from other threads using this
* files_struct, despite holding ->file_lock.
*
* alloc_fd() might have already claimed a slot, while fd_install()
* did not populate it yet. Note the latter operates locklessly, so
* the file can show up as we are walking the array below.
*
* At the same time we know no files will disappear as all other
* operations take the lock.
*
* Instead of trying to placate userspace racing with itself, we
* ref the file if we see it and mark the fd slot as unused otherwise.
*/
for (i = open_files; i != 0; i--) { for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++; struct file *f = rcu_dereference_raw(*old_fds++);
if (f) { if (f) {
get_file(f); get_file(f);
} else { } else {
/*
* The fd may be claimed in the fd bitmap but not yet
* instantiated in the files array if a sibling thread
* is partway through open(). So make sure that this
* fd is available to the new process.
*/
__clear_open_fd(open_files - i, new_fdt); __clear_open_fd(open_files - i, new_fdt);
} }
rcu_assign_pointer(*new_fds++, f); rcu_assign_pointer(*new_fds++, f);
@@ -624,7 +632,7 @@ static struct file *pick_file(struct files_struct *files, unsigned fd)
return NULL; return NULL;
fd = array_index_nospec(fd, fdt->max_fds); fd = array_index_nospec(fd, fdt->max_fds);
file = fdt->fd[fd]; file = rcu_dereference_raw(fdt->fd[fd]);
if (file) { if (file) {
rcu_assign_pointer(fdt->fd[fd], NULL); rcu_assign_pointer(fdt->fd[fd], NULL);
__put_unused_fd(files, fd); __put_unused_fd(files, fd);
@@ -1092,7 +1100,7 @@ __releases(&files->file_lock)
*/ */
fdt = files_fdtable(files); fdt = files_fdtable(files);
fd = array_index_nospec(fd, fdt->max_fds); fd = array_index_nospec(fd, fdt->max_fds);
tofree = fdt->fd[fd]; tofree = rcu_dereference_raw(fdt->fd[fd]);
if (!tofree && fd_is_open(fd, fdt)) if (!tofree && fd_is_open(fd, fdt))
goto Ebusy; goto Ebusy;
get_file(file); get_file(file);

View File

@@ -204,6 +204,10 @@ int dbMount(struct inode *ipbmap)
bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel); bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight); bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
if (!bmp->db_agwidth) {
err = -EINVAL;
goto err_release_metapage;
}
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG || if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG ||
@@ -3403,7 +3407,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
oldl2agsize = bmp->db_agl2size; oldl2agsize = bmp->db_agl2size;
bmp->db_agl2size = l2agsize; bmp->db_agl2size = l2agsize;
bmp->db_agsize = 1 << l2agsize; bmp->db_agsize = (s64)1 << l2agsize;
/* compute new number of AG */ /* compute new number of AG */
agno = bmp->db_numag; agno = bmp->db_numag;
@@ -3666,8 +3670,8 @@ void dbFinalizeBmap(struct inode *ipbmap)
* system size is not a multiple of the group size). * system size is not a multiple of the group size).
*/ */
inactfree = (inactags && ag_rem) ? inactfree = (inactags && ag_rem) ?
((inactags - 1) << bmp->db_agl2size) + ag_rem (((s64)inactags - 1) << bmp->db_agl2size) + ag_rem
: inactags << bmp->db_agl2size; : ((s64)inactags << bmp->db_agl2size);
/* determine how many free blocks are in the active /* determine how many free blocks are in the active
* allocation groups plus the average number of free blocks * allocation groups plus the average number of free blocks

View File

@@ -102,7 +102,7 @@ int diMount(struct inode *ipimap)
* allocate/initialize the in-memory inode map control structure * allocate/initialize the in-memory inode map control structure
*/ */
/* allocate the in-memory inode map control structure. */ /* allocate the in-memory inode map control structure. */
imap = kmalloc(sizeof(struct inomap), GFP_KERNEL); imap = kzalloc(sizeof(struct inomap), GFP_KERNEL);
if (imap == NULL) if (imap == NULL)
return -ENOMEM; return -ENOMEM;
@@ -456,7 +456,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
dp += inum % 8; /* 8 inodes per 4K page */ dp += inum % 8; /* 8 inodes per 4K page */
/* copy on-disk inode to in-memory inode */ /* copy on-disk inode to in-memory inode */
if ((copy_from_dinode(dp, ip)) != 0) { if ((copy_from_dinode(dp, ip) != 0) || (ip->i_nlink == 0)) {
/* handle bad return by returning NULL for ip */ /* handle bad return by returning NULL for ip */
set_nlink(ip, 1); /* Don't want iput() deleting it */ set_nlink(ip, 1); /* Don't want iput() deleting it */
iput(ip); iput(ip);

View File

@@ -1777,6 +1777,7 @@ static void warn_mandlock(void)
static int can_umount(const struct path *path, int flags) static int can_umount(const struct path *path, int flags)
{ {
struct mount *mnt = real_mount(path->mnt); struct mount *mnt = real_mount(path->mnt);
struct super_block *sb = path->dentry->d_sb;
if (!may_mount()) if (!may_mount())
return -EPERM; return -EPERM;
@@ -1786,7 +1787,7 @@ static int can_umount(const struct path *path, int flags)
return -EINVAL; return -EINVAL;
if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */ if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
return -EINVAL; return -EINVAL;
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) if (flags & MNT_FORCE && !ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
} }

View File

@@ -138,4 +138,26 @@ extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
extern void rtnl_offload_xstats_notify(struct net_device *dev); extern void rtnl_offload_xstats_notify(struct net_device *dev);
static inline int rtnl_has_listeners(const struct net *net, u32 group)
{
struct sock *rtnl = net->rtnl;
return netlink_has_listeners(rtnl, group);
}
/**
* rtnl_notify_needed - check if notification is needed
* @net: Pointer to the net namespace
* @nlflags: netlink ingress message flags
* @group: rtnl group
*
* Based on the ingress message flags and rtnl group, returns true
* if a notification is needed, false otherwise.
*/
static inline bool
rtnl_notify_needed(const struct net *net, u16 nlflags, u32 group)
{
return (nlflags & NLM_F_ECHO) || rtnl_has_listeners(net, group);
}
#endif /* __LINUX_RTNETLINK_H */ #endif /* __LINUX_RTNETLINK_H */

View File

@@ -372,7 +372,7 @@ struct xen_mce {
#define XEN_MCE_LOG_LEN 32 #define XEN_MCE_LOG_LEN 32
struct xen_mce_log { struct xen_mce_log {
char signature[12]; /* "MACHINECHECK" */ char signature[12] __nonstring; /* "MACHINECHECK" */
unsigned len; /* = XEN_MCE_LOG_LEN */ unsigned len; /* = XEN_MCE_LOG_LEN */
unsigned next; unsigned next;
unsigned flags; unsigned flags;

View File

@@ -776,7 +776,9 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file,
clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags); clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags);
} }
call->class->reg(call, TRACE_REG_UNREGISTER, file); ret = call->class->reg(call, TRACE_REG_UNREGISTER, file);
WARN_ON_ONCE(ret);
} }
/* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */ /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */
if (file->flags & EVENT_FILE_FL_SOFT_MODE) if (file->flags & EVENT_FILE_FL_SOFT_MODE)

View File

@@ -272,17 +272,6 @@ static int vlan_dev_open(struct net_device *dev)
goto out; goto out;
} }
if (dev->flags & IFF_ALLMULTI) {
err = dev_set_allmulti(real_dev, 1);
if (err < 0)
goto del_unicast;
}
if (dev->flags & IFF_PROMISC) {
err = dev_set_promiscuity(real_dev, 1);
if (err < 0)
goto clear_allmulti;
}
ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr); ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);
if (vlan->flags & VLAN_FLAG_GVRP) if (vlan->flags & VLAN_FLAG_GVRP)
@@ -296,12 +285,6 @@ static int vlan_dev_open(struct net_device *dev)
netif_carrier_on(dev); netif_carrier_on(dev);
return 0; return 0;
clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(real_dev, -1);
del_unicast:
if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
dev_uc_del(real_dev, dev->dev_addr);
out: out:
netif_carrier_off(dev); netif_carrier_off(dev);
return err; return err;
@@ -314,10 +297,6 @@ static int vlan_dev_stop(struct net_device *dev)
dev_mc_unsync(real_dev, dev); dev_mc_unsync(real_dev, dev);
dev_uc_unsync(real_dev, dev); dev_uc_unsync(real_dev, dev);
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(real_dev, -1);
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(real_dev, -1);
if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
dev_uc_del(real_dev, dev->dev_addr); dev_uc_del(real_dev, dev->dev_addr);
@@ -474,12 +453,10 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
{ {
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
if (dev->flags & IFF_UP) { if (change & IFF_ALLMULTI)
if (change & IFF_ALLMULTI) dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC)
if (change & IFF_PROMISC) dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
}
} }
static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)

View File

@@ -841,7 +841,13 @@ static void page_pool_release_retry(struct work_struct *wq)
int inflight; int inflight;
inflight = page_pool_release(pool); inflight = page_pool_release(pool);
if (!inflight) /* In rare cases, a driver bug may cause inflight to go negative.
* Don't reschedule release if inflight is 0 or negative.
* - If 0, the page_pool has been destroyed
* - if negative, we will never recover
* in both cases no reschedule is necessary.
*/
if (inflight <= 0)
return; return;
/* Periodic warning */ /* Periodic warning */

View File

@@ -384,7 +384,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
ret = ops->prepare_data(req_info, reply_data, info); ret = ops->prepare_data(req_info, reply_data, info);
rtnl_unlock(); rtnl_unlock();
if (ret < 0) if (ret < 0)
goto err_cleanup; goto err_dev;
ret = ops->reply_size(req_info, reply_data); ret = ops->reply_size(req_info, reply_data);
if (ret < 0) if (ret < 0)
goto err_cleanup; goto err_cleanup;
@@ -442,7 +442,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL); ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL);
rtnl_unlock(); rtnl_unlock();
if (ret < 0) if (ret < 0)
goto out; goto out_cancel;
ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr); ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
if (ret < 0) if (ret < 0)
goto out; goto out;
@@ -451,6 +451,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
out: out:
if (ctx->ops->cleanup_data) if (ctx->ops->cleanup_data)
ctx->ops->cleanup_data(ctx->reply_data); ctx->ops->cleanup_data(ctx->reply_data);
out_cancel:
ctx->reply_data->dev = NULL; ctx->reply_data->dev = NULL;
if (ret < 0) if (ret < 0)
genlmsg_cancel(skb, ehdr); genlmsg_cancel(skb, ehdr);
@@ -636,7 +637,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
ethnl_init_reply_data(reply_data, ops, dev); ethnl_init_reply_data(reply_data, ops, dev);
ret = ops->prepare_data(req_info, reply_data, NULL); ret = ops->prepare_data(req_info, reply_data, NULL);
if (ret < 0) if (ret < 0)
goto err_cleanup; goto err_rep;
ret = ops->reply_size(req_info, reply_data); ret = ops->reply_size(req_info, reply_data);
if (ret < 0) if (ret < 0)
goto err_cleanup; goto err_cleanup;
@@ -671,6 +672,7 @@ err_skb:
err_cleanup: err_cleanup:
if (ops->cleanup_data) if (ops->cleanup_data)
ops->cleanup_data(reply_data); ops->cleanup_data(reply_data);
err_rep:
kfree(reply_data); kfree(reply_data);
kfree(req_info); kfree(req_info);
return; return;

View File

@@ -471,10 +471,10 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
goto out; goto out;
hash = fl6->mp_hash; hash = fl6->mp_hash;
if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound) && if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound)) {
rt6_score_route(first->fib6_nh, first->fib6_flags, oif, if (rt6_score_route(first->fib6_nh, first->fib6_flags, oif,
strict) >= 0) { strict) >= 0)
match = first; match = first;
goto out; goto out;
} }

View File

@@ -994,8 +994,9 @@ static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill,
NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt, 8, pkt[8], bsize); NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt, 8, pkt[8], bsize);
NFT_PIPAPO_AVX2_AND(6, 2, 3); NFT_PIPAPO_AVX2_AND(6, 2, 3);
NFT_PIPAPO_AVX2_AND(3, 4, 7);
NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt, 9, pkt[9], bsize); NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt, 9, pkt[9], bsize);
NFT_PIPAPO_AVX2_AND(0, 4, 5); NFT_PIPAPO_AVX2_AND(0, 3, 5);
NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 10, pkt[10], bsize); NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 10, pkt[10], bsize);
NFT_PIPAPO_AVX2_AND(2, 6, 7); NFT_PIPAPO_AVX2_AND(2, 6, 7);
NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt, 11, pkt[11], bsize); NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt, 11, pkt[11], bsize);

View File

@@ -1824,6 +1824,7 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
struct tcmsg *tcm; struct tcmsg *tcm;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
unsigned char *b = skb_tail_pointer(skb); unsigned char *b = skb_tail_pointer(skb);
int ret = -EMSGSIZE;
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
if (!nlh) if (!nlh)
@@ -1868,11 +1869,45 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
return skb->len; return skb->len;
cls_op_not_supp:
ret = -EOPNOTSUPP;
out_nlmsg_trim: out_nlmsg_trim:
nla_put_failure: nla_put_failure:
cls_op_not_supp:
nlmsg_trim(skb, b); nlmsg_trim(skb, b);
return -1; return ret;
}
static struct sk_buff *tfilter_notify_prep(struct net *net,
struct sk_buff *oskb,
struct nlmsghdr *n,
struct tcf_proto *tp,
struct tcf_block *block,
struct Qdisc *q, u32 parent,
void *fh, int event,
u32 portid, bool rtnl_held,
struct netlink_ext_ack *extack)
{
unsigned int size = oskb ? max(NLMSG_GOODSIZE, oskb->len) : NLMSG_GOODSIZE;
struct sk_buff *skb;
int ret;
retry:
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOBUFS);
ret = tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
n->nlmsg_seq, n->nlmsg_flags, event, false,
rtnl_held, extack);
if (ret <= 0) {
kfree_skb(skb);
if (ret == -EMSGSIZE) {
size += NLMSG_GOODSIZE;
goto retry;
}
return ERR_PTR(-EINVAL);
}
return skb;
} }
static int tfilter_notify(struct net *net, struct sk_buff *oskb, static int tfilter_notify(struct net *net, struct sk_buff *oskb,
@@ -1885,16 +1920,13 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
int err = 0; int err = 0;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!unicast && !rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC))
if (!skb) return 0;
return -ENOBUFS;
if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid, skb = tfilter_notify_prep(net, oskb, n, tp, block, q, parent, fh, event,
n->nlmsg_seq, n->nlmsg_flags, event, portid, rtnl_held, extack);
false, rtnl_held, extack) <= 0) { if (IS_ERR(skb))
kfree_skb(skb); return PTR_ERR(skb);
return -EINVAL;
}
if (unicast) if (unicast)
err = rtnl_unicast(skb, net, portid); err = rtnl_unicast(skb, net, portid);
@@ -1914,16 +1946,14 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
int err; int err;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC))
if (!skb) return tp->ops->delete(tp, fh, last, rtnl_held, extack);
return -ENOBUFS;
if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid, skb = tfilter_notify_prep(net, oskb, n, tp, block, q, parent, fh,
n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER, RTM_DELTFILTER, portid, rtnl_held, extack);
false, rtnl_held, extack) <= 0) { if (IS_ERR(skb)) {
NL_SET_ERR_MSG(extack, "Failed to build del event notification"); NL_SET_ERR_MSG(extack, "Failed to build del event notification");
kfree_skb(skb); return PTR_ERR(skb);
return -EINVAL;
} }
err = tp->ops->delete(tp, fh, last, rtnl_held, extack); err = tp->ops->delete(tp, fh, last, rtnl_held, extack);
@@ -2731,6 +2761,9 @@ static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
struct sk_buff *skb; struct sk_buff *skb;
int err = 0; int err = 0;
if (!unicast && !rtnl_notify_needed(net, flags, RTNLGRP_TC))
return 0;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;
@@ -2760,6 +2793,9 @@ static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
struct net *net = block->net; struct net *net = block->net;
struct sk_buff *skb; struct sk_buff *skb;
if (!rtnl_notify_needed(net, flags, RTNLGRP_TC))
return 0;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;

View File

@@ -95,10 +95,7 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
&q->stats, qdisc_pkt_len, codel_get_enqueue_time, &q->stats, qdisc_pkt_len, codel_get_enqueue_time,
drop_func, dequeue_func); drop_func, dequeue_func);
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, if (q->stats.drop_count) {
* or HTB crashes. Defer it for next round.
*/
if (q->stats.drop_count && sch->q.qlen) {
qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
q->stats.drop_count = 0; q->stats.drop_count = 0;
q->stats.drop_len = 0; q->stats.drop_len = 0;

View File

@@ -314,10 +314,8 @@ begin:
} }
qdisc_bstats_update(sch, skb); qdisc_bstats_update(sch, skb);
flow->deficit -= qdisc_pkt_len(skb); flow->deficit -= qdisc_pkt_len(skb);
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
* or HTB crashes. Defer it for next round. if (q->cstats.drop_count) {
*/
if (q->cstats.drop_count && sch->q.qlen) {
qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
q->cstats.drop_len); q->cstats.drop_len);
q->cstats.drop_count = 0; q->cstats.drop_count = 0;

View File

@@ -631,6 +631,15 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
struct red_parms *p = NULL; struct red_parms *p = NULL;
struct sk_buff *to_free = NULL; struct sk_buff *to_free = NULL;
struct sk_buff *tail = NULL; struct sk_buff *tail = NULL;
unsigned int maxflows;
unsigned int quantum;
unsigned int divisor;
int perturb_period;
u8 headdrop;
u8 maxdepth;
int limit;
u8 flags;
if (opt->nla_len < nla_attr_size(sizeof(*ctl))) if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
return -EINVAL; return -EINVAL;
@@ -652,39 +661,64 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
} }
if (ctl->limit == 1) {
NL_SET_ERR_MSG_MOD(extack, "invalid limit");
return -EINVAL;
}
sch_tree_lock(sch); sch_tree_lock(sch);
limit = q->limit;
divisor = q->divisor;
headdrop = q->headdrop;
maxdepth = q->maxdepth;
maxflows = q->maxflows;
perturb_period = q->perturb_period;
quantum = q->quantum;
flags = q->flags;
/* update and validate configuration */
if (ctl->quantum) if (ctl->quantum)
q->quantum = ctl->quantum; quantum = ctl->quantum;
WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ); perturb_period = ctl->perturb_period * HZ;
if (ctl->flows) if (ctl->flows)
q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS); maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
if (ctl->divisor) { if (ctl->divisor) {
q->divisor = ctl->divisor; divisor = ctl->divisor;
q->maxflows = min_t(u32, q->maxflows, q->divisor); maxflows = min_t(u32, maxflows, divisor);
} }
if (ctl_v1) { if (ctl_v1) {
if (ctl_v1->depth) if (ctl_v1->depth)
q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH); maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
if (p) { if (p) {
swap(q->red_parms, p); red_set_parms(p,
red_set_parms(q->red_parms,
ctl_v1->qth_min, ctl_v1->qth_max, ctl_v1->qth_min, ctl_v1->qth_max,
ctl_v1->Wlog, ctl_v1->Wlog,
ctl_v1->Plog, ctl_v1->Scell_log, ctl_v1->Plog, ctl_v1->Scell_log,
NULL, NULL,
ctl_v1->max_P); ctl_v1->max_P);
} }
q->flags = ctl_v1->flags; flags = ctl_v1->flags;
q->headdrop = ctl_v1->headdrop; headdrop = ctl_v1->headdrop;
} }
if (ctl->limit) { if (ctl->limit) {
q->limit = min_t(u32, ctl->limit, q->maxdepth * q->maxflows); limit = min_t(u32, ctl->limit, maxdepth * maxflows);
q->maxflows = min_t(u32, q->maxflows, q->limit); maxflows = min_t(u32, maxflows, limit);
} }
if (limit == 1) {
sch_tree_unlock(sch);
kfree(p);
NL_SET_ERR_MSG_MOD(extack, "invalid limit");
return -EINVAL;
}
/* commit configuration */
q->limit = limit;
q->divisor = divisor;
q->headdrop = headdrop;
q->maxdepth = maxdepth;
q->maxflows = maxflows;
WRITE_ONCE(q->perturb_period, perturb_period);
q->quantum = quantum;
q->flags = flags;
if (p)
swap(q->red_parms, p);
qlen = sch->q.qlen; qlen = sch->q.qlen;
while (sch->q.qlen > q->limit) { while (sch->q.qlen > q->limit) {

View File

@@ -1068,6 +1068,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
if (unlikely(l->backlog[imp].len >= l->backlog[imp].limit)) { if (unlikely(l->backlog[imp].len >= l->backlog[imp].limit)) {
if (imp == TIPC_SYSTEM_IMPORTANCE) { if (imp == TIPC_SYSTEM_IMPORTANCE) {
pr_warn("%s<%s>, link overflow", link_rst_msg, l->name); pr_warn("%s<%s>, link overflow", link_rst_msg, l->name);
__skb_queue_purge(list);
return -ENOBUFS; return -ENOBUFS;
} }
rc = link_schedule_user(l, hdr); rc = link_schedule_user(l, hdr);

View File

@@ -896,6 +896,11 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
return do_tls_setsockopt(sk, optname, optval, optlen); return do_tls_setsockopt(sk, optname, optval, optlen);
} }
static int tls_disconnect(struct sock *sk, int flags)
{
return -EOPNOTSUPP;
}
struct tls_context *tls_ctx_create(struct sock *sk) struct tls_context *tls_ctx_create(struct sock *sk)
{ {
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
@@ -990,6 +995,7 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
prot[TLS_BASE][TLS_BASE] = *base; prot[TLS_BASE][TLS_BASE] = *base;
prot[TLS_BASE][TLS_BASE].setsockopt = tls_setsockopt; prot[TLS_BASE][TLS_BASE].setsockopt = tls_setsockopt;
prot[TLS_BASE][TLS_BASE].getsockopt = tls_getsockopt; prot[TLS_BASE][TLS_BASE].getsockopt = tls_getsockopt;
prot[TLS_BASE][TLS_BASE].disconnect = tls_disconnect;
prot[TLS_BASE][TLS_BASE].close = tls_sk_proto_close; prot[TLS_BASE][TLS_BASE].close = tls_sk_proto_close;
prot[TLS_SW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; prot[TLS_SW][TLS_BASE] = prot[TLS_BASE][TLS_BASE];

View File

@@ -37,6 +37,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pgtable.h> #include <linux/pgtable.h>
#include <linux/dmi.h>
#ifdef CONFIG_X86 #ifdef CONFIG_X86
/* for snoop control */ /* for snoop control */
@@ -1366,8 +1367,21 @@ static void azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) { if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued) if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus); snd_hda_unlock_devices(&chip->bus);
if (hda->vga_switcheroo_registered) if (hda->vga_switcheroo_registered) {
vga_switcheroo_unregister_client(chip->pci); vga_switcheroo_unregister_client(chip->pci);
/* Some GPUs don't have sound, and azx_first_init fails,
* leaving the device probed but non-functional. As long
* as it's probed, the PCI subsystem keeps its runtime
* PM status as active. Force it to suspended (as we
* actually stop the chip) to allow GPU to suspend via
* vga_switcheroo, and print a warning.
*/
dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n");
pm_runtime_disable(&pci->dev);
pm_runtime_set_suspended(&pci->dev);
pm_runtime_enable(&pci->dev);
}
} }
if (bus->chip_init) { if (bus->chip_init) {
@@ -2074,6 +2088,27 @@ static const struct pci_device_id driver_denylist[] = {
{} {}
}; };
static struct pci_device_id driver_denylist_ideapad_z570[] = {
{ PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */
{}
};
/* DMI-based denylist, to be used when:
* - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards.
* - Different modifications of the same laptop use different GPU models.
*/
static const struct dmi_system_id driver_denylist_dmi[] = {
{
/* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
},
.driver_data = &driver_denylist_ideapad_z570,
},
{}
};
static const struct hda_controller_ops pci_hda_ops = { static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq, .disable_msi_reset_irq = disable_msi_reset_irq,
.position_check = azx_position_check, .position_check = azx_position_check,
@@ -2084,6 +2119,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
static int azx_probe(struct pci_dev *pci, static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id) const struct pci_device_id *pci_id)
{ {
const struct dmi_system_id *dmi;
struct snd_card *card; struct snd_card *card;
struct hda_intel *hda; struct hda_intel *hda;
struct azx *chip; struct azx *chip;
@@ -2096,6 +2132,12 @@ static int azx_probe(struct pci_dev *pci,
return -ENODEV; return -ENODEV;
} }
dmi = dmi_first_match(driver_denylist_dmi);
if (dmi && pci_match_id(dmi->driver_data, pci)) {
dev_info(&pci->dev, "Skipping the device on the DMI denylist\n");
return -ENODEV;
}
dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); dev = find_first_zero_bit(probed_devs, SNDRV_CARDS);
if (dev >= SNDRV_CARDS) if (dev >= SNDRV_CARDS)
return -ENODEV; return -ENODEV;

View File

@@ -479,6 +479,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"), DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"),
} }
}, },
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"),
}
},
{} {}
}; };

View File

@@ -492,11 +492,17 @@ static int fsl_audmix_probe(struct platform_device *pdev)
goto err_disable_pm; goto err_disable_pm;
} }
priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); /*
if (IS_ERR(priv->pdev)) { * If dais property exist, then register the imx-audmix card driver.
ret = PTR_ERR(priv->pdev); * otherwise, it should be linked by audio graph card.
dev_err(dev, "failed to register platform: %d\n", ret); */
goto err_disable_pm; if (of_find_property(pdev->dev.of_node, "dais", NULL)) {
priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform: %d\n", ret);
goto err_disable_pm;
}
} }
return 0; return 0;

View File

@@ -489,16 +489,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
/* /*
* CME protocol: like the standard protocol, but SysEx commands are sent as a * CME protocol: like the standard protocol, but SysEx commands are sent as a
* single USB packet preceded by a 0x0F byte. * single USB packet preceded by a 0x0F byte, as are system realtime
* messages and MIDI Active Sensing.
* Also, multiple messages can be sent in the same packet.
*/ */
static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep,
uint8_t *buffer, int buffer_length) uint8_t *buffer, int buffer_length)
{ {
if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) int remaining = buffer_length;
snd_usbmidi_standard_input(ep, buffer, buffer_length);
else /*
snd_usbmidi_input_data(ep, buffer[0] >> 4, * CME send sysex, song position pointer, system realtime
&buffer[1], buffer_length - 1); * and active sensing using CIN 0x0f, which in the standard
* is only intended for single byte unparsed data.
* So we need to interpret these here before sending them on.
* By default, we assume single byte data, which is true
* for system realtime (midi clock, start, stop and continue)
* and active sensing, and handle the other (known) cases
* separately.
* In contrast to the standard, CME does not split sysex
* into multiple 4-byte packets, but lumps everything together
* into one. In addition, CME can string multiple messages
* together in the same packet; pressing the Record button
* on an UF6 sends a sysex message directly followed
* by a song position pointer in the same packet.
* For it to have any reasonable meaning, a sysex message
* needs to be at least 3 bytes in length (0xf0, id, 0xf7),
* corresponding to a packet size of 4 bytes, and the ones sent
* by CME devices are 6 or 7 bytes, making the packet fragments
* 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte).
* For the other types, the packet size is always 4 bytes,
* as per the standard, with the data size being 3 for SPP
* and 1 for the others.
* Thus all packet fragments are at least 4 bytes long, so we can
* skip anything that is shorter; this also conveniantly skips
* packets with size 0, which CME devices continuously send when
* they have nothing better to do.
* Another quirk is that sometimes multiple messages are sent
* in the same packet. This has been observed for midi clock
* and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00,
* but also multiple note ons/offs, and control change together
* with MIDI clock. Similarly, some sysex messages are followed by
* the song position pointer in the same packet, and occasionally
* additionally by a midi clock or active sensing.
* We handle this by looping over all data and parsing it along the way.
*/
while (remaining >= 4) {
int source_length = 4; /* default */
if ((buffer[0] & 0x0f) == 0x0f) {
int data_length = 1; /* default */
if (buffer[1] == 0xf0) {
/* Sysex: Find EOX and send on whole message. */
/* To kick off the search, skip the first
* two bytes (CN+CIN and SYSEX (0xf0).
*/
uint8_t *tmp_buf = buffer + 2;
int tmp_length = remaining - 2;
while (tmp_length > 1 && *tmp_buf != 0xf7) {
tmp_buf++;
tmp_length--;
}
data_length = tmp_buf - buffer;
source_length = data_length + 1;
} else if (buffer[1] == 0xf2) {
/* Three byte song position pointer */
data_length = 3;
}
snd_usbmidi_input_data(ep, buffer[0] >> 4,
&buffer[1], data_length);
} else {
/* normal channel events */
snd_usbmidi_standard_input(ep, buffer, source_length);
}
buffer += source_length;
remaining -= source_length;
}
} }
/* /*

View File

@@ -120,6 +120,10 @@ out_dir:
struct config *prepare_default_config() struct config *prepare_default_config()
{ {
struct config *config = malloc(sizeof(struct config)); struct config *config = malloc(sizeof(struct config));
if (!config) {
perror("malloc");
return NULL;
}
dprintf("loading defaults\n"); dprintf("loading defaults\n");

View File

@@ -98,7 +98,7 @@ int main(int argc, char *argv[])
info("Calling futex_waitv on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); info("Calling futex_waitv on f1: %u @ %p with val=%u\n", f1, &f1, f1+1);
res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC); res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC);
if (!res || errno != EWOULDBLOCK) { if (!res || errno != EWOULDBLOCK) {
ksft_test_result_pass("futex_waitv returned: %d %s\n", ksft_test_result_fail("futex_waitv returned: %d %s\n",
res ? errno : res, res ? errno : res,
res ? strerror(errno) : ""); res ? strerror(errno) : "");
ret = RET_FAIL; ret = RET_FAIL;