// SPDX-License-Identifier: GPL-2.0 /* * PCI Virtual Channel support * * Copyright (C) 2013 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <[email protected]> */ #include <linux/bitfield.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/types.h> #include "pci.h" /** * pci_vc_save_restore_dwords - Save or restore a series of dwords * @dev: device * @pos: starting config space position * @buf: buffer to save to or restore from * @dwords: number of dwords to save/restore * @save: whether to save or restore */ static void pci_vc_save_restore_dwords(struct pci_dev *dev, int pos, u32 *buf, int dwords, bool save) { … } /** * pci_vc_load_arb_table - load and wait for VC arbitration table * @dev: device * @pos: starting position of VC capability (VC/VC9/MFVC) * * Set Load VC Arbitration Table bit requesting hardware to apply the VC * Arbitration Table (previously loaded). When the VC Arbitration Table * Status clears, hardware has latched the table into VC arbitration logic. */ static void pci_vc_load_arb_table(struct pci_dev *dev, int pos) { … } /** * pci_vc_load_port_arb_table - Load and wait for VC port arbitration table * @dev: device * @pos: starting position of VC capability (VC/VC9/MFVC) * @res: VC resource number, ie. VCn (0-7) * * Set Load Port Arbitration Table bit requesting hardware to apply the Port * Arbitration Table (previously loaded). When the Port Arbitration Table * Status clears, hardware has latched the table into port arbitration logic. */ static void pci_vc_load_port_arb_table(struct pci_dev *dev, int pos, int res) { … } /** * pci_vc_enable - Enable virtual channel * @dev: device * @pos: starting position of VC capability (VC/VC9/MFVC) * @res: VC res number, ie. VCn (0-7) * * A VC is enabled by setting the enable bit in matching resource control * registers on both sides of a link. We therefore need to find the opposite * end of the link. To keep this simple we enable from the downstream device. * RC devices do not have an upstream device, nor does it seem that VC9 do * (spec is unclear). Once we find the upstream device, match the VC ID to * get the correct resource, disable and enable on both ends. */ static void pci_vc_enable(struct pci_dev *dev, int pos, int res) { … } /** * pci_vc_do_save_buffer - Size, save, or restore VC state * @dev: device * @pos: starting position of VC capability (VC/VC9/MFVC) * @save_state: buffer for save/restore * @save: if provided a buffer, this indicates what to do with it * * Walking Virtual Channel config space to size, save, or restore it * is complicated, so we do it all from one function to reduce code and * guarantee ordering matches in the buffer. When called with NULL * @save_state, return the size of the necessary save buffer. When called * with a non-NULL @save_state, @save determines whether we save to the * buffer or restore from it. */ static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos, struct pci_cap_saved_state *save_state, bool save) { … } static struct { … } vc_caps[] = …; /** * pci_save_vc_state - Save VC state to pre-allocate save buffer * @dev: device * * For each type of VC capability, VC/VC9/MFVC, find the capability and * save it to the pre-allocated save buffer. */ int pci_save_vc_state(struct pci_dev *dev) { … } /** * pci_restore_vc_state - Restore VC state from save buffer * @dev: device * * For each type of VC capability, VC/VC9/MFVC, find the capability and * restore it from the previously saved buffer. */ void pci_restore_vc_state(struct pci_dev *dev) { … } /** * pci_allocate_vc_save_buffers - Allocate save buffers for VC caps * @dev: device * * For each type of VC capability, VC/VC9/MFVC, find the capability, size * it, and allocate a buffer for save/restore. */ void pci_allocate_vc_save_buffers(struct pci_dev *dev) { … }