From 8fed1bbd7f2103dd0142d08aaf756e7b57be7a72 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Wed, 29 Nov 2023 09:37:54 +0530 Subject: [PATCH 01/15] BACKPORT: media: venus: hfi: add checks in capabilities from firmware The hfi parser, parses the capabilities received from venus firmware and copies them to core capabilities. Consider below api, for example, fill_caps - In this api, caps in core structure gets updated with the number of capabilities received in firmware data payload. If the same api is called multiple times, there is a possibility of copying beyond the max allocated size in core caps. Similar possibilities in fill_raw_fmts and fill_profile_level functions. cherry picked from 8d0b89398b7e ("media: venus: hfi: add checks to handle capabilities from firmware"). Change-Id: Ib34d6d8dd77b3997bbbc7a25376b658dbcb6bac6 Cc: stable@vger.kernel.org Fixes: 1a73374a04e5 ("media: venus: hfi_parser: add common capability parser") Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Signed-off-by: Vikash Garodia --- drivers/media/platform/qcom/venus/hfi_parser.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index 7f515a4b9bd1..f375cdd4afcb 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -86,6 +86,9 @@ static void fill_profile_level(struct venus_caps *cap, const void *data, { const struct hfi_profile_level *pl = data; + if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT) + return; + memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl)); cap->num_pl += num; } @@ -111,6 +114,9 @@ fill_caps(struct venus_caps *cap, const void *data, unsigned int num) { const struct hfi_capability *caps = data; + if (cap->num_caps + num >= MAX_CAP_ENTRIES) + return; + memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps)); cap->num_caps += num; } @@ -137,6 +143,9 @@ static void fill_raw_fmts(struct venus_caps *cap, const void *fmts, { const struct raw_formats *formats = fmts; + if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES) + return; + memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats)); cap->num_fmts += num_fmts; } @@ -159,6 +168,9 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) rawfmts[i].buftype = fmt->buffer_type; i++; + if (i >= MAX_FMT_ENTRIES) + return; + if (pinfo->num_planes > MAX_PLANES) break; From 3de9978f7031972ecf23e1de4d54c826ac344a5b Mon Sep 17 00:00:00 2001 From: Srinivasarao Pathipati Date: Fri, 3 May 2024 15:13:23 +0530 Subject: [PATCH 02/15] soc: qcom: mdt_loader: add bound checks for headers Add checks to ensure that ehdr's size not more than fw->size. Change-Id: Ia17558dfff783dc900ac67475019929ac95fe53b Signed-off-by: Srinivasarao Pathipati --- drivers/soc/qcom/mdt_loader.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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) From 1ddb3759670519401b90a0dd76f6821ce6f715f2 Mon Sep 17 00:00:00 2001 From: Vaibhav Vashisht Date: Wed, 15 May 2024 16:03:46 +0530 Subject: [PATCH 03/15] msm_ipa: Tunnel Config structure changes Added feature mode in the tunnel config structure. Change-Id: I8f52e0aee00d631aca3593ec45f8f47b6dfcf464 Signed-off-by: Vaibhav Vashisht --- include/uapi/linux/msm_ipa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 0abf3da4beac..10ab0902e5af 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -1854,7 +1854,7 @@ struct doubletag_mux_mapping_table_t { 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*/ + uint8_t feature_mode; uint16_t pad1; /*for alignment*/ uint32_t pad2; /*for alignment*/ /* table for single tag pkt */ From 4a348646df68e2c29904545e262c36c26684edf8 Mon Sep 17 00:00:00 2001 From: Pranav Mahesh Phansalkar Date: Thu, 25 Apr 2024 12:22:22 +0530 Subject: [PATCH 04/15] rpmsg: glink: Get reference of channel objects in rx path Get channel references in data receive path as channel might get freed while processing commands received from remote processor. This ensures channel context is not freed before its usage is complete. Change-Id: I7d9a98e34c21ae0d277456853a755dab8d105d5f Signed-off-by: Pranav Mahesh Phansalkar --- drivers/rpmsg/qcom_glink_native.c | 85 +++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 28 deletions(-) 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; } From 8ab07001b298e42fabad4852437f62eecf2e1efb Mon Sep 17 00:00:00 2001 From: Akash Kumar Date: Wed, 4 Oct 2023 18:39:26 +0530 Subject: [PATCH 05/15] UPSTREAM: xhci: prepare for operation without shared HCD This patch is reworked as multiple patches went to support target with only one roothub. This patch prepares xhci for the following scenario: - If either of the root hubs has no ports, then omit shared HCD. - The main HCD can be USB3 if there are no USB2 ports. (cherry picked from commit 57f23cd0bf2f ("xhci: factor out parts of xhci_gen_setup().") 4a593a62a9e3a (BACKPORT: xhci: Fix null pointer dereference in removal if xHC has only one roothub.") 669bc5a188b40 ("UPSTREAM: xhci: Add bus number to some debug messages.") 873f323618c20 ("UPSTREAM: xhci: prepare for operation without shared HCD.)" 0cf1ea040a7e2 ("BACKPORT: usb: host: xhci-plat: create shared HCD after having added the main HCD.") e0fe986972f5b ("BACKPORT: usb: host: xhci-plat: prepare operation without shared HCD.") 4736ebd7fcaff ("UPSTREAM: usb: host: xhci-plat: omit shared HCD if either root hub has no ports.") 1bd8bb7d2dfc4 ("xhci: Don't defer primary roothub registration if there is only one roothub.") https: //git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master). Change-Id: I2ebdb15ebc2125db6ee18f14291f5590139adbdf Signed-off-by: Akash Kumar --- drivers/usb/host/xhci-hub.c | 9 +- drivers/usb/host/xhci-mem.c | 11 +-- drivers/usb/host/xhci-plat.c | 59 ++++++++----- drivers/usb/host/xhci-ring.c | 3 +- drivers/usb/host/xhci.c | 165 ++++++++++++++++++++--------------- drivers/usb/host/xhci.h | 26 ++++++ 6 files changed, 172 insertions(+), 101 deletions(-) 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...) \ From 6f9f631c909b217b1510e1b385ce341a08061d6e Mon Sep 17 00:00:00 2001 From: Santosh Sakore Date: Mon, 27 May 2024 14:29:54 +0530 Subject: [PATCH 06/15] msm: adsprpc: use-after-free (UAF) in global maps Currently, remote heap maps get added to the global list before the fastrpc_internal_mmap function completes the mapping. Meanwhile, the fastrpc_internal_munmap function accesses the map, starts unmapping, and frees the map before the fastrpc_internal_mmap function completes, resulting in a use-after-free (UAF) issue. Add the map to the list after the fastrpc_internal_mmap function completes the mapping. Change-Id: Ia524f142edba57a1f389dd0e5c83a1967c7f5a59 Acked-by: Abhishek Singh Signed-off-by: Santosh Sakore --- drivers/char/adsprpc.c | 92 ++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 8e7b4eff7325..236a22608547 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ /* Uncomment this block to log an error on every VERIFY failure */ @@ -1108,64 +1108,43 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl) } while (free); } +static void fastrpc_mmap_add_global(struct fastrpc_mmap *map) +{ + struct fastrpc_apps *me = &gfa; + unsigned long irq_flags = 0; + + spin_lock_irqsave(&me->hlock, irq_flags); + hlist_add_head(&map->hn, &me->maps); + spin_unlock_irqrestore(&me->hlock, irq_flags); +} + static void fastrpc_mmap_add(struct fastrpc_mmap *map) { - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - struct fastrpc_apps *me = &gfa; + struct fastrpc_file *fl = map->fl; - spin_lock(&me->hlock); - hlist_add_head(&map->hn, &me->maps); - spin_unlock(&me->hlock); - } else { - struct fastrpc_file *fl = map->fl; - - hlist_add_head(&map->hn, &fl->maps); - } + hlist_add_head(&map->hn, &fl->maps); } static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, size_t len, int mflags, int refs, struct fastrpc_mmap **ppmap) { - struct fastrpc_apps *me = &gfa; struct fastrpc_mmap *match = NULL, *map = NULL; struct hlist_node *n; if ((va + len) < va) return -EFAULT; - if (mflags == ADSP_MMAP_HEAP_ADDR || - mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - spin_lock(&me->hlock); - hlist_for_each_entry_safe(map, n, &me->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) { - spin_unlock(&me->hlock); - return -ETOOMANYREFS; - } - map->refs++; - } - match = map; - break; - } - } - spin_unlock(&me->hlock); - } else { - hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) - return -ETOOMANYREFS; - map->refs++; - } - match = map; - break; + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + if (va >= map->va && + va + len <= map->va + map->len && + map->fd == fd) { + if (refs) { + if (map->refs + 1 == INT_MAX) + return -ETOOMANYREFS; + map->refs++; } + match = map; + break; } } if (match) { @@ -1641,7 +1620,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, } map->len = len; - fastrpc_mmap_add(map); + if ((mflags != ADSP_MMAP_HEAP_ADDR) && + (mflags != ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add(map); *ppmap = map; bail: @@ -4039,6 +4020,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_file *fl, spin_lock(&me->hlock); mem->in_use = true; spin_unlock(&me->hlock); + fastrpc_mmap_add_global(mem); } phys = mem->phys; size = mem->size; @@ -4772,7 +4754,7 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl) me->enable_ramdump = false; bail: if (err && match) - fastrpc_mmap_add(match); + fastrpc_mmap_add_global(match); return err; } @@ -4901,7 +4883,11 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, bail: if (err && map) { mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(map); + if ((map->flags == ADSP_MMAP_HEAP_ADDR) || + (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add_global(map); + else + fastrpc_mmap_add(map); mutex_unlock(&fl->map_mutex); } mutex_unlock(&fl->internal_map_mutex); @@ -4987,6 +4973,9 @@ static int fastrpc_internal_mem_map(struct fastrpc_file *fl, if (err) goto bail; ud->m.vaddrout = map->raddr; + if (ud->m.flags == ADSP_MMAP_HEAP_ADDR || + ud->m.flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + fastrpc_mmap_add_global(map); bail: if (err) { pr_err("adsprpc: %s failed to map fd %d flags %d err %d\n", @@ -5047,7 +5036,11 @@ bail: /* Add back to map list in case of error to unmap on DSP */ if (map) { mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(map); + if ((map->flags == ADSP_MMAP_HEAP_ADDR) || + (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add_global(map); + else + fastrpc_mmap_add(map); mutex_unlock(&fl->map_mutex); } } @@ -5115,6 +5108,9 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl, if (err) goto bail; map->raddr = raddr; + if (ud->flags == ADSP_MMAP_HEAP_ADDR || + ud->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + fastrpc_mmap_add_global(map); } ud->vaddrout = raddr; bail: From 62e6a8f4bb829423a1206abf0d7e728d88bdcaf6 Mon Sep 17 00:00:00 2001 From: Paras Sharma Date: Tue, 14 May 2024 12:33:46 +0530 Subject: [PATCH 07/15] PCI: Disable L0s support for SDX65 with QPS615 on CPE platform NoC timeout issues are seen with HSP attach over QPS615 switch while IPA is accessing HSP specific registers. At the time of issue link state from PARF register dump showed that link is in L0s. So, disable the L0s state as a work-around (vetted by hardware verification team) and this change should have minimum power impact. Change-Id: I21ddffdc69d83ece01ac8546c22b50b450cc6ed5 Signed-off-by: Paras Sharma --- drivers/pci/quirks.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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"); From 2142fdbde80cb26d0c3474de3169024033df7117 Mon Sep 17 00:00:00 2001 From: Khaja Hussain Shaik Khaji Date: Thu, 13 Jun 2024 00:42:50 +0530 Subject: [PATCH 08/15] defconfig: sdxlemur: Enable nodump support for sdxlemur Enable POWER_RESET_QCOM_DOWNLOAD_MODE_NODUMP for sdxlemur so that on a warm-restart, user can choose to set nodump as download mode. Change-Id: Icc600c2c45a266a56df890c16f1d32fd7a7eb98c Signed-off-by: Khaja Hussain Shaik Khaji --- arch/arm/configs/vendor/sdxlemur.config | 1 + 1 file changed, 1 insertion(+) 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 From c7cfe23876cad22565a24a7d613dc20f8189969e Mon Sep 17 00:00:00 2001 From: Khaja Hussain Shaik Khaji Date: Wed, 12 Jun 2024 15:29:45 +0530 Subject: [PATCH 09/15] power: reset: qcom-dload-mode: support for nodump mode In case of unexpected warm-restart, device will go into special download modes. Add support to not go into download modes i.e., nodump mode. Change-Id: Ica5f1b22a648458b151a8ae696e97aad83b7fc6c Signed-off-by: Khaja Hussain Shaik Khaji --- drivers/power/reset/Kconfig | 10 ++++++++++ drivers/power/reset/qcom-dload-mode.c | 11 +++++++++++ 2 files changed, 21 insertions(+) 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..e0e966a1d7f0 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; @@ -221,6 +226,12 @@ 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"); pr_err("Supported dumps: 'full', 'mini', or 'both'\n"); From db749ede68279ddeb61945846e4ccf1c78d99aea Mon Sep 17 00:00:00 2001 From: Rakesh Naidu Bhaviripudi Date: Wed, 22 May 2024 17:46:39 +0530 Subject: [PATCH 10/15] msm: kgsl: Fix error handling during drawctxt switch Currently, separate submissions are made for page table switch and context switch to the ring buffer. However, if the page table switch succeeds but the context switch fails, it can lead to use of wrong page table for drawctxt. To address this issue, submit page table switch and context switch commands as a single submission to ring buffer. Also, remove the unnecessary ADRENO_DEVICE_FAULT check and correctly put the refcount of adreno context during error cleanup. Change-Id: I1bb4ee3ebb0ce6ea32f0b6799cfb7fa89c0d09c7 Signed-off-by: Rakesh Naidu Bhaviripudi --- drivers/gpu/msm/adreno_drawctxt.c | 10 ++-- drivers/gpu/msm/adreno_iommu.c | 85 ++++++++----------------------- 2 files changed, 27 insertions(+), 68 deletions(-) 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; + } From 446a7be36fe4a8653150a75259c57a2f98a733be Mon Sep 17 00:00:00 2001 From: Khaja Hussain Shaik Khaji Date: Fri, 21 Jun 2024 00:35:37 +0530 Subject: [PATCH 11/15] firmware: qcom_scm: Add a call for getting dload mode Add an SCM call to read the dload mode cookie, which can be used in various drivers to make decisions based on the dload mode. Earlier, this support was not there and HLOS was not aware of changes in this cookie, outside of its domain. Change-Id: I3bb82b65bc411354090b34b98f7e651dd1888e5b Signed-off-by: Khaja Hussain Shaik Khaji --- drivers/firmware/qcom_scm.c | 19 +++++++++++++++++++ include/linux/qcom_scm.h | 3 +++ 2 files changed, 22 insertions(+) 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/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) {} From cef0450861ab82a161dbb95c336641a06ad59009 Mon Sep 17 00:00:00 2001 From: Khaja Hussain Shaik Khaji Date: Fri, 21 Jun 2024 00:39:41 +0530 Subject: [PATCH 12/15] power: reset: qcom-dload-mode: nodump mode error handling In case nodump mode is already set, do not allow user to change dump mode to other modes now. Change-Id: I25b9e0d20b4dca2fb19d22f225a3dd9f0ea66cc5 Signed-off-by: Khaja Hussain Shaik Khaji --- drivers/power/reset/qcom-dload-mode.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/power/reset/qcom-dload-mode.c b/drivers/power/reset/qcom-dload-mode.c index e0e966a1d7f0..5298b80921c9 100644 --- a/drivers/power/reset/qcom-dload-mode.c +++ b/drivers/power/reset/qcom-dload-mode.c @@ -219,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; @@ -234,7 +245,11 @@ static ssize_t dload_mode_store(struct kobject *kobj, #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; } From 8837f6669e2707f44751b5df7213a59b4fab1d19 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 18 Jun 2024 17:41:09 +0530 Subject: [PATCH 13/15] usb: gadget: f_cdev: Add remote wakeup capability from notify_serial_state Currently if the Modem sends notifications like Rind Indicator or Carrier Detect, we just bail out if USB is already suspended. Add remote wakeup capability in this path. Change-Id: I62321d67e54390f167776af563c0b666b0d9e789 Signed-off-by: Prashanth K --- drivers/usb/gadget/function/f_cdev.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) 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; } From 00d7d1195d28a82e45f704703a7e923e470abeec Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 18 Jun 2024 15:38:47 +0530 Subject: [PATCH 14/15] usb: dwc3: Fix dwc3 version and revisions in remote wakeup path Currently inorder to issue remote wakup to host, we perform some register operations which are needed only for DWC3_IP versions >= 194A, but we do perform operations for DWC31_IP controllers as well, which is not expected. Hence cleanup the IP and revisions of DWC3 in remote wakup path. Change-Id: Idede7b05b1fb53fe582c6e2d7483784d578a9738 Signed-off-by: Prashanth K --- drivers/usb/dwc3/gadget.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) 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); From 503c564d871fc77bcbaf9102b9219f108b837737 Mon Sep 17 00:00:00 2001 From: Himansu Nayak Date: Wed, 29 May 2024 11:30:12 +0530 Subject: [PATCH 15/15] msm_ipa: EoGRE Multi tunnel support Updated the existing pad variable to support multi tunnel in SINGLE_TAG feature. Change-Id: I9be926250308e1b4375b677834e0e83eaa9aad41 Signed-off-by: Himansu Nayak --- include/uapi/linux/msm_ipa.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 10ab0902e5af..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 feature_mode; - uint16_t pad1; /*for alignment*/ - uint32_t pad2; /*for alignment*/ + 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;