Merge 6.1.108 into android14-6.1-lts

Changes in 6.1.108
	drm/amdgpu: Using uninitialized value *size when calling amdgpu_vce_cs_reloc
	LoongArch: Remove the unused dma-direct.h
	btrfs: run delayed iputs when flushing delalloc
	smb/client: avoid dereferencing rdata=NULL in smb2_new_read_req()
	pinctrl: rockchip: correct RK3328 iomux width flag for GPIO2-B pins
	pinctrl: single: fix potential NULL dereference in pcs_get_function()
	of: Add cleanup.h based auto release via __free(device_node) markings
	wifi: wfx: repair open network AP mode
	wifi: mwifiex: duplicate static structs used in driver instances
	net: mana: Fix race of mana_hwc_post_rx_wqe and new hwc response
	mptcp: close subflow when receiving TCP+FIN
	mptcp: sched: check both backup in retrans
	mptcp: pm: skip connecting to already established sf
	mptcp: pm: reset MPC endp ID when re-added
	mptcp: pm: send ACK on an active subflow
	mptcp: pm: do not remove already closed subflows
	mptcp: pm: ADD_ADDR 0 is not a new address
	drm/amdgpu: align pp_power_profile_mode with kernel docs
	drm/amdgpu/swsmu: always force a state reprogram on init
	ata: libata-core: Fix null pointer dereference on error
	usb: typec: fix up incorrectly backported "usb: typec: tcpm: unregister existing source caps before re-registration"
	mmc: Avoid open coding by using mmc_op_tuning()
	mmc: mtk-sd: receive cmd8 data when hs400 tuning fail
	mptcp: unify pm get_local_id interfaces
	mptcp: pm: remove mptcp_pm_remove_subflow()
	mptcp: pm: only mark 'subflow' endp as available
	mptcp: pm: check add_addr_accept_max before accepting new ADD_ADDR
	of: Introduce for_each_*_child_of_node_scoped() to automate of_node_put() handling
	thermal: of: Fix OF node leak in thermal_of_trips_init() error path
	thermal: of: Fix OF node leak in of_thermal_zone_find() error paths
	ASoC: amd: acp: fix module autoloading
	ASoC: SOF: amd: Fix for acp init sequence
	pinctrl: mediatek: common-v2: Fix broken bias-disable for PULL_PU_PD_RSEL_TYPE
	mm: Fix missing folio invalidation calls during truncation
	btrfs: fix extent map use-after-free when adding pages to compressed bio
	soundwire: stream: fix programming slave ports for non-continous port maps
	phy: xilinx: add runtime PM support
	phy: xilinx: phy-zynqmp: dynamic clock support for power-save
	phy: xilinx: phy-zynqmp: Fix SGMII linkup failure on resume
	dmaengine: dw: Add peripheral bus width verification
	dmaengine: dw: Add memory bus width verification
	Bluetooth: hci_core: Fix not handling hibernation actions
	iommu: Do not return 0 from map_pages if it doesn't do anything
	netfilter: nf_tables: restore IP sanity checks for netdev/egress
	wifi: iwlwifi: fw: fix wgds rev 3 exact size
	ethtool: check device is present when getting link settings
	netfilter: nf_tables_ipv6: consider network offset in netdev/egress validation
	selftests: forwarding: no_forwarding: Down ports on cleanup
	selftests: forwarding: local_termination: Down ports on cleanup
	bonding: implement xdo_dev_state_free and call it after deletion
	gtp: fix a potential NULL pointer dereference
	sctp: fix association labeling in the duplicate COOKIE-ECHO case
	drm/amd/display: avoid using null object of framebuffer
	net: busy-poll: use ktime_get_ns() instead of local_clock()
	nfc: pn533: Add poll mod list filling check
	soc: qcom: cmd-db: Map shared memory as WC, not WB
	cdc-acm: Add DISABLE_ECHO quirk for GE HealthCare UI Controller
	USB: serial: option: add MeiG Smart SRM825L
	usb: dwc3: omap: add missing depopulate in probe error path
	usb: dwc3: core: Prevent USB core invalid event buffer address access
	usb: dwc3: st: fix probed platform device ref count on probe error path
	usb: dwc3: st: add missing depopulate in probe error path
	usb: core: sysfs: Unmerge @usb3_hardware_lpm_attr_group in remove_power_attributes()
	usb: cdnsp: fix incorrect index in cdnsp_get_hw_deq function
	usb: cdnsp: fix for Link TRB with TC
	phy: zynqmp: Enable reference clock correctly
	igc: Fix reset adapter logics when tx mode change
	igc: Fix qbv tx latency by setting gtxoffset
	scsi: aacraid: Fix double-free on probe failure
	apparmor: fix policy_unpack_test on big endian systems
	fbdev: offb: fix up missing cleanup.h
	Linux 6.1.108

Change-Id: I8ef0e85c12e4e2ecccaf467f40d86c559db7d007
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2024-09-27 15:00:01 +00:00
65 changed files with 645 additions and 310 deletions

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
VERSION = 6 VERSION = 6
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 107 SUBLEVEL = 108
EXTRAVERSION = EXTRAVERSION =
NAME = Curry Ramen NAME = Curry Ramen

View File

@@ -1,11 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
*/
#ifndef _LOONGARCH_DMA_DIRECT_H
#define _LOONGARCH_DMA_DIRECT_H
dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
#endif /* _LOONGARCH_DMA_DIRECT_H */

View File

@@ -5471,6 +5471,9 @@ static void ata_host_release(struct kref *kref)
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i]; struct ata_port *ap = host->ports[i];
if (!ap)
continue;
kfree(ap->pmp_link); kfree(ap->pmp_link);
kfree(ap->slave_link); kfree(ap->slave_link);
kfree(ap); kfree(ap);

View File

@@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/log2.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
@@ -621,12 +622,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct dw_desc *prev; struct dw_desc *prev;
struct dw_desc *first; struct dw_desc *first;
u32 ctllo, ctlhi; u32 ctllo, ctlhi;
u8 m_master = dwc->dws.m_master; u8 lms = DWC_LLP_LMS(dwc->dws.m_master);
u8 lms = DWC_LLP_LMS(m_master);
dma_addr_t reg; dma_addr_t reg;
unsigned int reg_width; unsigned int reg_width;
unsigned int mem_width; unsigned int mem_width;
unsigned int data_width = dw->pdata->data_width[m_master];
unsigned int i; unsigned int i;
struct scatterlist *sg; struct scatterlist *sg;
size_t total_len = 0; size_t total_len = 0;
@@ -660,7 +659,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg); mem = sg_dma_address(sg);
len = sg_dma_len(sg); len = sg_dma_len(sg);
mem_width = __ffs(data_width | mem | len); mem_width = __ffs(sconfig->src_addr_width | mem | len);
slave_sg_todev_fill_desc: slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc); desc = dwc_desc_get(dwc);
@@ -720,7 +719,7 @@ slave_sg_fromdev_fill_desc:
lli_write(desc, sar, reg); lli_write(desc, sar, reg);
lli_write(desc, dar, mem); lli_write(desc, dar, mem);
lli_write(desc, ctlhi, ctlhi); lli_write(desc, ctlhi, ctlhi);
mem_width = __ffs(data_width | mem); mem_width = __ffs(sconfig->dst_addr_width | mem);
lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width)); lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
desc->len = dlen; desc->len = dlen;
@@ -780,17 +779,93 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
} }
EXPORT_SYMBOL_GPL(dw_dma_filter); EXPORT_SYMBOL_GPL(dw_dma_filter);
static int dwc_verify_p_buswidth(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device);
u32 reg_width, max_width;
if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
reg_width = dwc->dma_sconfig.dst_addr_width;
else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM)
reg_width = dwc->dma_sconfig.src_addr_width;
else /* DMA_MEM_TO_MEM */
return 0;
max_width = dw->pdata->data_width[dwc->dws.p_master];
/* Fall-back to 1-byte transfer width if undefined */
if (reg_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
reg_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
else if (!is_power_of_2(reg_width) || reg_width > max_width)
return -EINVAL;
else /* bus width is valid */
return 0;
/* Update undefined addr width value */
if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
dwc->dma_sconfig.dst_addr_width = reg_width;
else /* DMA_DEV_TO_MEM */
dwc->dma_sconfig.src_addr_width = reg_width;
return 0;
}
static int dwc_verify_m_buswidth(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device);
u32 reg_width, reg_burst, mem_width;
mem_width = dw->pdata->data_width[dwc->dws.m_master];
/*
* It's possible to have a data portion locked in the DMA FIFO in case
* of the channel suspension. Subsequent channel disabling will cause
* that data silent loss. In order to prevent that maintain the src and
* dst transfer widths coherency by means of the relation:
* (CTLx.SRC_TR_WIDTH * CTLx.SRC_MSIZE >= CTLx.DST_TR_WIDTH)
* Look for the details in the commit message that brings this change.
*
* Note the DMA configs utilized in the calculations below must have
* been verified to have correct values by this method call.
*/
if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV) {
reg_width = dwc->dma_sconfig.dst_addr_width;
if (mem_width < reg_width)
return -EINVAL;
dwc->dma_sconfig.src_addr_width = mem_width;
} else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM) {
reg_width = dwc->dma_sconfig.src_addr_width;
reg_burst = rounddown_pow_of_two(dwc->dma_sconfig.src_maxburst);
dwc->dma_sconfig.dst_addr_width = min(mem_width, reg_width * reg_burst);
}
return 0;
}
static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
{ {
struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device); struct dw_dma *dw = to_dw_dma(chan->device);
int ret;
memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
dwc->dma_sconfig.src_maxburst = dwc->dma_sconfig.src_maxburst =
clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst); clamp(dwc->dma_sconfig.src_maxburst, 1U, dwc->max_burst);
dwc->dma_sconfig.dst_maxburst = dwc->dma_sconfig.dst_maxburst =
clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst); clamp(dwc->dma_sconfig.dst_maxburst, 1U, dwc->max_burst);
ret = dwc_verify_p_buswidth(chan);
if (ret)
return ret;
ret = dwc_verify_m_buswidth(chan);
if (ret)
return ret;
dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst); dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst); dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);

View File

@@ -743,7 +743,8 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,
uint32_t created = 0; uint32_t created = 0;
uint32_t allocated = 0; uint32_t allocated = 0;
uint32_t tmp, handle = 0; uint32_t tmp, handle = 0;
uint32_t *size = &tmp; uint32_t dummy = 0xffffffff;
uint32_t *size = &dummy;
unsigned idx; unsigned idx;
int i, r = 0; int i, r = 0;

View File

@@ -28,6 +28,7 @@
#include <drm/drm_blend.h> #include <drm/drm_blend.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include "amdgpu.h" #include "amdgpu.h"
@@ -848,10 +849,14 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
} }
afb = to_amdgpu_framebuffer(new_state->fb); afb = to_amdgpu_framebuffer(new_state->fb);
obj = new_state->fb->obj[0]; obj = drm_gem_fb_get_obj(new_state->fb, 0);
if (!obj) {
DRM_ERROR("Failed to get obj from framebuffer\n");
return -EINVAL;
}
rbo = gem_to_amdgpu_bo(obj); rbo = gem_to_amdgpu_bo(obj);
adev = amdgpu_ttm_adev(rbo->tbo.bdev); adev = amdgpu_ttm_adev(rbo->tbo.bdev);
r = amdgpu_bo_reserve(rbo, true); r = amdgpu_bo_reserve(rbo, true);
if (r) { if (r) {
dev_err(adev->dev, "fail to reserve bo (%d)\n", r); dev_err(adev->dev, "fail to reserve bo (%d)\n", r);

View File

@@ -1829,8 +1829,9 @@ static int smu_bump_power_profile_mode(struct smu_context *smu,
} }
static int smu_adjust_power_state_dynamic(struct smu_context *smu, static int smu_adjust_power_state_dynamic(struct smu_context *smu,
enum amd_dpm_forced_level level, enum amd_dpm_forced_level level,
bool skip_display_settings) bool skip_display_settings,
bool force_update)
{ {
int ret = 0; int ret = 0;
int index = 0; int index = 0;
@@ -1859,7 +1860,7 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu,
} }
} }
if (smu_dpm_ctx->dpm_level != level) { if (force_update || smu_dpm_ctx->dpm_level != level) {
ret = smu_asic_set_performance_level(smu, level); ret = smu_asic_set_performance_level(smu, level);
if (ret) { if (ret) {
dev_err(smu->adev->dev, "Failed to set performance level!"); dev_err(smu->adev->dev, "Failed to set performance level!");
@@ -1870,13 +1871,12 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu,
smu_dpm_ctx->dpm_level = level; smu_dpm_ctx->dpm_level = level;
} }
if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
index = fls(smu->workload_mask); index = fls(smu->workload_mask);
index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
workload[0] = smu->workload_setting[index]; workload[0] = smu->workload_setting[index];
if (smu->power_profile_mode != workload[0]) if (force_update || smu->power_profile_mode != workload[0])
smu_bump_power_profile_mode(smu, workload, 0); smu_bump_power_profile_mode(smu, workload, 0);
} }
@@ -1897,11 +1897,13 @@ static int smu_handle_task(struct smu_context *smu,
ret = smu_pre_display_config_changed(smu); ret = smu_pre_display_config_changed(smu);
if (ret) if (ret)
return ret; return ret;
ret = smu_adjust_power_state_dynamic(smu, level, false); ret = smu_adjust_power_state_dynamic(smu, level, false, false);
break; break;
case AMD_PP_TASK_COMPLETE_INIT: case AMD_PP_TASK_COMPLETE_INIT:
ret = smu_adjust_power_state_dynamic(smu, level, true, true);
break;
case AMD_PP_TASK_READJUST_POWER_STATE: case AMD_PP_TASK_READJUST_POWER_STATE:
ret = smu_adjust_power_state_dynamic(smu, level, true); ret = smu_adjust_power_state_dynamic(smu, level, true, false);
break; break;
default: default:
break; break;
@@ -1948,8 +1950,7 @@ static int smu_switch_power_profile(void *handle,
workload[0] = smu->workload_setting[index]; workload[0] = smu->workload_setting[index];
} }
if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)
smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)
smu_bump_power_profile_mode(smu, workload, 0); smu_bump_power_profile_mode(smu, workload, 0);
return 0; return 0;

View File

@@ -552,9 +552,8 @@ static int arm_v7s_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
paddr >= (1ULL << data->iop.cfg.oas))) paddr >= (1ULL << data->iop.cfg.oas)))
return -ERANGE; return -ERANGE;
/* If no access, then nothing to do */
if (!(prot & (IOMMU_READ | IOMMU_WRITE))) if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
return 0; return -EINVAL;
while (pgcount--) { while (pgcount--) {
ret = __arm_v7s_map(data, iova, paddr, pgsize, prot, 1, data->pgd, ret = __arm_v7s_map(data, iova, paddr, pgsize, prot, 1, data->pgd,

View File

@@ -494,9 +494,8 @@ static int arm_lpae_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
if (WARN_ON(iaext || paddr >> cfg->oas)) if (WARN_ON(iaext || paddr >> cfg->oas))
return -ERANGE; return -ERANGE;
/* If no access, then nothing to do */
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
return 0; return -EINVAL;
prot = arm_lpae_prot_to_pte(data, iommu_prot); prot = arm_lpae_prot_to_pte(data, iommu_prot);
ret = __arm_lpae_map(data, iova, paddr, pgsize, pgcount, prot, lvl, ret = __arm_lpae_map(data, iova, paddr, pgsize, pgcount, prot, lvl,

View File

@@ -250,9 +250,8 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
if (WARN_ON(paddr >> cfg->oas)) if (WARN_ON(paddr >> cfg->oas))
return -ERANGE; return -ERANGE;
/* If no access, then nothing to do */
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
return 0; return -EINVAL;
tbl = dart_get_table(data, iova); tbl = dart_get_table(data, iova);

View File

@@ -142,8 +142,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
int err = cmd->error; int err = cmd->error;
/* Flag re-tuning needed on CRC errors */ /* Flag re-tuning needed on CRC errors */
if (cmd->opcode != MMC_SEND_TUNING_BLOCK && if (!mmc_op_tuning(cmd->opcode) &&
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
!host->retune_crc_disable && !host->retune_crc_disable &&
(err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
(mrq->data && mrq->data->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ) ||

View File

@@ -334,8 +334,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
cmdr == MMC_READ_MULTIPLE_BLOCK || cmdr == MMC_READ_MULTIPLE_BLOCK ||
cmdr == MMC_WRITE_BLOCK || cmdr == MMC_WRITE_BLOCK ||
cmdr == MMC_WRITE_MULTIPLE_BLOCK || cmdr == MMC_WRITE_MULTIPLE_BLOCK ||
cmdr == MMC_SEND_TUNING_BLOCK || mmc_op_tuning(cmdr) ||
cmdr == MMC_SEND_TUNING_BLOCK_HS200 ||
cmdr == MMC_GEN_CMD) { cmdr == MMC_GEN_CMD) {
stop->opcode = MMC_STOP_TRANSMISSION; stop->opcode = MMC_STOP_TRANSMISSION;
stop->arg = 0; stop->arg = 0;

View File

@@ -1206,10 +1206,8 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
} }
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
if (events & MSDC_INT_CMDTMO || if ((events & MSDC_INT_CMDTMO && !host->hs400_tuning) ||
(cmd->opcode != MMC_SEND_TUNING_BLOCK && (!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning))
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
!host->hs400_tuning))
/* /*
* should not clear fifo/interrupt as the tune data * should not clear fifo/interrupt as the tune data
* may have alreay come when cmd19/cmd21 gets response * may have alreay come when cmd19/cmd21 gets response
@@ -1301,11 +1299,9 @@ static void msdc_start_command(struct msdc_host *host,
static void msdc_cmd_next(struct msdc_host *host, static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd) struct mmc_request *mrq, struct mmc_command *cmd)
{ {
if ((cmd->error && if ((cmd->error && !host->hs400_tuning &&
!(cmd->error == -EILSEQ && !(cmd->error == -EILSEQ &&
(cmd->opcode == MMC_SEND_TUNING_BLOCK || mmc_op_tuning(cmd->opcode))) ||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
host->hs400_tuning))) ||
(mrq->sbc && mrq->sbc->error)) (mrq->sbc && mrq->sbc->error))
msdc_request_done(host, mrq); msdc_request_done(host, mrq);
else if (cmd == mrq->sbc) else if (cmd == mrq->sbc)

View File

@@ -2218,8 +2218,7 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
if (!msm_host->use_cdr) if (!msm_host->use_cdr)
break; break;
if ((msm_host->transfer_mode & SDHCI_TRNS_READ) && if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 && !mmc_op_tuning(SDHCI_GET_CMD(val)))
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
sdhci_msm_set_cdr(host, true); sdhci_msm_set_cdr(host, true);
else else
sdhci_msm_set_cdr(host, false); sdhci_msm_set_cdr(host, false);

View File

@@ -326,8 +326,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
(host->timing != MMC_TIMING_UHS_SDR50)) (host->timing != MMC_TIMING_UHS_SDR50))
return sdhci_execute_tuning(mmc, opcode); return sdhci_execute_tuning(mmc, opcode);
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && if (WARN_ON(!mmc_op_tuning(opcode)))
(opcode != MMC_SEND_TUNING_BLOCK)))
return -EINVAL; return -EINVAL;
/* Force power mode enter L0 */ /* Force power mode enter L0 */

View File

@@ -268,13 +268,9 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{ {
bool is_tuning_cmd = 0; bool is_tuning_cmd = 0;
bool clk_enabled; bool clk_enabled;
u8 cmd;
if (reg == SDHCI_COMMAND) { if (reg == SDHCI_COMMAND)
cmd = SDHCI_GET_CMD(val); is_tuning_cmd = mmc_op_tuning(SDHCI_GET_CMD(val));
is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK ||
cmd == MMC_SEND_TUNING_BLOCK_HS200;
}
if (is_tuning_cmd) if (is_tuning_cmd)
clk_enabled = tegra_sdhci_configure_card_clk(host, 0); clk_enabled = tegra_sdhci_configure_card_clk(host, 0);

View File

@@ -1712,8 +1712,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
flags |= SDHCI_CMD_INDEX; flags |= SDHCI_CMD_INDEX;
/* CMD19 is special in that the Data Present Select should be set */ /* CMD19 is special in that the Data Present Select should be set */
if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || if (cmd->data || mmc_op_tuning(cmd->opcode))
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
flags |= SDHCI_CMD_DATA; flags |= SDHCI_CMD_DATA;
timeout = jiffies; timeout = jiffies;
@@ -3396,8 +3395,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{ {
u32 command;
/* /*
* CMD19 generates _only_ Buffer Read Ready interrupt if * CMD19 generates _only_ Buffer Read Ready interrupt if
* use sdhci_send_tuning. * use sdhci_send_tuning.
@@ -3406,9 +3403,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* SDHCI_INT_DATA_AVAIL always there, stuck in irq storm. * SDHCI_INT_DATA_AVAIL always there, stuck in irq storm.
*/ */
if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) { if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) {
command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); if (mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) {
if (command == MMC_SEND_TUNING_BLOCK ||
command == MMC_SEND_TUNING_BLOCK_HS200) {
host->tuning_done = 1; host->tuning_done = 1;
wake_up(&host->buf_ready_int); wake_up(&host->buf_ready_int);
return; return;

View File

@@ -577,12 +577,47 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
__func__); __func__);
} else { } else {
slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs); slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
if (slave->dev->xfrmdev_ops->xdo_dev_state_free)
slave->dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
} }
} }
spin_unlock_bh(&bond->ipsec_lock); spin_unlock_bh(&bond->ipsec_lock);
rcu_read_unlock(); rcu_read_unlock();
} }
static void bond_ipsec_free_sa(struct xfrm_state *xs)
{
struct net_device *bond_dev = xs->xso.dev;
struct net_device *real_dev;
netdevice_tracker tracker;
struct bonding *bond;
struct slave *slave;
if (!bond_dev)
return;
rcu_read_lock();
bond = netdev_priv(bond_dev);
slave = rcu_dereference(bond->curr_active_slave);
real_dev = slave ? slave->dev : NULL;
netdev_hold(real_dev, &tracker, GFP_ATOMIC);
rcu_read_unlock();
if (!slave)
goto out;
if (!xs->xso.real_dev)
goto out;
WARN_ON(xs->xso.real_dev != real_dev);
if (real_dev && real_dev->xfrmdev_ops &&
real_dev->xfrmdev_ops->xdo_dev_state_free)
real_dev->xfrmdev_ops->xdo_dev_state_free(xs);
out:
netdev_put(real_dev, &tracker);
}
/** /**
* bond_ipsec_offload_ok - can this packet use the xfrm hw offload * bond_ipsec_offload_ok - can this packet use the xfrm hw offload
* @skb: current data packet * @skb: current data packet
@@ -623,6 +658,7 @@ out:
static const struct xfrmdev_ops bond_xfrmdev_ops = { static const struct xfrmdev_ops bond_xfrmdev_ops = {
.xdo_dev_state_add = bond_ipsec_add_sa, .xdo_dev_state_add = bond_ipsec_add_sa,
.xdo_dev_state_delete = bond_ipsec_del_sa, .xdo_dev_state_delete = bond_ipsec_del_sa,
.xdo_dev_state_free = bond_ipsec_free_sa,
.xdo_dev_offload_ok = bond_ipsec_offload_ok, .xdo_dev_offload_ok = bond_ipsec_offload_ok,
}; };
#endif /* CONFIG_XFRM_OFFLOAD */ #endif /* CONFIG_XFRM_OFFLOAD */

View File

@@ -49,12 +49,19 @@ static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
return new_flags; return new_flags;
} }
static bool igc_tsn_is_tx_mode_in_tsn(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
return !!(rd32(IGC_TQAVCTRL) & IGC_TQAVCTRL_TRANSMIT_MODE_TSN);
}
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter) void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)
{ {
struct igc_hw *hw = &adapter->hw; struct igc_hw *hw = &adapter->hw;
u16 txoffset; u16 txoffset;
if (!is_any_launchtime(adapter)) if (!igc_tsn_is_tx_mode_in_tsn(adapter))
return; return;
switch (adapter->link_speed) { switch (adapter->link_speed) {

View File

@@ -51,32 +51,6 @@ static int mana_hwc_verify_resp_msg(const struct hwc_caller_ctx *caller_ctx,
return 0; return 0;
} }
static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,
const struct gdma_resp_hdr *resp_msg)
{
struct hwc_caller_ctx *ctx;
int err;
if (!test_bit(resp_msg->response.hwc_msg_id,
hwc->inflight_msg_res.map)) {
dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n",
resp_msg->response.hwc_msg_id);
return;
}
ctx = hwc->caller_ctx + resp_msg->response.hwc_msg_id;
err = mana_hwc_verify_resp_msg(ctx, resp_msg, resp_len);
if (err)
goto out;
ctx->status_code = resp_msg->status;
memcpy(ctx->output_buf, resp_msg, resp_len);
out:
ctx->error = err;
complete(&ctx->comp_event);
}
static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq, static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq,
struct hwc_work_request *req) struct hwc_work_request *req)
{ {
@@ -100,6 +74,40 @@ static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq,
return err; return err;
} }
static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,
struct hwc_work_request *rx_req)
{
const struct gdma_resp_hdr *resp_msg = rx_req->buf_va;
struct hwc_caller_ctx *ctx;
int err;
if (!test_bit(resp_msg->response.hwc_msg_id,
hwc->inflight_msg_res.map)) {
dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n",
resp_msg->response.hwc_msg_id);
mana_hwc_post_rx_wqe(hwc->rxq, rx_req);
return;
}
ctx = hwc->caller_ctx + resp_msg->response.hwc_msg_id;
err = mana_hwc_verify_resp_msg(ctx, resp_msg, resp_len);
if (err)
goto out;
ctx->status_code = resp_msg->status;
memcpy(ctx->output_buf, resp_msg, resp_len);
out:
ctx->error = err;
/* Must post rx wqe before complete(), otherwise the next rx may
* hit no_wqe error.
*/
mana_hwc_post_rx_wqe(hwc->rxq, rx_req);
complete(&ctx->comp_event);
}
static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self, static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self,
struct gdma_event *event) struct gdma_event *event)
{ {
@@ -216,14 +224,12 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
return; return;
} }
mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, resp); mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, rx_req);
/* Do no longer use 'resp', because the buffer is posted to the HW /* Can no longer use 'resp', because the buffer is posted to the HW
* in the below mana_hwc_post_rx_wqe(). * in mana_hwc_handle_resp() above.
*/ */
resp = NULL; resp = NULL;
mana_hwc_post_rx_wqe(hwc_rxq, rx_req);
} }
static void mana_hwc_tx_event_handler(void *ctx, u32 gdma_txq_id, static void mana_hwc_tx_event_handler(void *ctx, u32 gdma_txq_id,

View File

@@ -1219,7 +1219,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
sock = sockfd_lookup(fd, &err); sock = sockfd_lookup(fd, &err);
if (!sock) { if (!sock) {
pr_debug("gtp socket fd=%d not found\n", fd); pr_debug("gtp socket fd=%d not found\n", fd);
return NULL; return ERR_PTR(err);
} }
sk = sock->sk; sk = sock->sk;

View File

@@ -825,22 +825,25 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt)
entry = &wifi_pkg->package.elements[entry_idx]; entry = &wifi_pkg->package.elements[entry_idx];
entry_idx++; entry_idx++;
if (entry->type != ACPI_TYPE_INTEGER || if (entry->type != ACPI_TYPE_INTEGER ||
entry->integer.value > num_profiles) { entry->integer.value > num_profiles ||
entry->integer.value <
rev_data[idx].min_profiles) {
ret = -EINVAL; ret = -EINVAL;
goto out_free; goto out_free;
} }
num_profiles = entry->integer.value;
/* /*
* this also validates >= min_profiles since we * Check to see if we received package count
* otherwise wouldn't have gotten the data when * same as max # of profiles
* looking up in ACPI
*/ */
if (wifi_pkg->package.count != if (wifi_pkg->package.count !=
hdr_size + profile_size * num_profiles) { hdr_size + profile_size * num_profiles) {
ret = -EINVAL; ret = -EINVAL;
goto out_free; goto out_free;
} }
/* Number of valid profiles */
num_profiles = entry->integer.value;
} }
goto read_table; goto read_table;
} }

View File

@@ -4362,11 +4362,27 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info)) if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info))
wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
wiphy->bands[NL80211_BAND_2GHZ] = &mwifiex_band_2ghz; wiphy->bands[NL80211_BAND_2GHZ] = devm_kmemdup(adapter->dev,
if (adapter->config_bands & BAND_A) &mwifiex_band_2ghz,
wiphy->bands[NL80211_BAND_5GHZ] = &mwifiex_band_5ghz; sizeof(mwifiex_band_2ghz),
else GFP_KERNEL);
if (!wiphy->bands[NL80211_BAND_2GHZ]) {
ret = -ENOMEM;
goto err;
}
if (adapter->config_bands & BAND_A) {
wiphy->bands[NL80211_BAND_5GHZ] = devm_kmemdup(adapter->dev,
&mwifiex_band_5ghz,
sizeof(mwifiex_band_5ghz),
GFP_KERNEL);
if (!wiphy->bands[NL80211_BAND_5GHZ]) {
ret = -ENOMEM;
goto err;
}
} else {
wiphy->bands[NL80211_BAND_5GHZ] = NULL; wiphy->bands[NL80211_BAND_5GHZ] = NULL;
}
if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info))
wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs;
@@ -4459,8 +4475,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
if (ret < 0) { if (ret < 0) {
mwifiex_dbg(adapter, ERROR, mwifiex_dbg(adapter, ERROR,
"%s: wiphy_register failed: %d\n", __func__, ret); "%s: wiphy_register failed: %d\n", __func__, ret);
wiphy_free(wiphy); goto err;
return ret;
} }
if (!adapter->regd) { if (!adapter->regd) {
@@ -4502,4 +4517,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
adapter->wiphy = wiphy; adapter->wiphy = wiphy;
return ret; return ret;
err:
wiphy_free(wiphy);
return ret;
} }

View File

@@ -370,8 +370,11 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif)
ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset, ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
skb->len - ieoffset); skb->len - ieoffset);
if (unlikely(!ptr)) if (!ptr) {
/* No RSN IE is fine in open networks */
ret = 0;
goto free_skb; goto free_skb;
}
ptr += pairwise_cipher_suite_count_offset; ptr += pairwise_cipher_suite_count_offset;
if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))

View File

@@ -1723,6 +1723,11 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
} }
pn533_poll_create_mod_list(dev, im_protocols, tm_protocols); pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
if (!dev->poll_mod_count) {
nfc_err(dev->dev,
"Poll mod list is empty\n");
return -EINVAL;
}
/* Do not always start polling from the same modulation */ /* Do not always start polling from the same modulation */
get_random_bytes(&rand_mod, sizeof(rand_mod)); get_random_bytes(&rand_mod, sizeof(rand_mod));

View File

@@ -21,6 +21,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <dt-bindings/phy/phy.h> #include <dt-bindings/phy/phy.h>
@@ -80,7 +81,8 @@
/* Reference clock selection parameters */ /* Reference clock selection parameters */
#define L0_Ln_REF_CLK_SEL(n) (0x2860 + (n) * 4) #define L0_Ln_REF_CLK_SEL(n) (0x2860 + (n) * 4)
#define L0_REF_CLK_SEL_MASK 0x8f #define L0_REF_CLK_LCL_SEL BIT(7)
#define L0_REF_CLK_SEL_MASK 0x9f
/* Calibration digital logic parameters */ /* Calibration digital logic parameters */
#define L3_TM_CALIB_DIG19 0xec4c #define L3_TM_CALIB_DIG19 0xec4c
@@ -165,6 +167,24 @@
/* Timeout values */ /* Timeout values */
#define TIMEOUT_US 1000 #define TIMEOUT_US 1000
/* Lane 0/1/2/3 offset */
#define DIG_8(n) ((0x4000 * (n)) + 0x1074)
#define ILL13(n) ((0x4000 * (n)) + 0x1994)
#define DIG_10(n) ((0x4000 * (n)) + 0x107c)
#define RST_DLY(n) ((0x4000 * (n)) + 0x19a4)
#define BYP_15(n) ((0x4000 * (n)) + 0x1038)
#define BYP_12(n) ((0x4000 * (n)) + 0x102c)
#define MISC3(n) ((0x4000 * (n)) + 0x19ac)
#define EQ11(n) ((0x4000 * (n)) + 0x1978)
static u32 save_reg_address[] = {
/* Lane 0/1/2/3 Register */
DIG_8(0), ILL13(0), DIG_10(0), RST_DLY(0), BYP_15(0), BYP_12(0), MISC3(0), EQ11(0),
DIG_8(1), ILL13(1), DIG_10(1), RST_DLY(1), BYP_15(1), BYP_12(1), MISC3(1), EQ11(1),
DIG_8(2), ILL13(2), DIG_10(2), RST_DLY(2), BYP_15(2), BYP_12(2), MISC3(2), EQ11(2),
DIG_8(3), ILL13(3), DIG_10(3), RST_DLY(3), BYP_15(3), BYP_12(3), MISC3(3), EQ11(3),
};
struct xpsgtr_dev; struct xpsgtr_dev;
/** /**
@@ -213,6 +233,7 @@ struct xpsgtr_phy {
* @tx_term_fix: fix for GT issue * @tx_term_fix: fix for GT issue
* @saved_icm_cfg0: stored value of ICM CFG0 register * @saved_icm_cfg0: stored value of ICM CFG0 register
* @saved_icm_cfg1: stored value of ICM CFG1 register * @saved_icm_cfg1: stored value of ICM CFG1 register
* @saved_regs: registers to be saved/restored during suspend/resume
*/ */
struct xpsgtr_dev { struct xpsgtr_dev {
struct device *dev; struct device *dev;
@@ -225,6 +246,7 @@ struct xpsgtr_dev {
bool tx_term_fix; bool tx_term_fix;
unsigned int saved_icm_cfg0; unsigned int saved_icm_cfg0;
unsigned int saved_icm_cfg1; unsigned int saved_icm_cfg1;
u32 *saved_regs;
}; };
/* /*
@@ -298,6 +320,32 @@ static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
writel((readl(addr) & ~clr) | set, addr); writel((readl(addr) & ~clr) | set, addr);
} }
/**
* xpsgtr_save_lane_regs - Saves registers on suspend
* @gtr_dev: pointer to phy controller context structure
*/
static void xpsgtr_save_lane_regs(struct xpsgtr_dev *gtr_dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
gtr_dev->saved_regs[i] = xpsgtr_read(gtr_dev,
save_reg_address[i]);
}
/**
* xpsgtr_restore_lane_regs - Restores registers on resume
* @gtr_dev: pointer to phy controller context structure
*/
static void xpsgtr_restore_lane_regs(struct xpsgtr_dev *gtr_dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
xpsgtr_write(gtr_dev, save_reg_address[i],
gtr_dev->saved_regs[i]);
}
/* /*
* Hardware Configuration * Hardware Configuration
*/ */
@@ -349,11 +397,12 @@ static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
PLL_FREQ_MASK, ssc->pll_ref_clk); PLL_FREQ_MASK, ssc->pll_ref_clk);
/* Enable lane clock sharing, if required */ /* Enable lane clock sharing, if required */
if (gtr_phy->refclk != gtr_phy->lane) { if (gtr_phy->refclk == gtr_phy->lane)
/* Lane3 Ref Clock Selection Register */ xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
L0_REF_CLK_SEL_MASK, L0_REF_CLK_LCL_SEL);
else
xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane), xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk); L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk);
}
/* SSC step size [7:0] */ /* SSC step size [7:0] */
xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB, xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB,
@@ -572,6 +621,10 @@ static int xpsgtr_phy_init(struct phy *phy)
mutex_lock(&gtr_dev->gtr_mutex); mutex_lock(&gtr_dev->gtr_mutex);
/* Configure and enable the clock when peripheral phy_init call */
if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
goto out;
/* Skip initialization if not required. */ /* Skip initialization if not required. */
if (!xpsgtr_phy_init_required(gtr_phy)) if (!xpsgtr_phy_init_required(gtr_phy))
goto out; goto out;
@@ -616,9 +669,13 @@ out:
static int xpsgtr_phy_exit(struct phy *phy) static int xpsgtr_phy_exit(struct phy *phy)
{ {
struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy); struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
gtr_phy->skip_phy_init = false; gtr_phy->skip_phy_init = false;
/* Ensure that disable clock only, which configure for lane */
clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
return 0; return 0;
} }
@@ -821,34 +878,27 @@ static struct phy *xpsgtr_xlate(struct device *dev,
* Power Management * Power Management
*/ */
static int __maybe_unused xpsgtr_suspend(struct device *dev) static int xpsgtr_runtime_suspend(struct device *dev)
{ {
struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
unsigned int i;
/* Save the snapshot ICM_CFG registers. */ /* Save the snapshot ICM_CFG registers. */
gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) xpsgtr_save_lane_regs(gtr_dev);
clk_disable_unprepare(gtr_dev->clk[i]);
return 0; return 0;
} }
static int __maybe_unused xpsgtr_resume(struct device *dev) static int xpsgtr_runtime_resume(struct device *dev)
{ {
struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
unsigned int icm_cfg0, icm_cfg1; unsigned int icm_cfg0, icm_cfg1;
unsigned int i; unsigned int i;
bool skip_phy_init; bool skip_phy_init;
int err;
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { xpsgtr_restore_lane_regs(gtr_dev);
err = clk_prepare_enable(gtr_dev->clk[i]);
if (err)
goto err_clk_put;
}
icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
@@ -869,18 +919,10 @@ static int __maybe_unused xpsgtr_resume(struct device *dev)
gtr_dev->phys[i].skip_phy_init = skip_phy_init; gtr_dev->phys[i].skip_phy_init = skip_phy_init;
return 0; return 0;
err_clk_put:
while (i--)
clk_disable_unprepare(gtr_dev->clk[i]);
return err;
} }
static const struct dev_pm_ops xpsgtr_pm_ops = { static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend,
SET_SYSTEM_SLEEP_PM_OPS(xpsgtr_suspend, xpsgtr_resume) xpsgtr_runtime_resume, NULL);
};
/* /*
* Probe & Platform Driver * Probe & Platform Driver
*/ */
@@ -888,7 +930,6 @@ static const struct dev_pm_ops xpsgtr_pm_ops = {
static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
{ {
unsigned int refclk; unsigned int refclk;
int ret;
for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
unsigned long rate; unsigned long rate;
@@ -899,19 +940,14 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
snprintf(name, sizeof(name), "ref%u", refclk); snprintf(name, sizeof(name), "ref%u", refclk);
clk = devm_clk_get_optional(gtr_dev->dev, name); clk = devm_clk_get_optional(gtr_dev->dev, name);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), return dev_err_probe(gtr_dev->dev, PTR_ERR(clk),
"Failed to get reference clock %u\n", "Failed to get ref clock %u\n",
refclk); refclk);
goto err_clk_put;
} }
if (!clk) if (!clk)
continue; continue;
ret = clk_prepare_enable(clk);
if (ret)
goto err_clk_put;
gtr_dev->clk[refclk] = clk; gtr_dev->clk[refclk] = clk;
/* /*
@@ -931,18 +967,11 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
dev_err(gtr_dev->dev, dev_err(gtr_dev->dev,
"Invalid rate %lu for reference clock %u\n", "Invalid rate %lu for reference clock %u\n",
rate, refclk); rate, refclk);
ret = -EINVAL; return -EINVAL;
goto err_clk_put;
} }
} }
return 0; return 0;
err_clk_put:
while (refclk--)
clk_disable_unprepare(gtr_dev->clk[refclk]);
return ret;
} }
static int xpsgtr_probe(struct platform_device *pdev) static int xpsgtr_probe(struct platform_device *pdev)
@@ -951,7 +980,6 @@ static int xpsgtr_probe(struct platform_device *pdev)
struct xpsgtr_dev *gtr_dev; struct xpsgtr_dev *gtr_dev;
struct phy_provider *provider; struct phy_provider *provider;
unsigned int port; unsigned int port;
unsigned int i;
int ret; int ret;
gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL);
@@ -991,8 +1019,7 @@ static int xpsgtr_probe(struct platform_device *pdev)
phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n"); dev_err(&pdev->dev, "failed to create PHY\n");
ret = PTR_ERR(phy); return PTR_ERR(phy);
goto err_clk_put;
} }
gtr_phy->phy = phy; gtr_phy->phy = phy;
@@ -1003,16 +1030,36 @@ static int xpsgtr_probe(struct platform_device *pdev)
provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate);
if (IS_ERR(provider)) { if (IS_ERR(provider)) {
dev_err(&pdev->dev, "registering provider failed\n"); dev_err(&pdev->dev, "registering provider failed\n");
ret = PTR_ERR(provider); return PTR_ERR(provider);
goto err_clk_put;
} }
pm_runtime_set_active(gtr_dev->dev);
pm_runtime_enable(gtr_dev->dev);
ret = pm_runtime_resume_and_get(gtr_dev->dev);
if (ret < 0) {
pm_runtime_disable(gtr_dev->dev);
return ret;
}
gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
sizeof(save_reg_address),
GFP_KERNEL);
if (!gtr_dev->saved_regs)
return -ENOMEM;
return 0; return 0;
}
err_clk_put: static int xpsgtr_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) {
clk_disable_unprepare(gtr_dev->clk[i]); struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev);
return ret; pm_runtime_disable(gtr_dev->dev);
pm_runtime_put_noidle(gtr_dev->dev);
pm_runtime_set_suspended(gtr_dev->dev);
return 0;
} }
static const struct of_device_id xpsgtr_of_match[] = { static const struct of_device_id xpsgtr_of_match[] = {
@@ -1024,10 +1071,11 @@ MODULE_DEVICE_TABLE(of, xpsgtr_of_match);
static struct platform_driver xpsgtr_driver = { static struct platform_driver xpsgtr_driver = {
.probe = xpsgtr_probe, .probe = xpsgtr_probe,
.remove = xpsgtr_remove,
.driver = { .driver = {
.name = "xilinx-psgtr", .name = "xilinx-psgtr",
.of_match_table = xpsgtr_of_match, .of_match_table = xpsgtr_of_match,
.pm = &xpsgtr_pm_ops, .pm = pm_ptr(&xpsgtr_pm_ops),
}, },
}; };

View File

@@ -709,32 +709,35 @@ static int mtk_pinconf_bias_set_rsel(struct mtk_pinctrl *hw,
{ {
int err, rsel_val; int err, rsel_val;
if (!pullup && arg == MTK_DISABLE)
return 0;
if (hw->rsel_si_unit) { if (hw->rsel_si_unit) {
/* find pin rsel_index from pin_rsel array*/ /* find pin rsel_index from pin_rsel array*/
err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, &rsel_val); err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, &rsel_val);
if (err) if (err)
goto out; return err;
} else { } else {
if (arg < MTK_PULL_SET_RSEL_000 || if (arg < MTK_PULL_SET_RSEL_000 || arg > MTK_PULL_SET_RSEL_111)
arg > MTK_PULL_SET_RSEL_111) { return -EINVAL;
err = -EINVAL;
goto out;
}
rsel_val = arg - MTK_PULL_SET_RSEL_000; rsel_val = arg - MTK_PULL_SET_RSEL_000;
} }
err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_RSEL, rsel_val); return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_RSEL, rsel_val);
if (err) }
goto out;
err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, MTK_ENABLE); static int mtk_pinconf_bias_set_pu_pd_rsel(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc,
u32 pullup, u32 arg)
{
u32 enable = arg == MTK_DISABLE ? MTK_DISABLE : MTK_ENABLE;
int err;
out: if (arg != MTK_DISABLE) {
return err; err = mtk_pinconf_bias_set_rsel(hw, desc, pullup, arg);
if (err)
return err;
}
return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable);
} }
int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
@@ -750,22 +753,22 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
try_all_type = MTK_PULL_TYPE_MASK; try_all_type = MTK_PULL_TYPE_MASK;
if (try_all_type & MTK_PULL_RSEL_TYPE) { if (try_all_type & MTK_PULL_RSEL_TYPE) {
err = mtk_pinconf_bias_set_rsel(hw, desc, pullup, arg); err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PU_PD_TYPE) { if (try_all_type & MTK_PULL_PU_PD_TYPE) {
err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg); err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PULLSEL_TYPE) { if (try_all_type & MTK_PULL_PULLSEL_TYPE) {
err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc, err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc,
pullup, arg); pullup, arg);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE) if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)
@@ -803,9 +806,9 @@ static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw,
return 0; return 0;
} }
static int mtk_pinconf_bias_get_rsel(struct mtk_pinctrl *hw, static int mtk_pinconf_bias_get_pu_pd_rsel(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, const struct mtk_pin_desc *desc,
u32 *pullup, u32 *enable) u32 *pullup, u32 *enable)
{ {
int pu, pd, rsel, err; int pu, pd, rsel, err;
@@ -939,22 +942,22 @@ int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
try_all_type = MTK_PULL_TYPE_MASK; try_all_type = MTK_PULL_TYPE_MASK;
if (try_all_type & MTK_PULL_RSEL_TYPE) { if (try_all_type & MTK_PULL_RSEL_TYPE) {
err = mtk_pinconf_bias_get_rsel(hw, desc, pullup, enable); err = mtk_pinconf_bias_get_pu_pd_rsel(hw, desc, pullup, enable);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PU_PD_TYPE) { if (try_all_type & MTK_PULL_PU_PD_TYPE) {
err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable); err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PULLSEL_TYPE) { if (try_all_type & MTK_PULL_PULLSEL_TYPE) {
err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc, err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc,
pullup, enable); pullup, enable);
if (!err) if (!err)
return err; return 0;
} }
if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE) if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)

View File

@@ -3803,7 +3803,7 @@ static struct rockchip_pin_bank rk3328_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0), PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0),
PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0), PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0, PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0,
0, IOMUX_WIDTH_2BIT,
IOMUX_WIDTH_3BIT, IOMUX_WIDTH_3BIT,
0), 0),
PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3",

View File

@@ -350,6 +350,8 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
return -ENOTSUPP; return -ENOTSUPP;
fselector = setting->func; fselector = setting->func;
function = pinmux_generic_get_function(pctldev, fselector); function = pinmux_generic_get_function(pctldev, fselector);
if (!function)
return -EINVAL;
*func = function->data; *func = function->data;
if (!(*func)) { if (!(*func)) {
dev_err(pcs->dev, "%s could not find function%i\n", dev_err(pcs->dev, "%s could not find function%i\n",

View File

@@ -642,6 +642,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
if (aac_comm_init(dev)<0){ if (aac_comm_init(dev)<0){
kfree(dev->queues); kfree(dev->queues);
dev->queues = NULL;
return NULL; return NULL;
} }
/* /*
@@ -649,6 +650,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
*/ */
if (aac_fib_setup(dev) < 0) { if (aac_fib_setup(dev) < 0) {
kfree(dev->queues); kfree(dev->queues);
dev->queues = NULL;
return NULL; return NULL;
} }

View File

@@ -354,7 +354,7 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB); cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC);
if (!cmd_db_header) { if (!cmd_db_header) {
ret = -ENOMEM; ret = -ENOMEM;
cmd_db_header = NULL; cmd_db_header = NULL;

View File

@@ -1272,18 +1272,18 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
unsigned int port_num) unsigned int port_num)
{ {
struct sdw_dpn_prop *dpn_prop; struct sdw_dpn_prop *dpn_prop;
u8 num_ports; unsigned long mask;
int i; int i;
if (direction == SDW_DATA_DIR_TX) { if (direction == SDW_DATA_DIR_TX) {
num_ports = hweight32(slave->prop.source_ports); mask = slave->prop.source_ports;
dpn_prop = slave->prop.src_dpn_prop; dpn_prop = slave->prop.src_dpn_prop;
} else { } else {
num_ports = hweight32(slave->prop.sink_ports); mask = slave->prop.sink_ports;
dpn_prop = slave->prop.sink_dpn_prop; dpn_prop = slave->prop.sink_dpn_prop;
} }
for (i = 0; i < num_ports; i++) { for_each_set_bit(i, &mask, 32) {
if (dpn_prop[i].num == port_num) if (dpn_prop[i].num == port_num)
return &dpn_prop[i]; return &dpn_prop[i];
} }

View File

@@ -235,7 +235,7 @@ static int thermal_of_populate_trip(struct device_node *np,
static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips) static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
{ {
struct thermal_trip *tt; struct thermal_trip *tt;
struct device_node *trips, *trip; struct device_node *trips;
int ret, count; int ret, count;
trips = of_get_child_by_name(np, "trips"); trips = of_get_child_by_name(np, "trips");
@@ -260,7 +260,7 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
*ntrips = count; *ntrips = count;
count = 0; count = 0;
for_each_child_of_node(trips, trip) { for_each_child_of_node_scoped(trips, trip) {
ret = thermal_of_populate_trip(trip, &tt[count++]); ret = thermal_of_populate_trip(trip, &tt[count++]);
if (ret) if (ret)
goto out_kfree; goto out_kfree;
@@ -294,14 +294,14 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int
* Search for each thermal zone, a defined sensor * Search for each thermal zone, a defined sensor
* corresponding to the one passed as parameter * corresponding to the one passed as parameter
*/ */
for_each_available_child_of_node(np, tz) { for_each_available_child_of_node_scoped(np, child) {
int count, i; int count, i;
count = of_count_phandle_with_args(tz, "thermal-sensors", count = of_count_phandle_with_args(child, "thermal-sensors",
"#thermal-sensor-cells"); "#thermal-sensor-cells");
if (count <= 0) { if (count <= 0) {
pr_err("%pOFn: missing thermal sensor\n", tz); pr_err("%pOFn: missing thermal sensor\n", child);
tz = ERR_PTR(-EINVAL); tz = ERR_PTR(-EINVAL);
goto out; goto out;
} }
@@ -310,18 +310,19 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int
int ret; int ret;
ret = of_parse_phandle_with_args(tz, "thermal-sensors", ret = of_parse_phandle_with_args(child, "thermal-sensors",
"#thermal-sensor-cells", "#thermal-sensor-cells",
i, &sensor_specs); i, &sensor_specs);
if (ret < 0) { if (ret < 0) {
pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", tz, ret); pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", child, ret);
tz = ERR_PTR(ret); tz = ERR_PTR(ret);
goto out; goto out;
} }
if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ? if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
sensor_specs.args[0] : 0)) { sensor_specs.args[0] : 0)) {
pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, tz); pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child);
tz = no_free_ptr(child);
goto out; goto out;
} }
} }

View File

@@ -811,6 +811,7 @@ struct cdnsp_stream_info {
* generate Missed Service Error Event. * generate Missed Service Error Event.
* Set skip flag when receive a Missed Service Error Event and * Set skip flag when receive a Missed Service Error Event and
* process the missed tds on the endpoint ring. * process the missed tds on the endpoint ring.
* @wa1_nop_trb: hold pointer to NOP trb.
*/ */
struct cdnsp_ep { struct cdnsp_ep {
struct usb_ep endpoint; struct usb_ep endpoint;
@@ -838,6 +839,8 @@ struct cdnsp_ep {
#define EP_UNCONFIGURED BIT(7) #define EP_UNCONFIGURED BIT(7)
bool skip; bool skip;
union cdnsp_trb *wa1_nop_trb;
}; };
/** /**

View File

@@ -402,7 +402,7 @@ static u64 cdnsp_get_hw_deq(struct cdnsp_device *pdev,
struct cdnsp_stream_ctx *st_ctx; struct cdnsp_stream_ctx *st_ctx;
struct cdnsp_ep *pep; struct cdnsp_ep *pep;
pep = &pdev->eps[stream_id]; pep = &pdev->eps[ep_index];
if (pep->ep_state & EP_HAS_STREAMS) { if (pep->ep_state & EP_HAS_STREAMS) {
st_ctx = &pep->stream_info.stream_ctx_array[stream_id]; st_ctx = &pep->stream_info.stream_ctx_array[stream_id];
@@ -1902,6 +1902,23 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
if (ret) if (ret)
return ret; return ret;
/*
* workaround 1: STOP EP command on LINK TRB with TC bit set to 1
* causes that internal cycle bit can have incorrect state after
* command complete. In consequence empty transfer ring can be
* incorrectly detected when EP is resumed.
* NOP TRB before LINK TRB avoid such scenario. STOP EP command is
* then on NOP TRB and internal cycle bit is not changed and have
* correct value.
*/
if (pep->wa1_nop_trb) {
field = le32_to_cpu(pep->wa1_nop_trb->trans_event.flags);
field ^= TRB_CYCLE;
pep->wa1_nop_trb->trans_event.flags = cpu_to_le32(field);
pep->wa1_nop_trb = NULL;
}
/* /*
* Don't give the first TRB to the hardware (by toggling the cycle bit) * Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle * until we've finished creating all the other TRBs. The ring's cycle
@@ -1997,6 +2014,17 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
send_addr = addr; send_addr = addr;
} }
if (cdnsp_trb_is_link(ring->enqueue + 1)) {
field = TRB_TYPE(TRB_TR_NOOP) | TRB_IOC;
if (!ring->cycle_state)
field |= TRB_CYCLE;
pep->wa1_nop_trb = ring->enqueue;
cdnsp_queue_trb(pdev, ring, 0, 0x0, 0x0,
TRB_INTR_TARGET(0), field);
}
cdnsp_check_trb_math(preq, enqd_len); cdnsp_check_trb_math(preq, enqd_len);
ret = cdnsp_giveback_first_trb(pdev, pep, preq->request.stream_id, ret = cdnsp_giveback_first_trb(pdev, pep, preq->request.stream_id,
start_cycle, start_trb); start_cycle, start_trb);

View File

@@ -1737,6 +1737,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
.driver_info = SINGLE_RX_URB, .driver_info = SINGLE_RX_URB,
}, },
{ USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */
.driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */
},
{ USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
}, },

View File

@@ -670,6 +670,7 @@ static int add_power_attributes(struct device *dev)
static void remove_power_attributes(struct device *dev) static void remove_power_attributes(struct device *dev)
{ {
sysfs_unmerge_group(&dev->kobj, &usb3_hardware_lpm_attr_group);
sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
sysfs_unmerge_group(&dev->kobj, &power_attr_group); sysfs_unmerge_group(&dev->kobj, &power_attr_group);
} }

View File

@@ -553,9 +553,17 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc)
void dwc3_event_buffers_cleanup(struct dwc3 *dwc) void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
u32 reg;
if (!dwc->ev_buf) if (!dwc->ev_buf)
return; return;
/*
* Exynos platforms may not be able to access event buffer if the
* controller failed to halt on dwc3_core_exit().
*/
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
if (!(reg & DWC3_DSTS_DEVCTRLHLT))
return;
evt = dwc->ev_buf; evt = dwc->ev_buf;

View File

@@ -522,11 +522,13 @@ static int dwc3_omap_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(dev, "failed to request IRQ #%d --> %d\n", dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret); omap->irq, ret);
goto err1; goto err2;
} }
dwc3_omap_enable_irqs(omap); dwc3_omap_enable_irqs(omap);
return 0; return 0;
err2:
of_platform_depopulate(dev);
err1: err1:
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);

View File

@@ -219,10 +219,8 @@ static int st_dwc3_probe(struct platform_device *pdev)
dwc3_data->regmap = regmap; dwc3_data->regmap = regmap;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg");
if (!res) { if (!res)
ret = -ENXIO; return -ENXIO;
goto undo_platform_dev_alloc;
}
dwc3_data->syscfg_reg_off = res->start; dwc3_data->syscfg_reg_off = res->start;
@@ -233,8 +231,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
devm_reset_control_get_exclusive(dev, "powerdown"); devm_reset_control_get_exclusive(dev, "powerdown");
if (IS_ERR(dwc3_data->rstc_pwrdn)) { if (IS_ERR(dwc3_data->rstc_pwrdn)) {
dev_err(&pdev->dev, "could not get power controller\n"); dev_err(&pdev->dev, "could not get power controller\n");
ret = PTR_ERR(dwc3_data->rstc_pwrdn); return PTR_ERR(dwc3_data->rstc_pwrdn);
goto undo_platform_dev_alloc;
} }
/* Manage PowerDown */ /* Manage PowerDown */
@@ -269,7 +266,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
if (!child_pdev) { if (!child_pdev) {
dev_err(dev, "failed to find dwc3 core device\n"); dev_err(dev, "failed to find dwc3 core device\n");
ret = -ENODEV; ret = -ENODEV;
goto err_node_put; goto depopulate;
} }
dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev); dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev);
@@ -285,6 +282,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
ret = st_dwc3_drd_init(dwc3_data); ret = st_dwc3_drd_init(dwc3_data);
if (ret) { if (ret) {
dev_err(dev, "drd initialisation failed\n"); dev_err(dev, "drd initialisation failed\n");
of_platform_depopulate(dev);
goto undo_softreset; goto undo_softreset;
} }
@@ -294,14 +292,14 @@ static int st_dwc3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dwc3_data); platform_set_drvdata(pdev, dwc3_data);
return 0; return 0;
depopulate:
of_platform_depopulate(dev);
err_node_put: err_node_put:
of_node_put(child); of_node_put(child);
undo_softreset: undo_softreset:
reset_control_assert(dwc3_data->rstc_rst); reset_control_assert(dwc3_data->rstc_rst);
undo_powerdown: undo_powerdown:
reset_control_assert(dwc3_data->rstc_pwrdn); reset_control_assert(dwc3_data->rstc_pwrdn);
undo_platform_dev_alloc:
platform_device_put(pdev);
return ret; return ret;
} }

View File

@@ -619,6 +619,8 @@ static void option_instat_callback(struct urb *urb);
/* MeiG Smart Technology products */ /* MeiG Smart Technology products */
#define MEIGSMART_VENDOR_ID 0x2dee #define MEIGSMART_VENDOR_ID 0x2dee
/* MeiG Smart SRM825L based on Qualcomm 315 */
#define MEIGSMART_PRODUCT_SRM825L 0x4d22
/* MeiG Smart SLM320 based on UNISOC UIS8910 */ /* MeiG Smart SLM320 based on UNISOC UIS8910 */
#define MEIGSMART_PRODUCT_SLM320 0x4d41 #define MEIGSMART_PRODUCT_SLM320 0x4d41
@@ -2366,6 +2368,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x30) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x60) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(usb, option_ids); MODULE_DEVICE_TABLE(usb, option_ids);

View File

@@ -27,6 +27,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/cleanup.h>
#include <asm/io.h> #include <asm/io.h>
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32

View File

@@ -613,6 +613,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
put_page(page); put_page(page);
break; break;
} }
add_size = min(em->start + em->len, page_end + 1) - cur;
free_extent_map(em); free_extent_map(em);
if (page->index == end_index) { if (page->index == end_index) {
@@ -625,7 +626,6 @@ static noinline int add_ra_bio_pages(struct inode *inode,
} }
} }
add_size = min(em->start + em->len, page_end + 1) - cur;
ret = bio_add_page(cb->orig_bio, page, add_size, offset_in_page(cur)); ret = bio_add_page(cb->orig_bio, page, add_size, offset_in_page(cur));
if (ret != add_size) { if (ret != add_size) {
unlock_extent(tree, cur, page_end, NULL); unlock_extent(tree, cur, page_end, NULL);

View File

@@ -3745,6 +3745,8 @@ static int try_flush_qgroup(struct btrfs_root *root)
return 0; return 0;
} }
btrfs_run_delayed_iputs(root->fs_info);
btrfs_wait_on_delayed_iputs(root->fs_info);
ret = btrfs_start_delalloc_snapshot(root, true); ret = btrfs_start_delalloc_snapshot(root, true);
if (ret < 0) if (ret < 0)
goto out; goto out;

View File

@@ -4184,7 +4184,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
* If we want to do a RDMA write, fill in and append * If we want to do a RDMA write, fill in and append
* smbd_buffer_descriptor_v1 to the end of read request * smbd_buffer_descriptor_v1 to the end of read request
*/ */
if (smb3_use_rdma_offload(io_parms)) { if (rdata && smb3_use_rdma_offload(io_parms)) {
struct smbd_buffer_descriptor_v1 *v1; struct smbd_buffer_descriptor_v1 *v1;
bool need_invalidate = server->dialect == SMB30_PROT_ID; bool need_invalidate = server->dialect == SMB30_PROT_ID;

View File

@@ -13,6 +13,7 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
@@ -128,6 +129,7 @@ static inline struct device_node *of_node_get(struct device_node *node)
} }
static inline void of_node_put(struct device_node *node) { } static inline void of_node_put(struct device_node *node) { }
#endif /* !CONFIG_OF_DYNAMIC */ #endif /* !CONFIG_OF_DYNAMIC */
DEFINE_FREE(device_node, struct device_node *, if (_T) of_node_put(_T))
/* Pointer for first entry in chain of all nodes. */ /* Pointer for first entry in chain of all nodes. */
extern struct device_node *of_root; extern struct device_node *of_root;
@@ -1371,10 +1373,23 @@ static inline int of_property_read_s32(const struct device_node *np,
#define for_each_child_of_node(parent, child) \ #define for_each_child_of_node(parent, child) \
for (child = of_get_next_child(parent, NULL); child != NULL; \ for (child = of_get_next_child(parent, NULL); child != NULL; \
child = of_get_next_child(parent, child)) child = of_get_next_child(parent, child))
#define for_each_child_of_node_scoped(parent, child) \
for (struct device_node *child __free(device_node) = \
of_get_next_child(parent, NULL); \
child != NULL; \
child = of_get_next_child(parent, child))
#define for_each_available_child_of_node(parent, child) \ #define for_each_available_child_of_node(parent, child) \
for (child = of_get_next_available_child(parent, NULL); child != NULL; \ for (child = of_get_next_available_child(parent, NULL); child != NULL; \
child = of_get_next_available_child(parent, child)) child = of_get_next_available_child(parent, child))
#define for_each_available_child_of_node_scoped(parent, child) \
for (struct device_node *child __free(device_node) = \
of_get_next_available_child(parent, NULL); \
child != NULL; \
child = of_get_next_available_child(parent, child))
#define for_each_of_cpu_node(cpu) \ #define for_each_of_cpu_node(cpu) \
for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \ for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
cpu = of_get_next_cpu_node(cpu)) cpu = of_get_next_cpu_node(cpu))

View File

@@ -63,7 +63,7 @@ static inline bool sk_can_busy_loop(struct sock *sk)
static inline unsigned long busy_loop_current_time(void) static inline unsigned long busy_loop_current_time(void)
{ {
#ifdef CONFIG_NET_RX_BUSY_POLL #ifdef CONFIG_NET_RX_BUSY_POLL
return (unsigned long)(local_clock() >> 10); return (unsigned long)(ktime_get_ns() >> 10);
#else #else
return 0; return 0;
#endif #endif

View File

@@ -19,7 +19,7 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt) static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
{ {
struct iphdr *iph, _iph; struct iphdr *iph, _iph;
u32 len, thoff; u32 len, thoff, skb_len;
iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb), iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
sizeof(*iph), &_iph); sizeof(*iph), &_iph);
@@ -30,15 +30,17 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
return -1; return -1;
len = iph_totlen(pkt->skb, iph); len = iph_totlen(pkt->skb, iph);
thoff = skb_network_offset(pkt->skb) + (iph->ihl * 4); thoff = iph->ihl * 4;
if (pkt->skb->len < len) skb_len = pkt->skb->len - skb_network_offset(pkt->skb);
if (skb_len < len)
return -1; return -1;
else if (len < thoff) else if (len < thoff)
return -1; return -1;
pkt->flags = NFT_PKTINFO_L4PROTO; pkt->flags = NFT_PKTINFO_L4PROTO;
pkt->tprot = iph->protocol; pkt->tprot = iph->protocol;
pkt->thoff = thoff; pkt->thoff = skb_network_offset(pkt->skb) + thoff;
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET; pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
return 0; return 0;

View File

@@ -31,8 +31,8 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
struct ipv6hdr *ip6h, _ip6h; struct ipv6hdr *ip6h, _ip6h;
unsigned int thoff = 0; unsigned int thoff = 0;
unsigned short frag_off; unsigned short frag_off;
u32 pkt_len, skb_len;
int protohdr; int protohdr;
u32 pkt_len;
ip6h = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb), ip6h = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
sizeof(*ip6h), &_ip6h); sizeof(*ip6h), &_ip6h);
@@ -43,7 +43,8 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
return -1; return -1;
pkt_len = ntohs(ip6h->payload_len); pkt_len = ntohs(ip6h->payload_len);
if (pkt_len + sizeof(*ip6h) > pkt->skb->len) skb_len = pkt->skb->len - skb_network_offset(pkt->skb);
if (pkt_len + sizeof(*ip6h) > skb_len)
return -1; return -1;
protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags); protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags);

View File

@@ -175,7 +175,7 @@ static void truncate_cleanup_folio(struct folio *folio)
if (folio_mapped(folio)) if (folio_mapped(folio))
unmap_mapping_folio(folio); unmap_mapping_folio(folio);
if (folio_has_private(folio)) if (folio_needs_release(folio))
folio_invalidate(folio, 0, folio_size(folio)); folio_invalidate(folio, 0, folio_size(folio));
/* /*
@@ -237,7 +237,7 @@ bool truncate_inode_partial_folio(struct folio *folio, loff_t start, loff_t end)
folio_zero_range(folio, offset, length); folio_zero_range(folio, offset, length);
cleancache_invalidate_page(folio->mapping, &folio->page); cleancache_invalidate_page(folio->mapping, &folio->page);
if (folio_has_private(folio)) if (folio_needs_release(folio))
folio_invalidate(folio, offset, length); folio_invalidate(folio, offset, length);
if (!folio_test_large(folio)) if (!folio_test_large(folio))
return true; return true;

View File

@@ -2404,10 +2404,16 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
/* To avoid a potential race with hci_unregister_dev. */ /* To avoid a potential race with hci_unregister_dev. */
hci_dev_hold(hdev); hci_dev_hold(hdev);
if (action == PM_SUSPEND_PREPARE) switch (action) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
ret = hci_suspend_dev(hdev); ret = hci_suspend_dev(hdev);
else if (action == PM_POST_SUSPEND) break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
ret = hci_resume_dev(hdev); ret = hci_resume_dev(hdev);
break;
}
if (ret) if (ret)
bt_dev_err(hdev, "Suspend notifier action (%lu) failed: %d", bt_dev_err(hdev, "Suspend notifier action (%lu) failed: %d",

View File

@@ -215,7 +215,7 @@ static ssize_t speed_show(struct device *dev,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
if (netif_running(netdev) && netif_device_present(netdev)) { if (netif_running(netdev)) {
struct ethtool_link_ksettings cmd; struct ethtool_link_ksettings cmd;
if (!__ethtool_get_link_ksettings(netdev, &cmd)) if (!__ethtool_get_link_ksettings(netdev, &cmd))

View File

@@ -447,6 +447,9 @@ int __ethtool_get_link_ksettings(struct net_device *dev,
if (!dev->ethtool_ops->get_link_ksettings) if (!dev->ethtool_ops->get_link_ksettings)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!netif_device_present(dev))
return -ENODEV;
memset(link_ksettings, 0, sizeof(*link_ksettings)); memset(link_ksettings, 0, sizeof(*link_ksettings));
return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings); return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings);
} }

View File

@@ -59,16 +59,6 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_
return 0; return 0;
} }
int mptcp_pm_remove_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list)
{
pr_debug("msk=%p, rm_list_nr=%d", msk, rm_list->nr);
spin_lock_bh(&msk->pm.lock);
mptcp_pm_nl_rm_subflow_received(msk, rm_list);
spin_unlock_bh(&msk->pm.lock);
return 0;
}
/* path manager event handlers */ /* path manager event handlers */
void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side) void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side)
@@ -235,7 +225,9 @@ void mptcp_pm_add_addr_received(const struct sock *ssk,
} else { } else {
__MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP); __MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP);
} }
} else if (!READ_ONCE(pm->accept_addr)) { /* id0 should not have a different address */
} else if ((addr->id == 0 && !mptcp_pm_nl_is_init_remote_addr(msk, addr)) ||
(addr->id > 0 && !READ_ONCE(pm->accept_addr))) {
mptcp_pm_announce_addr(msk, addr, true); mptcp_pm_announce_addr(msk, addr, true);
mptcp_pm_add_addr_send_ack(msk); mptcp_pm_add_addr_send_ack(msk);
} else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) { } else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
@@ -413,7 +405,23 @@ out_unlock:
int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
{ {
return mptcp_pm_nl_get_local_id(msk, skc); struct mptcp_addr_info skc_local;
struct mptcp_addr_info msk_local;
if (WARN_ON_ONCE(!msk))
return -1;
/* The 0 ID mapping is defined by the first subflow, copied into the msk
* addr
*/
mptcp_local_address((struct sock_common *)msk, &msk_local);
mptcp_local_address((struct sock_common *)skc, &skc_local);
if (mptcp_addresses_equal(&msk_local, &skc_local, false))
return 0;
if (mptcp_pm_is_userspace(msk))
return mptcp_userspace_pm_get_local_id(msk, &skc_local);
return mptcp_pm_nl_get_local_id(msk, &skc_local);
} }
bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc) bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc)

View File

@@ -134,12 +134,15 @@ static bool lookup_subflow_by_daddr(const struct list_head *list,
{ {
struct mptcp_subflow_context *subflow; struct mptcp_subflow_context *subflow;
struct mptcp_addr_info cur; struct mptcp_addr_info cur;
struct sock_common *skc;
list_for_each_entry(subflow, list, node) { list_for_each_entry(subflow, list, node) {
skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow); struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
remote_address(skc, &cur); if (!((1 << inet_sk_state_load(ssk)) &
(TCPF_ESTABLISHED | TCPF_SYN_SENT | TCPF_SYN_RECV)))
continue;
remote_address((struct sock_common *)ssk, &cur);
if (mptcp_addresses_equal(&cur, daddr, daddr->port)) if (mptcp_addresses_equal(&cur, daddr, daddr->port))
return true; return true;
} }
@@ -736,6 +739,15 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
} }
} }
bool mptcp_pm_nl_is_init_remote_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *remote)
{
struct mptcp_addr_info mpc_remote;
remote_address((struct sock_common *)msk, &mpc_remote);
return mptcp_addresses_equal(&mpc_remote, remote, remote->port);
}
void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk) void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
{ {
struct mptcp_subflow_context *subflow; struct mptcp_subflow_context *subflow;
@@ -747,9 +759,12 @@ void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
!mptcp_pm_should_rm_signal(msk)) !mptcp_pm_should_rm_signal(msk))
return; return;
subflow = list_first_entry_or_null(&msk->conn_list, typeof(*subflow), node); mptcp_for_each_subflow(msk, subflow) {
if (subflow) if (__mptcp_subflow_active(subflow)) {
mptcp_pm_send_ack(msk, subflow, false, false); mptcp_pm_send_ack(msk, subflow, false, false);
break;
}
}
} }
int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk, int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
@@ -819,6 +834,8 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
int how = RCV_SHUTDOWN | SEND_SHUTDOWN; int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
u8 id = subflow_get_local_id(subflow); u8 id = subflow_get_local_id(subflow);
if (inet_sk_state_load(ssk) == TCP_CLOSE)
continue;
if (rm_type == MPTCP_MIB_RMADDR && remote_id != rm_id) if (rm_type == MPTCP_MIB_RMADDR && remote_id != rm_id)
continue; continue;
if (rm_type == MPTCP_MIB_RMSUBFLOW && !mptcp_local_id_match(msk, id, rm_id)) if (rm_type == MPTCP_MIB_RMSUBFLOW && !mptcp_local_id_match(msk, id, rm_id))
@@ -838,10 +855,10 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
if (rm_type == MPTCP_MIB_RMSUBFLOW) if (rm_type == MPTCP_MIB_RMSUBFLOW)
__MPTCP_INC_STATS(sock_net(sk), rm_type); __MPTCP_INC_STATS(sock_net(sk), rm_type);
} }
if (rm_type == MPTCP_MIB_RMSUBFLOW)
__set_bit(rm_id ? rm_id : msk->mpc_endpoint_id, msk->pm.id_avail_bitmap); if (rm_type == MPTCP_MIB_RMADDR)
else if (rm_type == MPTCP_MIB_RMADDR)
__MPTCP_INC_STATS(sock_net(sk), rm_type); __MPTCP_INC_STATS(sock_net(sk), rm_type);
if (!removed) if (!removed)
continue; continue;
@@ -853,10 +870,8 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
/* Note: if the subflow has been closed before, this /* Note: if the subflow has been closed before, this
* add_addr_accepted counter will not be decremented. * add_addr_accepted counter will not be decremented.
*/ */
msk->pm.add_addr_accepted--; if (--msk->pm.add_addr_accepted < mptcp_pm_get_add_addr_accept_max(msk))
WRITE_ONCE(msk->pm.accept_addr, true); WRITE_ONCE(msk->pm.accept_addr, true);
} else if (rm_type == MPTCP_MIB_RMSUBFLOW) {
msk->pm.local_addr_used--;
} }
} }
} }
@@ -866,8 +881,8 @@ static void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk)
mptcp_pm_nl_rm_addr_or_subflow(msk, &msk->pm.rm_list_rx, MPTCP_MIB_RMADDR); mptcp_pm_nl_rm_addr_or_subflow(msk, &msk->pm.rm_list_rx, MPTCP_MIB_RMADDR);
} }
void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, static void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk,
const struct mptcp_rm_list *rm_list) const struct mptcp_rm_list *rm_list)
{ {
mptcp_pm_nl_rm_addr_or_subflow(msk, rm_list, MPTCP_MIB_RMSUBFLOW); mptcp_pm_nl_rm_addr_or_subflow(msk, rm_list, MPTCP_MIB_RMSUBFLOW);
} }
@@ -1074,33 +1089,17 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
return 0; return 0;
} }
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc)
{ {
struct mptcp_pm_addr_entry *entry; struct mptcp_pm_addr_entry *entry;
struct mptcp_addr_info skc_local;
struct mptcp_addr_info msk_local;
struct pm_nl_pernet *pernet; struct pm_nl_pernet *pernet;
int ret = -1; int ret = -1;
if (WARN_ON_ONCE(!msk))
return -1;
/* The 0 ID mapping is defined by the first subflow, copied into the msk
* addr
*/
mptcp_local_address((struct sock_common *)msk, &msk_local);
mptcp_local_address((struct sock_common *)skc, &skc_local);
if (mptcp_addresses_equal(&msk_local, &skc_local, false))
return 0;
if (mptcp_pm_is_userspace(msk))
return mptcp_userspace_pm_get_local_id(msk, &skc_local);
pernet = pm_nl_get_pernet_from_msk(msk); pernet = pm_nl_get_pernet_from_msk(msk);
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
if (mptcp_addresses_equal(&entry->addr, &skc_local, entry->addr.port)) { if (mptcp_addresses_equal(&entry->addr, skc, entry->addr.port)) {
ret = entry->addr.id; ret = entry->addr.id;
break; break;
} }
@@ -1114,7 +1113,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
if (!entry) if (!entry)
return -ENOMEM; return -ENOMEM;
entry->addr = skc_local; entry->addr = *skc;
entry->addr.id = 0; entry->addr.id = 0;
entry->addr.port = 0; entry->addr.port = 0;
entry->ifindex = 0; entry->ifindex = 0;
@@ -1328,20 +1327,27 @@ static struct pm_nl_pernet *genl_info_pm_nl(struct genl_info *info)
return pm_nl_get_pernet(genl_info_net(info)); return pm_nl_get_pernet(genl_info_net(info));
} }
static int mptcp_nl_add_subflow_or_signal_addr(struct net *net) static int mptcp_nl_add_subflow_or_signal_addr(struct net *net,
struct mptcp_addr_info *addr)
{ {
struct mptcp_sock *msk; struct mptcp_sock *msk;
long s_slot = 0, s_num = 0; long s_slot = 0, s_num = 0;
while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
struct sock *sk = (struct sock *)msk; struct sock *sk = (struct sock *)msk;
struct mptcp_addr_info mpc_addr;
if (!READ_ONCE(msk->fully_established) || if (!READ_ONCE(msk->fully_established) ||
mptcp_pm_is_userspace(msk)) mptcp_pm_is_userspace(msk))
goto next; goto next;
/* if the endp linked to the init sf is re-added with a != ID */
mptcp_local_address((struct sock_common *)msk, &mpc_addr);
lock_sock(sk); lock_sock(sk);
spin_lock_bh(&msk->pm.lock); spin_lock_bh(&msk->pm.lock);
if (mptcp_addresses_equal(addr, &mpc_addr, addr->port))
msk->mpc_endpoint_id = addr->id;
mptcp_pm_create_subflow_or_signal_addr(msk); mptcp_pm_create_subflow_or_signal_addr(msk);
spin_unlock_bh(&msk->pm.lock); spin_unlock_bh(&msk->pm.lock);
release_sock(sk); release_sock(sk);
@@ -1414,7 +1420,7 @@ static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info)
goto out_free; goto out_free;
} }
mptcp_nl_add_subflow_or_signal_addr(sock_net(skb->sk)); mptcp_nl_add_subflow_or_signal_addr(sock_net(skb->sk), &entry->addr);
return 0; return 0;
out_free: out_free:
@@ -1488,6 +1494,14 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
return ret; return ret;
} }
static void __mark_subflow_endp_available(struct mptcp_sock *msk, u8 id)
{
/* If it was marked as used, and not ID 0, decrement local_addr_used */
if (!__test_and_set_bit(id ? : msk->mpc_endpoint_id, msk->pm.id_avail_bitmap) &&
id && !WARN_ON_ONCE(msk->pm.local_addr_used == 0))
msk->pm.local_addr_used--;
}
static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
const struct mptcp_pm_addr_entry *entry) const struct mptcp_pm_addr_entry *entry)
{ {
@@ -1518,15 +1532,19 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
!(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT));
if (remove_subflow) { if (remove_subflow) {
mptcp_pm_remove_subflow(msk, &list);
} else if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
/* If the subflow has been used, but now closed */
spin_lock_bh(&msk->pm.lock); spin_lock_bh(&msk->pm.lock);
if (!__test_and_set_bit(entry->addr.id, msk->pm.id_avail_bitmap)) mptcp_pm_nl_rm_subflow_received(msk, &list);
msk->pm.local_addr_used--;
spin_unlock_bh(&msk->pm.lock); spin_unlock_bh(&msk->pm.lock);
} }
if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
spin_lock_bh(&msk->pm.lock);
__mark_subflow_endp_available(msk, list.ids[0]);
spin_unlock_bh(&msk->pm.lock);
}
if (msk->mpc_endpoint_id == entry->addr.id)
msk->mpc_endpoint_id = 0;
release_sock(sk); release_sock(sk);
next: next:
@@ -1561,6 +1579,7 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,
spin_lock_bh(&msk->pm.lock); spin_lock_bh(&msk->pm.lock);
mptcp_pm_remove_addr(msk, &list); mptcp_pm_remove_addr(msk, &list);
mptcp_pm_nl_rm_subflow_received(msk, &list); mptcp_pm_nl_rm_subflow_received(msk, &list);
__mark_subflow_endp_available(msk, 0);
spin_unlock_bh(&msk->pm.lock); spin_unlock_bh(&msk->pm.lock);
release_sock(sk); release_sock(sk);
@@ -1664,18 +1683,14 @@ void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
alist.ids[alist.nr++] = entry->addr.id; alist.ids[alist.nr++] = entry->addr.id;
} }
spin_lock_bh(&msk->pm.lock);
if (alist.nr) { if (alist.nr) {
spin_lock_bh(&msk->pm.lock);
msk->pm.add_addr_signaled -= alist.nr; msk->pm.add_addr_signaled -= alist.nr;
mptcp_pm_remove_addr(msk, &alist); mptcp_pm_remove_addr(msk, &alist);
spin_unlock_bh(&msk->pm.lock);
} }
if (slist.nr) if (slist.nr)
mptcp_pm_remove_subflow(msk, &slist); mptcp_pm_nl_rm_subflow_received(msk, &slist);
/* Reset counters: maybe some subflows have been removed before */ /* Reset counters: maybe some subflows have been removed before */
spin_lock_bh(&msk->pm.lock);
bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
msk->pm.local_addr_used = 0; msk->pm.local_addr_used = 0;
spin_unlock_bh(&msk->pm.lock); spin_unlock_bh(&msk->pm.lock);
@@ -1957,6 +1972,7 @@ static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk,
spin_lock_bh(&msk->pm.lock); spin_lock_bh(&msk->pm.lock);
mptcp_pm_nl_rm_subflow_received(msk, &list); mptcp_pm_nl_rm_subflow_received(msk, &list);
__mark_subflow_endp_available(msk, list.ids[0]);
mptcp_pm_create_subflow_or_signal_addr(msk); mptcp_pm_create_subflow_or_signal_addr(msk);
spin_unlock_bh(&msk->pm.lock); spin_unlock_bh(&msk->pm.lock);
} }

View File

@@ -2309,7 +2309,7 @@ static struct sock *mptcp_subflow_get_retrans(struct mptcp_sock *msk)
continue; continue;
} }
if (subflow->backup) { if (subflow->backup || subflow->request_bkup) {
if (!backup) if (!backup)
backup = ssk; backup = ssk;
continue; continue;
@@ -2528,8 +2528,11 @@ static void __mptcp_close_subflow(struct sock *sk)
mptcp_for_each_subflow_safe(msk, subflow, tmp) { mptcp_for_each_subflow_safe(msk, subflow, tmp) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow); struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
int ssk_state = inet_sk_state_load(ssk);
if (inet_sk_state_load(ssk) != TCP_CLOSE) if (ssk_state != TCP_CLOSE &&
(ssk_state != TCP_CLOSE_WAIT ||
inet_sk_state_load(sk) != TCP_ESTABLISHED))
continue; continue;
/* 'subflow_data_ready' will re-sched once rx queue is empty */ /* 'subflow_data_ready' will re-sched once rx queue is empty */

View File

@@ -802,6 +802,8 @@ void mptcp_pm_add_addr_received(const struct sock *ssk,
void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr); const struct mptcp_addr_info *addr);
void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk); void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk);
bool mptcp_pm_nl_is_init_remote_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *remote);
void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk); void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk);
void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
const struct mptcp_rm_list *rm_list); const struct mptcp_rm_list *rm_list);
@@ -834,7 +836,6 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr, const struct mptcp_addr_info *addr,
bool echo); bool echo);
int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list); int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
int mptcp_pm_remove_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list); void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list);
void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk, void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
struct list_head *rm_list); struct list_head *rm_list);
@@ -912,6 +913,7 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb,
bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
struct mptcp_rm_list *rm_list); struct mptcp_rm_list *rm_list);
int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc); bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc);
bool mptcp_pm_nl_is_backup(struct mptcp_sock *msk, struct mptcp_addr_info *skc); bool mptcp_pm_nl_is_backup(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
@@ -928,9 +930,6 @@ static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflo
void __init mptcp_pm_nl_init(void); void __init mptcp_pm_nl_init(void);
void mptcp_pm_nl_work(struct mptcp_sock *msk); void mptcp_pm_nl_work(struct mptcp_sock *msk);
void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk,
const struct mptcp_rm_list *rm_list);
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
unsigned int mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock *msk); unsigned int mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock *msk);
unsigned int mptcp_pm_get_add_addr_accept_max(const struct mptcp_sock *msk); unsigned int mptcp_pm_get_add_addr_accept_max(const struct mptcp_sock *msk);
unsigned int mptcp_pm_get_subflows_max(const struct mptcp_sock *msk); unsigned int mptcp_pm_get_subflows_max(const struct mptcp_sock *msk);

View File

@@ -1137,12 +1137,16 @@ out:
/* sched mptcp worker to remove the subflow if no more data is pending */ /* sched mptcp worker to remove the subflow if no more data is pending */
static void subflow_sched_work_if_closed(struct mptcp_sock *msk, struct sock *ssk) static void subflow_sched_work_if_closed(struct mptcp_sock *msk, struct sock *ssk)
{ {
if (likely(ssk->sk_state != TCP_CLOSE)) struct sock *sk = (struct sock *)msk;
if (likely(ssk->sk_state != TCP_CLOSE &&
(ssk->sk_state != TCP_CLOSE_WAIT ||
inet_sk_state_load(sk) != TCP_ESTABLISHED)))
return; return;
if (skb_queue_empty(&ssk->sk_receive_queue) && if (skb_queue_empty(&ssk->sk_receive_queue) &&
!test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags)) !test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
mptcp_schedule_work((struct sock *)msk); mptcp_schedule_work(sk);
} }
static bool subflow_can_fallback(struct mptcp_subflow_context *subflow) static bool subflow_can_fallback(struct mptcp_subflow_context *subflow)

View File

@@ -2261,12 +2261,6 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
} }
} }
/* Update socket peer label if first association. */
if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
/* Set temp so that it won't be added into hashtable */ /* Set temp so that it won't be added into hashtable */
new_asoc->temp = 1; new_asoc->temp = 1;
@@ -2275,6 +2269,22 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
*/ */
action = sctp_tietags_compare(new_asoc, asoc); action = sctp_tietags_compare(new_asoc, asoc);
/* In cases C and E the association doesn't enter the ESTABLISHED
* state, so there is no need to call security_sctp_assoc_request().
*/
switch (action) {
case 'A': /* Association restart. */
case 'B': /* Collision case B. */
case 'D': /* Collision case D. */
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_association *)asoc,
chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
break;
}
switch (action) { switch (action) {
case 'A': /* Association restart. */ case 'A': /* Association restart. */
retval = sctp_sf_do_dupcook_a(net, ep, asoc, chunk, commands, retval = sctp_sf_do_dupcook_a(net, ep, asoc, chunk, commands,

View File

@@ -81,14 +81,14 @@ static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
*(buf + 1) = strlen(TEST_U32_NAME) + 1; *(buf + 1) = strlen(TEST_U32_NAME) + 1;
strcpy(buf + 3, TEST_U32_NAME); strcpy(buf + 3, TEST_U32_NAME);
*(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32; *(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32;
*((u32 *)(buf + 3 + strlen(TEST_U32_NAME) + 2)) = TEST_U32_DATA; *((__le32 *)(buf + 3 + strlen(TEST_U32_NAME) + 2)) = cpu_to_le32(TEST_U32_DATA);
buf = e->start + TEST_NAMED_U64_BUF_OFFSET; buf = e->start + TEST_NAMED_U64_BUF_OFFSET;
*buf = AA_NAME; *buf = AA_NAME;
*(buf + 1) = strlen(TEST_U64_NAME) + 1; *(buf + 1) = strlen(TEST_U64_NAME) + 1;
strcpy(buf + 3, TEST_U64_NAME); strcpy(buf + 3, TEST_U64_NAME);
*(buf + 3 + strlen(TEST_U64_NAME) + 1) = AA_U64; *(buf + 3 + strlen(TEST_U64_NAME) + 1) = AA_U64;
*((u64 *)(buf + 3 + strlen(TEST_U64_NAME) + 2)) = TEST_U64_DATA; *((__le64 *)(buf + 3 + strlen(TEST_U64_NAME) + 2)) = cpu_to_le64(TEST_U64_DATA);
buf = e->start + TEST_NAMED_BLOB_BUF_OFFSET; buf = e->start + TEST_NAMED_BLOB_BUF_OFFSET;
*buf = AA_NAME; *buf = AA_NAME;
@@ -104,7 +104,7 @@ static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
*(buf + 1) = strlen(TEST_ARRAY_NAME) + 1; *(buf + 1) = strlen(TEST_ARRAY_NAME) + 1;
strcpy(buf + 3, TEST_ARRAY_NAME); strcpy(buf + 3, TEST_ARRAY_NAME);
*(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY; *(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY;
*((u16 *)(buf + 3 + strlen(TEST_ARRAY_NAME) + 2)) = TEST_ARRAY_SIZE; *((__le16 *)(buf + 3 + strlen(TEST_ARRAY_NAME) + 2)) = cpu_to_le16(TEST_ARRAY_SIZE);
return e; return e;
} }

View File

@@ -144,6 +144,8 @@ static const struct platform_device_id board_ids[] = {
}, },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, board_ids);
static struct platform_driver acp_asoc_audio = { static struct platform_driver acp_asoc_audio = {
.driver = { .driver = {
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,

View File

@@ -363,6 +363,7 @@ static int acp_power_on(struct snd_sof_dev *sdev)
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int base = desc->pgfsm_base; unsigned int base = desc->pgfsm_base;
unsigned int val; unsigned int val;
unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask;
int ret; int ret;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET); val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET);
@@ -370,9 +371,23 @@ static int acp_power_on(struct snd_sof_dev *sdev)
if (val == ACP_POWERED_ON) if (val == ACP_POWERED_ON)
return 0; return 0;
if (val & ACP_PGFSM_STATUS_MASK) switch (desc->rev) {
case 3:
case 5:
acp_pgfsm_status_mask = ACP3X_PGFSM_STATUS_MASK;
acp_pgfsm_cntl_mask = ACP3X_PGFSM_CNTL_POWER_ON_MASK;
break;
case 6:
acp_pgfsm_status_mask = ACP6X_PGFSM_STATUS_MASK;
acp_pgfsm_cntl_mask = ACP6X_PGFSM_CNTL_POWER_ON_MASK;
break;
default:
return -EINVAL;
}
if (val & acp_pgfsm_status_mask)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET, snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET,
ACP_PGFSM_CNTL_POWER_ON_MASK); acp_pgfsm_cntl_mask);
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val, ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val,
!val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);

View File

@@ -22,8 +22,11 @@
#define ACP_REG_POLL_TIMEOUT_US 2000 #define ACP_REG_POLL_TIMEOUT_US 2000
#define ACP_DMA_COMPLETE_TIMEOUT_US 5000 #define ACP_DMA_COMPLETE_TIMEOUT_US 5000
#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 #define ACP3X_PGFSM_CNTL_POWER_ON_MASK 0x01
#define ACP_PGFSM_STATUS_MASK 0x03 #define ACP3X_PGFSM_STATUS_MASK 0x03
#define ACP6X_PGFSM_CNTL_POWER_ON_MASK 0x07
#define ACP6X_PGFSM_STATUS_MASK 0x0F
#define ACP_POWERED_ON 0x00 #define ACP_POWERED_ON 0x00
#define ACP_ASSERT_RESET 0x01 #define ACP_ASSERT_RESET 0x01
#define ACP_RELEASE_RESET 0x00 #define ACP_RELEASE_RESET 0x00

View File

@@ -278,6 +278,10 @@ bridge()
cleanup() cleanup()
{ {
pre_cleanup pre_cleanup
ip link set $h2 down
ip link set $h1 down
vrf_cleanup vrf_cleanup
} }

View File

@@ -233,6 +233,9 @@ cleanup()
{ {
pre_cleanup pre_cleanup
ip link set dev $swp2 down
ip link set dev $swp1 down
h2_destroy h2_destroy
h1_destroy h1_destroy