diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 59549a3b7aae..f51895fb5d48 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -347,6 +347,7 @@ CONFIG_SERIAL_MSM=y CONFIG_QCOM_EUD=y CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE=y CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT=y +CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP=y CONFIG_POWER_RESET_QCOM_REBOOT_REASON=y CONFIG_POWER_RESET_MSM=y CONFIG_QCOM_MINIDUMP=y diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 5b6543836b50..99593aaebacd 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -207,6 +207,25 @@ void qcom_scm_set_download_mode(enum qcom_download_mode mode, } EXPORT_SYMBOL(qcom_scm_set_download_mode); +int qcom_scm_get_download_mode(unsigned int *mode, phys_addr_t tcsr_boot_misc) +{ + int ret = -EINVAL; + struct device *dev = __scm ? __scm->dev : NULL; + + if (tcsr_boot_misc || (__scm && __scm->dload_mode_addr)) { + ret = qcom_scm_io_readl(tcsr_boot_misc ? : __scm->dload_mode_addr, mode); + } else { + dev_err(dev, + "No available mechanism for getting download mode\n"); + } + + if (ret) + dev_err(dev, "failed to get download mode: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_get_download_mode); + int qcom_scm_config_cpu_errata(void) { return __qcom_scm_config_cpu_errata(__scm->dev); diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index e31aaffb9f1a..cb2bc2af14df 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -601,8 +602,6 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev, if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base)) return -ENOENT; - trace_adreno_drawctxt_switch(rb, drawctxt); - /* Get a refcount to the new instance */ if (drawctxt) { if (!_kgsl_context_get(&drawctxt->base)) @@ -616,7 +615,7 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev, ret = adreno_iommu_set_pt_ctx(rb, new_pt, drawctxt); if (ret) - return ret; + goto err; if (rb->drawctxt_active) { /* Wait for the timestamp to expire */ @@ -626,7 +625,12 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev, kgsl_context_put(&rb->drawctxt_active->base); } } + trace_adreno_drawctxt_switch(rb, drawctxt); rb->drawctxt_active = drawctxt; return 0; +err: + if (drawctxt) + kgsl_context_put(&drawctxt->base); + return ret; } diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index be88bafb12da..1ab5d6acea4a 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -353,63 +353,6 @@ static unsigned int __add_curr_ctxt_cmds(struct adreno_ringbuffer *rb, return cmds - cmds_orig; } -/** - * _set_ctxt_gpu() - Add commands to set the current context in memstore - * @rb: The ringbuffer in which commands to set memstore are added - * @drawctxt: The context whose id is being set in memstore - */ -static int _set_ctxt_gpu(struct adreno_ringbuffer *rb, - struct adreno_context *drawctxt) -{ - unsigned int link[15], *cmds; - int result; - - cmds = &link[0]; - cmds += __add_curr_ctxt_cmds(rb, cmds, drawctxt); - result = adreno_ringbuffer_issue_internal_cmds(rb, 0, link, - (unsigned int)(cmds - link)); - return result; -} - -/** - * _set_pagetable_gpu() - Use GPU to switch the pagetable - * @rb: The rb in which commands to switch pagetable are to be - * submitted - * @new_pt: The pagetable to switch to - */ -static int _set_pagetable_gpu(struct adreno_ringbuffer *rb, - struct kgsl_pagetable *new_pt) -{ - struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); - unsigned int *link = NULL, count; - int result; - - link = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (link == NULL) - return -ENOMEM; - - /* If we are in a fault the MMU will be reset soon */ - if (test_bit(ADRENO_DEVICE_FAULT, &adreno_dev->priv)) { - kfree(link); - return 0; - } - - count = adreno_iommu_set_pt_generate_cmds(rb, link, new_pt); - - WARN(count > (PAGE_SIZE / sizeof(unsigned int)), - "Temp command buffer overflow\n"); - - /* - * This returns the per context timestamp but we need to - * use the global timestamp for iommu clock disablement - */ - result = adreno_ringbuffer_issue_internal_cmds(rb, - KGSL_CMD_FLAGS_PMODE, link, count); - - kfree(link); - return result; -} - /** * adreno_iommu_init() - Adreno iommu init * @adreno_dev: Adreno device @@ -443,7 +386,6 @@ void adreno_iommu_init(struct adreno_device *adreno_dev) /** * adreno_iommu_set_pt_ctx() - Change the pagetable of the current RB - * @device: Pointer to device to which the rb belongs * @rb: The RB pointer on which pagetable is to be changed * @new_pt: The new pt the device will change to * @drawctxt: The context whose pagetable the ringbuffer is switching to, @@ -458,21 +400,34 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pagetable *cur_pt = device->mmu.defaultpagetable; + unsigned int *cmds = NULL, count = 0; int result = 0; + cmds = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (cmds == NULL) + return -ENOMEM; + /* Switch the page table if a MMU is attached */ if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_NONE) { if (rb->drawctxt_active) cur_pt = rb->drawctxt_active->base.proc_priv->pagetable; - /* Pagetable switch */ + /* Add commands for pagetable switch */ if (new_pt != cur_pt) - result = _set_pagetable_gpu(rb, new_pt); + count += adreno_iommu_set_pt_generate_cmds(rb, cmds, new_pt); - if (result) - return result; } - /* Context switch */ - return _set_ctxt_gpu(rb, drawctxt); + /* Add commands to set the current context in memstore */ + count += __add_curr_ctxt_cmds(rb, cmds + count, drawctxt); + + WARN(count > (PAGE_SIZE / sizeof(unsigned int)), + "Temp command buffer overflow\n"); + + result = adreno_ringbuffer_issue_internal_cmds(rb, KGSL_CMD_FLAGS_PMODE, + cmds, count); + + kfree(cmds); + return result; + } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bbe4e6d1ba4b..eeb4e2af29ff 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2334,6 +2334,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s); +/* + * QPS615 PCIe-PCI bridge devices cause AER timeout errors on the upstream + * PCIe root port when L0s is enabled in CPE platform with SDX65. + * Disable L0s for both QPS615 and SDX65 when QPS615 switch is + * present. + */ +static void quirk_disable_aspm_qps615_l0s(struct pci_dev *dev) +{ + struct pci_dev *p; + + pci_disable_link_state(dev, PCIE_LINK_STATE_L0S); + p = pci_get_device(PCI_VENDOR_ID_QCOM, 0x0308, NULL); + pci_disable_link_state(p, PCIE_LINK_STATE_L0S); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TOSHIBA, 0x0623, quirk_disable_aspm_qps615_l0s); + static void quirk_disable_aspm_l0s_l1(struct pci_dev *dev) { pci_info(dev, "Disabling ASPM L0s/L1\n"); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 83e6cc9dbd0d..5955c9307e9e 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -132,6 +132,16 @@ config POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT Say Y here to enable "download mode" by default. +config POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP + bool "MSM download mode as nodump" + depends on POWER_RESET_QCOM_DOWNLOAD_MODE + help + Support MSM boards to be able to set nodump as download mode, + when unexpected warm-restart is called, so that device will + not go into ramdump path. + + Say N if not sure. + config POWER_RESET_QCOM_PON tristate "Qualcomm power-on driver" depends on ARCH_QCOM diff --git a/drivers/power/reset/qcom-dload-mode.c b/drivers/power/reset/qcom-dload-mode.c index ec181d36f373..5298b80921c9 100644 --- a/drivers/power/reset/qcom-dload-mode.c +++ b/drivers/power/reset/qcom-dload-mode.c @@ -203,6 +203,11 @@ static ssize_t dload_mode_show(struct kobject *kobj, case QCOM_DOWNLOAD_BOTHDUMP: mode = "both"; break; +#ifdef CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP + case QCOM_DOWNLOAD_NODUMP: + mode = "nodump"; + break; +#endif default: mode = "unknown"; break; @@ -214,6 +219,17 @@ static ssize_t dload_mode_store(struct kobject *kobj, const char *buf, size_t count) { enum qcom_download_mode mode; +#ifdef CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP + int temp; + + dump_mode = qcom_scm_get_download_mode(&temp, 0) ? dump_mode : temp; + + if (dump_mode == QCOM_DOWNLOAD_NODUMP) { + pr_err("%s: Current dump mode already set: nodump\n", __func__); + pr_err("%s: Changing dump mode now is not allowed, reboot the device\n", __func__); + return -EINVAL; + } +#endif if (sysfs_streq(buf, "full")) mode = QCOM_DOWNLOAD_FULLDUMP; @@ -221,9 +237,19 @@ static ssize_t dload_mode_store(struct kobject *kobj, mode = QCOM_DOWNLOAD_MINIDUMP; else if (sysfs_streq(buf, "both")) mode = QCOM_DOWNLOAD_BOTHDUMP; +#ifdef CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP + else if (sysfs_streq(buf, "nodump")) { + mode = QCOM_DOWNLOAD_NODUMP; + qcom_scm_disable_sdi(); + } +#endif else { pr_err("Invalid dump mode request...\n"); +#ifdef CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP + pr_err("Supported dumps: 'full', 'mini', 'both' or 'nodump'\n"); +#else pr_err("Supported dumps: 'full', 'mini', or 'both'\n"); +#endif return -EINVAL; } diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index b826865862f2..a5caf62682c8 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2016-2017, Linaro Ltd * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -354,6 +355,38 @@ static void qcom_glink_channel_release(struct kref *ref) kfree(channel); } +static struct glink_channel *qcom_glink_channel_ref_get( + struct qcom_glink *glink, + bool remote_channel, int cid) +{ + struct glink_channel *channel = NULL; + unsigned long flags; + + if (!glink) + return NULL; + + spin_lock_irqsave(&glink->idr_lock, flags); + if (remote_channel) + channel = idr_find(&glink->rcids, cid); + else + channel = idr_find(&glink->lcids, cid); + + if (channel) + kref_get(&channel->refcount); + + spin_unlock_irqrestore(&glink->idr_lock, flags); + return channel; +} + +static void qcom_glink_channel_ref_put(struct glink_channel *channel) +{ + + if (!channel) + return; + + kref_put(&channel->refcount, qcom_glink_channel_release); +} + static size_t qcom_glink_rx_avail(struct qcom_glink *glink) { return glink->rx_pipe->avail(glink->rx_pipe); @@ -505,11 +538,8 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, unsigned int cid, bool granted) { struct glink_channel *channel; - unsigned long flags; - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, cid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, cid); if (!channel) { dev_err(glink->dev, "unable to find channel\n"); return; @@ -519,6 +549,7 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, atomic_inc(&channel->intent_req_acked); wake_up(&channel->intent_req_ack); CH_INFO(channel, "\n"); + qcom_glink_channel_ref_put(channel); } /** @@ -867,9 +898,7 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink, struct glink_channel *channel; unsigned long flags; - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, cid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, cid); if (!channel) { dev_err(glink->dev, "invalid channel id received\n"); return; @@ -881,6 +910,7 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink, if (!intent) { spin_unlock_irqrestore(&channel->intent_lock, flags); dev_err(glink->dev, "invalid intent id received\n"); + qcom_glink_channel_ref_put(channel); return; } @@ -892,6 +922,7 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink, kfree(intent); } spin_unlock_irqrestore(&channel->intent_lock, flags); + qcom_glink_channel_ref_put(channel); } /** @@ -914,9 +945,7 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink, unsigned long flags; int iid; - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, cid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, cid); if (!channel) { pr_err("%s channel not found for cid %d\n", __func__, cid); @@ -933,6 +962,7 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink, spin_unlock_irqrestore(&channel->intent_lock, flags); if (intent) { qcom_glink_send_intent_req_ack(glink, channel, !!intent); + qcom_glink_channel_ref_put(channel); return; } @@ -942,6 +972,7 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink, qcom_glink_advertise_intent(glink, channel, intent); qcom_glink_send_intent_req_ack(glink, channel, !!intent); + qcom_glink_channel_ref_put(channel); } static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra) @@ -976,7 +1007,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra) static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) { struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_channel *channel = NULL; struct { struct glink_msg msg; __le32 chunk_size; @@ -1004,9 +1035,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) } rcid = le16_to_cpu(hdr.msg.param1); - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, rcid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, rcid); if (!channel) { dev_dbg(glink->dev, "Data on non-existing channel\n"); @@ -1019,13 +1048,16 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) /* Might have an ongoing, fragmented, message to append */ if (!channel->buf) { intent = kzalloc(sizeof(*intent), GFP_ATOMIC); - if (!intent) + if (!intent) { + qcom_glink_channel_ref_put(channel); return -ENOMEM; + } intent->data = kmalloc(chunk_size + left_size, GFP_ATOMIC); if (!intent->data) { kfree(intent); + qcom_glink_channel_ref_put(channel); return -ENOMEM; } @@ -1092,7 +1124,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) advance_rx: qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr) + chunk_size, 8)); - + qcom_glink_channel_ref_put(channel); return ret; } @@ -1123,9 +1155,7 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink, return; } - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, cid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, cid); if (!channel) { dev_err(glink->dev, "intents for non-existing channel\n"); qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); @@ -1133,8 +1163,10 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink, } msg = kmalloc(msglen, GFP_ATOMIC); - if (!msg) + if (!msg) { + qcom_glink_channel_ref_put(channel); return; + } qcom_glink_rx_peak(glink, msg, 0, msglen); @@ -1163,15 +1195,14 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink, kfree(msg); qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); + qcom_glink_channel_ref_put(channel); } static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) { struct glink_channel *channel; - spin_lock(&glink->idr_lock); - channel = idr_find(&glink->lcids, lcid); - spin_unlock(&glink->idr_lock); + channel = qcom_glink_channel_ref_get(glink, false, lcid); if (!channel) { dev_err(glink->dev, "Invalid open ack packet\n"); return -EINVAL; @@ -1179,7 +1210,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) CH_INFO(channel, "\n"); complete_all(&channel->open_ack); - + qcom_glink_channel_ref_put(channel); return 0; } @@ -1220,12 +1251,9 @@ static int qcom_glink_handle_signals(struct qcom_glink *glink, unsigned int rcid, unsigned int signals) { struct glink_channel *channel; - unsigned long flags; u32 old; - spin_lock_irqsave(&glink->idr_lock, flags); - channel = idr_find(&glink->rcids, rcid); - spin_unlock_irqrestore(&glink->idr_lock, flags); + channel = qcom_glink_channel_ref_get(glink, true, rcid); if (!channel) { dev_err(glink->dev, "signal for non-existing channel\n"); return -EINVAL; @@ -1252,6 +1280,7 @@ static int qcom_glink_handle_signals(struct qcom_glink *glink, old, channel->rsigs); } + qcom_glink_channel_ref_put(channel); return 0; } diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 38249a1a27d0..a441763fbd29 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -92,10 +92,16 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len) size_t ehdr_size; void *data; + if (fw->size < sizeof(struct elf32_hdr)) { + dev_err(dev, "Image is too small\n"); + return ERR_PTR(-EINVAL); + } + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); - if (ehdr->e_phnum < 2 || ehdr->e_phnum > PN_XNUM) + if (ehdr->e_phnum < 2 || ehdr->e_phoff > fw->size || + (sizeof(phdrs) * ehdr->e_phnum > fw->size - ehdr->e_phoff)) return ERR_PTR(-EINVAL); if (phdrs[0].p_type == PT_LOAD) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3f55565cda18..b405b97f13d1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -100,7 +100,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) * Wait until device controller is ready. Only applies to 1.94a and * later RTL. */ - if (dwc->revision >= DWC3_REVISION_194A) { + if (dwc3_is_usb3(dwc) && dwc->revision >= DWC3_REVISION_194A) { while (--retries) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); if (reg & DWC3_DSTS_DCNRD) @@ -124,7 +124,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) * The following code is racy when called from dwc3_gadget_wakeup, * and is not needed, at least on newer versions */ - if (dwc->revision >= DWC3_REVISION_194A) + if (dwc3_is_usb3(dwc) && dwc->revision >= DWC3_REVISION_194A) return 0; /* wait for a change in DSTS */ @@ -2116,13 +2116,10 @@ static int dwc3_gadget_remote_wakeup(struct dwc3 *dwc) goto out; } - /* Recent versions do this automatically */ - if (dwc->revision < DWC3_REVISION_194A) { - /* write zeroes to Link Change Request */ - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - } + /* write zeroes to Link Change Request */ + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); spin_unlock_irqrestore(&dwc->lock, flags); enable_irq(dwc->irq); diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 50833c6e2c17..3a98b59458f1 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -732,13 +732,26 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value, static int port_notify_serial_state(struct cserial *cser) { struct f_cdev *port = cser_to_port(cser); - int status; + int status, ret; unsigned long flags; struct usb_composite_dev *cdev = port->port_usb.func.config->cdev; + struct usb_function *func = &cser->func; + struct usb_gadget *gadget; if (port->is_suspended) { + gadget = cser->func.config->cdev->gadget; port->pending_state_notify = true; pr_debug("%s: port is suspended\n", __func__); + if (usb_cser_get_remote_wakeup_capable(func, gadget)) { + if (gadget->speed >= USB_SPEED_SUPER && port->func_is_suspended) { + ret = usb_func_wakeup(func); + port->func_wakeup_pending = (ret == -EAGAIN) ? true : false; + } else { + ret = usb_gadget_wakeup(gadget); + } + } else { + pr_debug("%s remote-wakeup not capable\n", __func__); + } return 0; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index cea8cb7e0645..55a617e9b0a7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -619,6 +619,7 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci, static int xhci_enter_test_mode(struct xhci_hcd *xhci, u16 test_mode, u16 wIndex, unsigned long *flags) { + struct usb_hcd *usb3_hcd = xhci_get_usb3_hcd(xhci); int i, retval; /* Disable all Device Slots */ @@ -639,7 +640,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, xhci_dbg(xhci, "Disable all port (PP = 0)\n"); /* Power off USB3 ports*/ for (i = 0; i < xhci->usb3_rhub.num_ports; i++) - xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags); + xhci_set_port_power(xhci, usb3_hcd, i, false, flags); /* Power off USB2 ports*/ for (i = 0; i < xhci->usb2_rhub.num_ports; i++) xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags); @@ -1743,7 +1744,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) status = 1; } if (!status && !reset_change) { - xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); + xhci_dbg(xhci, "%s: stopping usb%d port polling\n", + __func__, hcd->self.busnum); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); } spin_unlock_irqrestore(&xhci->lock, flags); @@ -1775,7 +1777,8 @@ int xhci_bus_suspend(struct usb_hcd *hcd) if (bus_state->resuming_ports || /* USB2 */ bus_state->port_remote_wakeup) { /* USB3 */ spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because a port is resuming\n"); + xhci_dbg(xhci, "usb%d bus suspend to fail because a port is resuming\n", + hcd->self.busnum); return -EBUSY; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 47eca9ab277e..4383a08b396d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1086,7 +1086,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, struct usb_hcd *hcd; if (udev->speed >= USB_SPEED_SUPER) - hcd = xhci->shared_hcd; + hcd = xhci_get_usb3_hcd(xhci); else hcd = xhci->main_hcd; @@ -2494,10 +2494,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci->usb2_rhub.num_ports = USB_MAXCHILDREN; } - /* - * Note we could have all USB 3.0 ports, or all USB 2.0 ports. - * Not sure how the USB core will handle a hub with no ports... - */ + if (!xhci->usb2_rhub.num_ports) + xhci_info(xhci, "USB2 root hub has no ports\n"); + + if (!xhci->usb3_rhub.num_ports) + xhci_info(xhci, "USB3 root hub has no ports\n"); xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags); xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index d496a3b265b3..524bf63d5e9b 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -171,7 +171,7 @@ static int xhci_plat_probe(struct platform_device *pdev) struct device *sysdev, *tmpdev; struct xhci_hcd *xhci; struct resource *res; - struct usb_hcd *hcd; + struct usb_hcd *hcd, *usb3_hcd; int ret; int irq; struct xhci_plat_priv *priv = NULL; @@ -246,6 +246,8 @@ static int xhci_plat_probe(struct platform_device *pdev) xhci = hcd_to_xhci(hcd); + xhci->allow_single_roothub = 1; + /* * Not all platforms have clks so it is not an error if the * clock do not exist. @@ -291,12 +293,6 @@ static int xhci_plat_probe(struct platform_device *pdev) device_init_wakeup(hcd->self.controller, 1); xhci->main_hcd = hcd; - xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, - dev_name(&pdev->dev), hcd); - if (!xhci->shared_hcd) { - ret = -ENOMEM; - goto disable_clk; - } /* imod_interval is the interrupt moderation value in nanoseconds. */ xhci->imod_interval = 40000; @@ -321,16 +317,15 @@ static int xhci_plat_probe(struct platform_device *pdev) if (IS_ERR(hcd->usb_phy)) { ret = PTR_ERR(hcd->usb_phy); if (ret == -EPROBE_DEFER) - goto put_usb3_hcd; + goto disable_clk; hcd->usb_phy = NULL; } else { ret = usb_phy_init(hcd->usb_phy); if (ret) - goto put_usb3_hcd; + goto disable_clk; } hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); - xhci->shared_hcd->tpl_support = hcd->tpl_support; if (priv) { ret = xhci_priv_plat_setup(hcd); @@ -345,16 +340,31 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; + if (!xhci_has_one_roothub(xhci)) { + xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, + dev_name(&pdev->dev), hcd); + if (!xhci->shared_hcd) { + ret = -ENOMEM; + goto dealloc_usb2_hcd; + } - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); - if (ret) - goto dealloc_usb2_hcd; + xhci->shared_hcd->tpl_support = hcd->tpl_support; + } + + usb3_hcd = xhci_get_usb3_hcd(xhci); + if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4) + usb3_hcd->can_do_streams = 1; + + if (xhci->shared_hcd) { + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) + goto put_usb3_hcd; + } device_enable_async_suspend(&pdev->dev); if (device_may_wakeup(sysdev)) { - device_wakeup_enable(&xhci->shared_hcd->self.root_hub->dev); + if (xhci->shared_hcd) + device_wakeup_enable(&xhci->shared_hcd->self.root_hub->dev); device_wakeup_enable(&hcd->self.root_hub->dev); } @@ -364,15 +374,15 @@ static int xhci_plat_probe(struct platform_device *pdev) return 0; +put_usb3_hcd: + usb_put_hcd(xhci->shared_hcd); + dealloc_usb2_hcd: usb_remove_hcd(hcd); disable_usb_phy: usb_phy_shutdown(hcd->usb_phy); -put_usb3_hcd: - usb_put_hcd(xhci->shared_hcd); - disable_clk: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -398,12 +408,17 @@ static int xhci_plat_remove(struct platform_device *dev) pm_runtime_get_sync(&dev->dev); xhci->xhc_state |= XHCI_STATE_REMOVING; - usb_remove_hcd(shared_hcd); + if (shared_hcd) + usb_remove_hcd(shared_hcd); + usb_phy_shutdown(hcd->usb_phy); usb_remove_hcd(hcd); - xhci->shared_hcd = NULL; - usb_put_hcd(shared_hcd); + + if (shared_hcd) { + xhci->shared_hcd = NULL; + usb_put_hcd(shared_hcd); + } clk_disable_unprepare(clk); clk_disable_unprepare(reg_clk); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5a6d825d64e4..ded09937f0f6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1808,7 +1808,8 @@ cleanup: * bits are still set. When an event occurs, switch over to * polling to avoid losing status changes. */ - xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + xhci_dbg(xhci, "%s: starting usb%d port polling.\n", + __func__, hcd->self.busnum); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); spin_unlock(&xhci->lock); /* Pass this up to the core */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 89424697f743..5bb772bd9d87 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -520,6 +520,10 @@ static void compliance_mode_recovery(struct timer_list *t) xhci = from_timer(xhci, t, comp_mode_recovery_timer); rhub = &xhci->usb3_rhub; + hcd = rhub->hcd; + + if (!hcd) + return; for (i = 0; i < rhub->num_ports; i++) { temp = readl(rhub->ports[i]->addr); @@ -533,7 +537,6 @@ static void compliance_mode_recovery(struct timer_list *t) i + 1); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Attempting compliance mode recovery"); - hcd = xhci->shared_hcd; if (hcd->state == HC_STATE_SUSPENDED) usb_hcd_resume_root_hub(hcd); @@ -646,14 +649,11 @@ static int xhci_run_finished(struct xhci_hcd *xhci) xhci_halt(xhci); return -ENODEV; } - xhci->shared_hcd->state = HC_STATE_RUNNING; xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Finished xhci_run for USB3 roothub"); return 0; } @@ -727,14 +727,19 @@ int xhci_run(struct usb_hcd *hcd) if (ret) xhci_free_command(xhci, command); } - set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags); xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Finished xhci_run for USB2 roothub"); + "Finished %s for main hcd", __func__); xhci_dbc_init(xhci); xhci_debugfs_init(xhci); + if (xhci_has_one_roothub(xhci)) + return xhci_run_finished(xhci); + + /* Defer primary roothub registration if we have 2 root hubs only */ + set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags); + return 0; } EXPORT_SYMBOL_GPL(xhci_run); @@ -1027,7 +1032,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) return 0; if (hcd->state != HC_STATE_SUSPENDED || - xhci->shared_hcd->state != HC_STATE_SUSPENDED) + (xhci->shared_hcd && + xhci->shared_hcd->state != HC_STATE_SUSPENDED)) return -EINVAL; if (!HCD_HW_ACCESSIBLE(hcd)) @@ -1040,18 +1046,22 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) xhci_dbc_suspend(xhci); /* Don't poll the roothubs on bus suspend. */ - xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); + xhci_dbg(xhci, "%s: stopping usb%d port polling.\n", + __func__, hcd->self.busnum); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); - clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); - del_timer_sync(&xhci->shared_hcd->rh_timer); + if (xhci->shared_hcd) { + clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + del_timer_sync(&xhci->shared_hcd->rh_timer); + } if (xhci->quirks & XHCI_SUSPEND_DELAY) usleep_range(1000, 1500); spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + if (xhci->shared_hcd) + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); /* step 1: stop endpoint */ /* skipped assuming that port suspend has done */ @@ -1070,7 +1080,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) * served. */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + if (xhci->shared_hcd) + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); xhci_hc_died(xhci); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; @@ -1157,7 +1168,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) msleep(100); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + if (xhci->shared_hcd) + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); spin_lock_irq(&xhci->lock); @@ -1218,7 +1230,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); - usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); + if (xhci->shared_hcd) + usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); @@ -1258,12 +1271,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); - if (!retval) { + if (!retval && secondary_hcd) { xhci_dbg(xhci, "Start the secondary HCD\n"); retval = xhci_run(secondary_hcd); } hcd->state = HC_STATE_SUSPENDED; - xhci->shared_hcd->state = HC_STATE_SUSPENDED; + if (xhci->shared_hcd) + xhci->shared_hcd->state = HC_STATE_SUSPENDED; goto done; } @@ -1301,7 +1315,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) } if (pending_portevent) { - usb_hcd_resume_root_hub(xhci->shared_hcd); + if (xhci->shared_hcd) + usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(hcd); } } @@ -1318,9 +1333,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller)); /* Re-enable port polling. */ - xhci_dbg(xhci, "%s: starting port polling.\n", __func__); - set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); - usb_hcd_poll_rh_status(xhci->shared_hcd); + xhci_dbg(xhci, "%s: starting usb%d port polling.\n", + __func__, hcd->self.busnum); + if (xhci->shared_hcd) { + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + usb_hcd_poll_rh_status(xhci->shared_hcd); + } set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); @@ -5229,6 +5247,55 @@ static int xhci_get_frame(struct usb_hcd *hcd) return readl(&xhci->run_regs->microframe_index) >> 3; } +static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct usb_hcd *hcd) +{ + xhci->usb2_rhub.hcd = hcd; + hcd->speed = HCD_USB2; + hcd->self.root_hub->speed = USB_SPEED_HIGH; + /* + * USB 2.0 roothub under xHCI has an integrated TT, + * (rate matching hub) as opposed to having an OHCI/UHCI + * companion controller. + */ + hcd->has_tt = 1; +} + +static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd) +{ + unsigned int minor_rev; + + /* + * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts + * should return 0x31 for sbrn, or that the minor revision + * is a two digit BCD containig minor and sub-minor numbers. + * This was later clarified in xHCI 1.2. + * + * Some USB 3.1 capable hosts therefore have sbrn 0x30, and + * minor revision set to 0x1 instead of 0x10. + */ + if (xhci->usb3_rhub.min_rev == 0x1) + minor_rev = 1; + else + minor_rev = xhci->usb3_rhub.min_rev / 0x10; + + switch (minor_rev) { + case 2: + hcd->speed = HCD_USB32; + hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; + hcd->self.root_hub->rx_lanes = 2; + hcd->self.root_hub->tx_lanes = 2; + break; + case 1: + hcd->speed = HCD_USB31; + hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; + break; + } + xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n", + minor_rev, minor_rev ? "Enhanced " : ""); + + xhci->usb3_rhub.hcd = hcd; +} + int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) { struct xhci_hcd *xhci; @@ -5237,7 +5304,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) * quirks */ struct device *dev = hcd->self.sysdev; - unsigned int minor_rev; int retval; /* Accept arbitrarily long scatter-gather lists */ @@ -5251,59 +5317,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci = hcd_to_xhci(hcd); - if (usb_hcd_is_primary_hcd(hcd)) { - xhci->main_hcd = hcd; - xhci->usb2_rhub.hcd = hcd; - /* Mark the first roothub as being USB 2.0. - * The xHCI driver will register the USB 3.0 roothub. - */ - hcd->speed = HCD_USB2; - hcd->self.root_hub->speed = USB_SPEED_HIGH; - /* - * USB 2.0 roothub under xHCI has an integrated TT, - * (rate matching hub) as opposed to having an OHCI/UHCI - * companion controller. - */ - hcd->has_tt = 1; - } else { - /* - * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts - * should return 0x31 for sbrn, or that the minor revision - * is a two digit BCD containig minor and sub-minor numbers. - * This was later clarified in xHCI 1.2. - * - * Some USB 3.1 capable hosts therefore have sbrn 0x30, and - * minor revision set to 0x1 instead of 0x10. - */ - if (xhci->usb3_rhub.min_rev == 0x1) - minor_rev = 1; - else - minor_rev = xhci->usb3_rhub.min_rev / 0x10; - - switch (minor_rev) { - case 2: - hcd->speed = HCD_USB32; - hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; - hcd->self.root_hub->rx_lanes = 2; - hcd->self.root_hub->tx_lanes = 2; - break; - case 1: - hcd->speed = HCD_USB31; - hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; - break; - } - xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n", - minor_rev, - minor_rev ? "Enhanced " : ""); - - xhci->usb3_rhub.hcd = hcd; - /* xHCI private pointer was set in xhci_pci_probe for the second - * registered roothub. - */ + if (!usb_hcd_is_primary_hcd(hcd)) { + xhci_hcd_init_usb3_data(xhci, hcd); return 0; } mutex_init(&xhci->mutex); + xhci->main_hcd = hcd; xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(readl(&xhci->cap_regs->hc_capbase)); @@ -5379,6 +5399,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) return retval; xhci_dbg(xhci, "Called HCD init\n"); + if (xhci_hcd_is_usb3(hcd)) + xhci_hcd_init_usb3_data(xhci, hcd); + else + xhci_hcd_init_usb2_data(xhci, hcd); + xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n", xhci->hcc_params, xhci->hci_version, xhci->quirks); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index eff7e09a3da6..a520d40836ac 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1902,6 +1902,8 @@ struct xhci_hcd { unsigned hw_lpm_support:1; /* Broken Suspend flag for SNPS Suspend resume issue */ unsigned broken_suspend:1; + /* Indicates that omitting hcd is supported if root hub has no ports */ + unsigned allow_single_roothub:1; /* cached usb2 extened protocol capabilites */ u32 *ext_caps; unsigned int num_ext_caps; @@ -1955,6 +1957,30 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) return xhci->main_hcd; } +static inline struct usb_hcd *xhci_get_usb3_hcd(struct xhci_hcd *xhci) +{ + if (xhci->shared_hcd) + return xhci->shared_hcd; + + if (!xhci->usb2_rhub.num_ports) + return xhci->main_hcd; + + return NULL; +} + +static inline bool xhci_hcd_is_usb3(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return hcd == xhci_get_usb3_hcd(xhci); +} + +static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci) +{ + return xhci->allow_single_roothub && + (!xhci->usb2_rhub.num_ports || !xhci->usb3_rhub.num_ports); +} + #define xhci_dbg(xhci, fmt, args...) \ dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args) #define xhci_err(xhci, fmt, args...) \ diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index d4ce6f0c7989..5b292531dd2f 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -95,6 +95,7 @@ extern int qcom_scm_set_remote_state(u32 state, u32 id); extern int qcom_scm_spin_cpu(void); extern void qcom_scm_set_download_mode(enum qcom_download_mode mode, phys_addr_t tcsr_boot_misc); +extern int qcom_scm_get_download_mode(unsigned int *mode, phys_addr_t tcsr_boot_misc); extern int qcom_scm_config_cpu_errata(void); extern void qcom_scm_phy_update_scm_level_shifter(u32 val); extern bool qcom_scm_pas_supported(u32 peripheral); @@ -244,6 +245,8 @@ static inline u32 qcom_scm_set_remote_state(u32 state, u32 id) static inline int qcom_scm_spin_cpu(void) { return -ENODEV; } static inline void qcom_scm_set_download_mode(enum qcom_download_mode mode, phys_addr_t tcsr_boot_misc) {} +static inline int qcom_scm_get_download_mode(unsigned int *mode, + phys_addr_t tcsr_boot_misc) {} static inline int qcom_scm_config_cpu_errata(void) { return -ENODEV; } static inline void qcom_scm_phy_update_scm_level_shifter(u32 val) {} diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 0abf3da4beac..bd2a5920b654 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -1731,7 +1731,7 @@ struct IpaDscpVlanPcpMap_t { uint8_t num_vlan; /* indicate how many vlans valid vlan above */ uint8_t num_s_vlan; /* indicate how many vlans valid in s_vlan below */ uint8_t dscp_opt; /* indicates if dscp is required or optional */ - uint8_t pad1; /* for alignment */ + uint8_t tunnel_id; /* tunnel id */ /* * The same lookup scheme, using vlan[] above, is used for * generating the first index of mpls below; and in addition, @@ -1750,8 +1750,8 @@ struct IpaDscpVlanPcpMap_t { * mpls_val_sorted is in ascending order, by mpls label values in mpls array * vlan_c and vlan_s are vlan id values that are corresponding to the mpls label */ - uint16_t pad2; /* for alignment */ - uint8_t pad3; /* for alignment */ + uint16_t del_add_vlan_id; /* vlan id to add or del */ + uint8_t is_vlan_to_del_add; /* whether to add or del vlan? */ uint8_t num_mpls_val_sorted; /* num of elements in mpls_val_sorted */ uint32_t mpls_val_sorted[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; uint16_t vlan_c[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; @@ -1825,7 +1825,7 @@ struct singletag_mux_mapping_table_t { uint8_t mux_id; /* flag if 1=>pkt_with_option_hdr 0=>pkt_without_option_hdr */ uint8_t is_v6_options_hdr_present; - uint16_t pad0; /*for alignment*/ + uint16_t tunnel_id;/* tunnel_id */ uint32_t *tunnel_template_addr; } __packed; @@ -1850,13 +1850,22 @@ struct doubletag_mux_mapping_table_t { /* max number of tunnel to support ie: per PDN two tunnel (2*8)*/ #define MAX_TUNNEL_SUPPORT 16 -/* configuration table */ +/* @tunnel_protocols_config_table_t: Config tbl for uC + * @untagged_mapping_table : Store the untag tunnel info. + * @num_of_single_tag_configs : no of active tunnel in single tag config. + * @feature_mode: which tunnel feature is enabled. + * @tunnel_id: Which tunnel info receive from ipacm. + * @is_tunnel_id_to_del: whether tunnel to delete. + * @singletag_mux_mapping_table: Store tunnel info for active tunnels. + * @num_of_double_tag_configs: no of active tunnel in double tag config. + * @doubletag_mux_mapping_table: Store double tag tunnel info. + */ struct tunnel_protocols_config_table_t { struct untag_pkt_config_t untagged_mapping_table; uint8_t num_of_single_tag_configs; - uint8_t pad0; /*for alignment*/ - uint16_t pad1; /*for alignment*/ - uint32_t pad2; /*for alignment*/ + uint8_t feature_mode; + uint16_t tunnel_id; + uint32_t is_tunnel_id_to_del; /* table for single tag pkt */ struct singletag_mux_mapping_table_t singletag_mux_mapping_table[MAX_TUNNEL_SUPPORT]; uint8_t num_of_double_tag_configs;