mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
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:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) */
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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++) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
26
fs/file.c
26
fs/file.c
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
}
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user