From patchwork Fri Apr 15 19:54:33 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 711401 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3FJseBb032132 for ; Fri, 15 Apr 2011 19:54:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753368Ab1DOTyh (ORCPT ); Fri, 15 Apr 2011 15:54:37 -0400 Received: from mx1.redhat.com ([209.132.183.28]:31420 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751910Ab1DOTyg (ORCPT ); Fri, 15 Apr 2011 15:54:36 -0400 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p3FJsYtJ013349 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 15 Apr 2011 15:54:34 -0400 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p3FJsX6s032270; Fri, 15 Apr 2011 15:54:33 -0400 From: Alex Williamson Subject: [PATCH 1/2] PCI: Add interfaces to store and load the device saved state To: linux-pci@vger.kernel.org, kvm@vger.kernel.org Cc: alex.williamson@redhat.com, jan.kiszka@siemens.com, avi@redhat.com, jbarnes@virtuousgeek.org Date: Fri, 15 Apr 2011 13:54:33 -0600 Message-ID: <20110415195433.2838.96871.stgit@s20.home> In-Reply-To: <20110415194220.2838.10750.stgit@s20.home> References: <20110415194220.2838.10750.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 15 Apr 2011 19:54:41 +0000 (UTC) For KVM device assignment, we'd like to save off the state of a device prior to passing it to the guest and restore it later. We also want to allow pci_reset_funciton() to be called while the device is owned by the guest. This however overwrites and invalidates the struct pci_dev buffers, so we can't just manually call save and restore. Add generic interfaces for the saved state to be stored into a buffer and reloaded back into struct pci_dev at a later time. Signed-off-by: Alex Williamson --- drivers/pci/pci.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 3 ++ 2 files changed, 97 insertions(+), 0 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2472e71..2b00354 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -975,6 +975,100 @@ void pci_restore_state(struct pci_dev *dev) dev->state_saved = false; } +struct pci_state { + u32 config_space[16]; + u16 pcie_state[PCI_EXP_SAVE_REGS]; + u16 pcix_state[1]; +}; + +/** + * pci_store_saved_state - Store the device saved state into a buffer + * @dev: - PCI device that we're dealing with + * + * Returns an opaque buffer containing the device saved state. + * NULL if no state or error. + */ +void *pci_store_saved_state(struct pci_dev *dev) +{ + struct pci_state *state; + struct pci_cap_saved_state *cap_state; + int pos; + + if (!dev->state_saved) + return NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + memcpy(state->config_space, dev->saved_config_space, + sizeof(state->config_space)); + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + cap_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); + if (cap_state && pos) + memcpy(state->pcie_state, cap_state->data, + sizeof(state->pcie_state)); + + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + cap_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); + if (cap_state && pos) + memcpy(state->pcix_state, cap_state->data, + sizeof(state->pcix_state)); + + return state; +} +EXPORT_SYMBOL_GPL(pci_store_saved_state); + +/** + * pci_load_saved_state - Load the device saved state from buffer + * @dev: - PCI device that we're dealing with + * @buf: - Saved state returned from pci_store_saved_state() + */ +void pci_load_saved_state(struct pci_dev *dev, void *buf) +{ + struct pci_state *state = buf; + struct pci_cap_saved_state *cap_state; + int pos; + + if (!state) { + dev->state_saved = false; + return; + } + + memcpy(dev->saved_config_space, state->config_space, + sizeof(state->config_space)); + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + cap_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); + if (cap_state && pos) + memcpy(cap_state->data, state->pcie_state, + sizeof(state->pcie_state)); + + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + cap_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); + if (cap_state && pos) + memcpy(cap_state->data, state->pcix_state, + sizeof(state->pcix_state)); + + dev->state_saved = true; +} +EXPORT_SYMBOL_GPL(pci_load_saved_state); + +/** + * pci_load_and_free_saved_state - Load the device saved state from buffer + * and free the buffer + * @dev: - PCI device that we're dealing with + * @buf: - Pointer to saved state returned from pci_store_saved_state() + */ +void pci_load_and_free_saved_state(struct pci_dev *dev, void **buf) +{ + pci_load_saved_state(dev, *buf); + kfree(*buf); + *buf = NULL; +} +EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state); + static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; diff --git a/include/linux/pci.h b/include/linux/pci.h index 96f70d7..67ce42a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -807,6 +807,9 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); void pci_restore_state(struct pci_dev *dev); +void *pci_store_saved_state(struct pci_dev *dev); +void pci_load_saved_state(struct pci_dev *dev, void *buf); +void pci_load_and_free_saved_state(struct pci_dev *dev, void **buf); int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state); int pci_set_power_state(struct pci_dev *dev, pci_power_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);