From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f199.google.com (mail-pf1-f199.google.com [209.85.210.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74BBF53F6B5 for ; Thu, 24 Sep 2026 17:35:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.199 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790271323; cv=none; b=Kg3zN1uUHkngkOYv5OfAc9zGLNqLpkoH058fgjtXiB+cbjCi+DlfJnfg5qSrPCVlDVUq9luLFFbdFfTqfx6yymAg4qW/3dBxh9JoOcjVoW36atO02RczLW0PsIdWd1ZFw91VNm99f3Y1/uul3tUvfVdKSV5Owr4fqWKpsehkx04= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790271323; c=relaxed/simple; bh=gVaN4rPHSo+YJcfNKYUlKRUwEkAznxWgxA/JWQOZlkk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gjB1AqPoSLBFcs0rQ4FU+IE2cC+h7CA3XFglojvLhid6JUAJpFf+/qRsSNz+vjBY0hAbJaAZOhpsxVprZIUrrf1bmm3Vmy0rg90nnlpjzNrdCjsQTEK0rBxA0joliey3P5gJGmVHIUTDn0rolXHYBopI93QspDfSwU70VzsCc/Q= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GFPerJF6; arc=none smtp.client-ip=209.85.210.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GFPerJF6" Received: by mail-pf1-f199.google.com with SMTP id d2e1a72fcca58-86917d18a02so111889b3a.1 for ; Thu, 24 Sep 2026 10:35:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1790271321; x=1790876121; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=I5Z8coCk3E9gqKO3PHj9jQ4bq0JckBz/qt0J/ndctwk=; b=GFPerJF6JXPNEglBEKt5SiKXrEGMOp+fKcgZeAiPeq0wpHl/BVG3Gs1ztensJToz40 JSP+JL3ycs+RJsB0LZWvppPhLzR60wR63WPDt+kkwA6AN/ZTysWSM418VpOajiFrTwKF OJdNBtUufQTpq86+Yp84+6hhWjv4bOk4EGFpxC3V9k69YsY9ILNyDtPPiS6Fp3a6Alh/ dGlgQ4Ramji6NBm7J5ZNiFpbSmzHrF96db4e2QOkNOmBEnNDJ5Obx53ePWNIjnW2eq7U aGb2IpjKGCIJ+jKYdX9kshje1AXSq658IUhzhbQh5I0IfmHlSySsA/vFuBBLTFqvNE/5 Plow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790271321; x=1790876121; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=I5Z8coCk3E9gqKO3PHj9jQ4bq0JckBz/qt0J/ndctwk=; b=pRQkRKBBGesm5SiBagMsDxyg5m3Fktc/+KSWonXyhan4906vq6sbbPeA9xgZ3mvn9P uZBynQSXkFAPyZc6oJ/EK3EUmMukpXGK0eOL1wIxxbtmEtEntqZrx5umlfDfqe/oIpY2 zbHCFPHLixb3Hy/JfKjBwxm52O275DVVOnxvH+IlK/kLUWQT+XXgXzvJSyQXT9HFG0qF +Wx/z1OA8jwbEAawCJvdvArqCCH2V5bsNwxAP4fGGXbE8mHKkshgibeCvXlUDBd4d0EI 82xuZFqWGVL6wsvkVLtjZUWMtEnTz10o7Qumd7DzHWnifpUCM0YanAI3MxA2FFm3cY34 8DcA== X-Gm-Message-State: AFuF++lJ5SFDcU8QNJnHq9Aboqn9BJQDteBgS0rUEp2VnGaW7ro+sVo4 OnbhX/NalPOy9y5CHHO0lMyvAU+fY6X4ozEscDsQQMd4E6XZX55hiXCKacFo9xok/LDNme5hlkB X36c2T/K16r71z9Cy6Hiedvnp8IrPJz0/IPpqoAGF+6HXxdroPXRhMv0iID0BGhcCreMnN41WEp NLHe5ORcH6gkOVt/Jf+3ED1JqIfOPWB9aeU4I8cZmrRD0NDQ2eobBHGxY= X-Received: from pgbcv2.prod.google.com ([2002:a05:6a02:4202:b0:cc7:6228:9be5]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:3d82:b0:3dd:a006:7b3d with SMTP id adf61e73a8af0-3de0e895d9fmr2863185637.60.1790271320315; Thu, 24 Sep 2026 10:35:20 -0700 (PDT) Date: Thu, 24 Sep 2026 17:35:01 +0000 In-Reply-To: <20260924173501.856380-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260924173501.856380-1-dmatlack@google.com> X-Mailer: git-send-email 2.56.0.rc1.315.gc6ed9934b7-goog Message-ID: <20260924173501.856380-16-dmatlack@google.com> Subject: [PATCH 15/15] PCI: Remove the per-capability save buffers From: David Matlack To: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: Alex Williamson , Bjorn Helgaas , Jason Gunthorpe , Josh Hilke , Lukas Wunner , Mahesh J Salgaonkar , "Oliver O'Halloran" , Pasha Tatashin , Pratyush Yadav , Samiullah Khawaja , Vipin Sharma , David Matlack Content-Type: text/plain; charset="UTF-8" Delete struct pci_cap_saved_state, struct pci_cap_saved_data, pci_dev.saved_cap_space and the helpers that managed them. Every capability now saves its registers in the offset-indexed capability store, so nothing is left to find, allocate or free. That retires the last of nine separate save buffer allocations, four of which ignored their allocation failure entirely. Rename pci_allocate_cap_save_buffers() to pci_reserve_saved_caps(), which is all it does now, and drop pci_free_cap_save_buffers() from pci_release_capabilities(); pci_saved_caps_release() already frees the one remaining allocation. pci_store_saved_state() and pci_load_saved_state() no longer have to append and consume the records of the capabilities that still had a buffer, so the blob they exchange is now just the saved DWORDs. Assisted-by: LLM Signed-off-by: David Matlack --- drivers/pci/pci.c | 140 +------------------------------------------- drivers/pci/pci.h | 21 +------ drivers/pci/probe.c | 5 +- include/linux/pci.h | 1 - 4 files changed, 6 insertions(+), 161 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 73aa526e6901..b6e14c9a6c20 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1663,28 +1663,6 @@ static const u16 pcie_saved_regs[] = { PCI_EXP_SLTCTL2, }; -static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev, - u16 cap, bool extended) -{ - struct pci_cap_saved_state *tmp; - - hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) { - if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap) - return tmp; - } - return NULL; -} - -struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap) -{ - return _pci_find_saved_cap(dev, cap, false); -} - -struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap) -{ - return _pci_find_saved_cap(dev, cap, true); -} - static void pci_restore_pcie_state(struct pci_dev *dev) { unsigned int i; @@ -1844,32 +1822,12 @@ EXPORT_SYMBOL(pci_restore_state); * * Laid out so that the position of every value is described by the device's * configuration space rather than by the kernel. - * - * Capabilities that have not moved to the saved capability store yet keep - * their own buffer, and their records trail @dword_val until the last of - * those buffers goes away. Both areas vary in length and only one of them - * can be a flexible array member, so the records are reached with - * pci_saved_state_records() rather than declared here. */ struct pci_saved_state { unsigned long dword_map[BITS_TO_LONGS(PCI_CFG_SPACE_EXP_DWORDS)]; u32 dword_val[]; - /* struct pci_cap_saved_data cap[] follows dword_val */ }; -/* - * The records that follow the saved DWORDs, one per capability that still has - * its own save buffer, terminated by an empty record. - */ -static struct pci_cap_saved_data * -pci_saved_state_records(struct pci_saved_state *state) -{ - unsigned int nr_dwords = bitmap_weight(state->dword_map, - PCI_CFG_SPACE_EXP_DWORDS); - - return (struct pci_cap_saved_data *)&state->dword_val[nr_dwords]; -} - /** * pci_store_saved_state - Allocate and return an opaque struct containing * the device saved state. @@ -1881,11 +1839,8 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev) { DECLARE_BITMAP(map, PCI_CFG_SPACE_EXP_DWORDS); struct pci_saved_caps *caps = &dev->saved_caps; - struct pci_cap_saved_state *tmp; - struct pci_cap_saved_data *cap; struct pci_saved_state *state; unsigned int dword, nr_dwords, i = 0; - size_t size; if (!dev->state_saved) return NULL; @@ -1897,14 +1852,7 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev) nr_dwords = bitmap_weight(map, PCI_CFG_SPACE_EXP_DWORDS); - size = struct_size(state, dword_val, nr_dwords); - - /* Room for the buffers that are left, and for the terminator */ - size += sizeof(struct pci_cap_saved_data); - hlist_for_each_entry(tmp, &dev->saved_cap_space, next) - size += sizeof(struct pci_cap_saved_data) + tmp->cap.size; - - state = kzalloc(size, GFP_KERNEL); + state = kzalloc(struct_size(state, dword_val, nr_dwords), GFP_KERNEL); if (!state) return NULL; @@ -1919,15 +1867,6 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev) pci_read_saved_cap_dword(dev, dword * sizeof(u32), val); } - cap = pci_saved_state_records(state); - hlist_for_each_entry(tmp, &dev->saved_cap_space, next) { - size_t len = sizeof(struct pci_cap_saved_data) + tmp->cap.size; - - memcpy(cap, &tmp->cap, len); - cap = (struct pci_cap_saved_data *)((u8 *)cap + len); - } - /* Empty record terminates the list */ - return state; } EXPORT_SYMBOL_GPL(pci_store_saved_state); @@ -1940,7 +1879,6 @@ EXPORT_SYMBOL_GPL(pci_store_saved_state); int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state) { - struct pci_cap_saved_data *cap; unsigned int dword, i = 0; dev->state_saved = false; @@ -1967,19 +1905,6 @@ int pci_load_saved_state(struct pci_dev *dev, pci_write_saved_cap_dword(dev, off, val); } - cap = pci_saved_state_records(state); - while (cap->size) { - struct pci_cap_saved_state *tmp; - - tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended); - if (!tmp || tmp->cap.size != cap->size) - return -EINVAL; - - memcpy(tmp->cap.data, cap->data, tmp->cap.size); - cap = (struct pci_cap_saved_data *)((u8 *)cap + - sizeof(struct pci_cap_saved_data) + cap->size); - } - dev->state_saved = true; return 0; } @@ -3479,61 +3404,11 @@ void pci_ea_init(struct pci_dev *dev) offset = pci_ea_read(dev, offset); } -static void pci_add_saved_cap(struct pci_dev *pci_dev, - struct pci_cap_saved_state *new_cap) -{ - hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space); -} - /** - * _pci_add_cap_save_buffer - allocate buffer for saving given - * capability registers + * pci_reserve_saved_caps - reserve room to save capability registers * @dev: the PCI device - * @cap: the capability to allocate the buffer for - * @extended: Standard or Extended capability ID - * @size: requested size of the buffer */ -static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap, - bool extended, unsigned int size) -{ - int pos; - struct pci_cap_saved_state *save_state; - - if (extended) - pos = pci_find_ext_capability(dev, cap); - else - pos = pci_find_capability(dev, cap); - - if (!pos) - return 0; - - save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL); - if (!save_state) - return -ENOMEM; - - save_state->cap.cap_nr = cap; - save_state->cap.cap_extended = extended; - save_state->cap.size = size; - pci_add_saved_cap(dev, save_state); - - return 0; -} - -int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size) -{ - return _pci_add_cap_save_buffer(dev, cap, false, size); -} - -int pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size) -{ - return _pci_add_cap_save_buffer(dev, cap, true, size); -} - -/** - * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities - * @dev: the PCI device - */ -void pci_allocate_cap_save_buffers(struct pci_dev *dev) +void pci_reserve_saved_caps(struct pci_dev *dev) { unsigned int i; int error, pos; @@ -3567,15 +3442,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) pci_vc_reserve_saved_caps(dev); } -void pci_free_cap_save_buffers(struct pci_dev *dev) -{ - struct pci_cap_saved_state *tmp; - struct hlist_node *n; - - hlist_for_each_entry_safe(tmp, n, &dev->saved_cap_space, next) - kfree(tmp); -} - /** * pci_configure_ari - enable or disable ARI forwarding * @dev: the PCI device diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 99de55799826..343a37524a22 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -237,26 +237,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev); int pci_bus_error_reset(struct pci_dev *dev); int pci_try_reset_bridge(struct pci_dev *bridge); -struct pci_cap_saved_data { - u16 cap_nr; - bool cap_extended; - unsigned int size; - u32 data[]; -}; - -struct pci_cap_saved_state { - struct hlist_node next; - struct pci_cap_saved_data cap; -}; - -void pci_allocate_cap_save_buffers(struct pci_dev *dev); -void pci_free_cap_save_buffers(struct pci_dev *dev); -int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size); -int pci_add_ext_cap_save_buffer(struct pci_dev *dev, - u16 cap, unsigned int size); -struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap); -struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, - u16 cap); +void pci_reserve_saved_caps(struct pci_dev *dev); /* DWORDs of the configuration space header, i.e. pci_dev.saved_config_space */ #define PCI_STD_HEADER_DWORDS (PCI_STD_HEADER_SIZEOF / sizeof(u32)) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b4c0b8171d94..5f6236fc9002 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2468,7 +2468,6 @@ static void pci_release_capabilities(struct pci_dev *dev) pci_aer_exit(dev); pci_rcec_exit(dev); pci_iov_release(dev); - pci_free_cap_save_buffers(dev); pci_saved_caps_release(dev); } @@ -2654,8 +2653,8 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_msi_init(dev); /* Disable MSI */ pci_msix_init(dev); /* Disable MSI-X */ - /* Buffers for saving PCIe and PCI-X capabilities */ - pci_allocate_cap_save_buffers(dev); + /* Room to save PCIe, PCI-X and LTR state */ + pci_reserve_saved_caps(dev); pci_imm_ready_init(dev); /* Immediate Readiness */ pci_pm_init(dev); /* Power Management */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 7b80f809f934..62a541a63a0c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -548,7 +548,6 @@ struct pci_dev { spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ u32 saved_config_space[16]; /* Config space saved at suspend time */ - struct hlist_head saved_cap_space; struct pci_saved_caps saved_caps; /* Saved capability registers */ #ifdef CONFIG_HOTPLUG_PCI_PCIE -- 2.56.0.rc1.315.gc6ed9934b7-goog