@@ -5583,7 +5583,7 @@ static void nvme_process_sq(void *opaque)
}
}
-static void nvme_ctrl_reset(NvmeCtrl *n)
+static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst)
{
NvmeNamespace *ns;
int i;
@@ -5615,7 +5615,9 @@ static void nvme_ctrl_reset(NvmeCtrl *n)
}
if (!pci_is_vf(&n->parent_obj) && n->params.sriov_max_vfs) {
- pcie_sriov_pf_disable_vfs(&n->parent_obj);
+ if (rst != NVME_RESET_CONTROLLER) {
+ pcie_sriov_pf_disable_vfs(&n->parent_obj);
+ }
}
n->aer_queued = 0;
@@ -5849,7 +5851,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
}
} else if (!NVME_CC_EN(data) && NVME_CC_EN(cc)) {
trace_pci_nvme_mmio_stopped();
- nvme_ctrl_reset(n);
+ nvme_ctrl_reset(n, NVME_RESET_CONTROLLER);
cc = 0;
csts &= ~NVME_CSTS_READY;
}
@@ -6406,6 +6408,28 @@ static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset,
PCI_BASE_ADDRESS_MEM_TYPE_64, bar_size);
}
+static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
+{
+ Error *err = NULL;
+ int ret;
+
+ ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset,
+ PCI_PM_SIZEOF, &err);
+ if (err) {
+ error_report_err(err);
+ return ret;
+ }
+
+ pci_set_word(pci_dev->config + offset + PCI_PM_PMC,
+ PCI_PM_CAP_VER_1_2);
+ pci_set_word(pci_dev->config + offset + PCI_PM_CTRL,
+ PCI_PM_CTRL_NO_SOFT_RESET);
+ pci_set_word(pci_dev->wmask + offset + PCI_PM_CTRL,
+ PCI_PM_CTRL_STATE_MASK);
+
+ return 0;
+}
+
static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
{
uint8_t *pci_conf = pci_dev->config;
@@ -6427,7 +6451,9 @@ static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
}
pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_EXPRESS);
+ nvme_add_pm_capability(pci_dev, 0x60);
pcie_endpoint_cap_init(pci_dev, 0x80);
+ pcie_cap_flr_init(pci_dev);
if (n->params.sriov_max_vfs) {
pcie_ari_init(pci_dev, 0x100, 1);
}
@@ -6676,7 +6702,7 @@ static void nvme_exit(PCIDevice *pci_dev)
NvmeNamespace *ns;
int i;
- nvme_ctrl_reset(n);
+ nvme_ctrl_reset(n, NVME_RESET_FUNCTION);
if (n->subsys) {
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
@@ -6775,6 +6801,15 @@ static void nvme_set_smart_warning(Object *obj, Visitor *v, const char *name,
}
}
+static void nvme_pci_reset(DeviceState *qdev)
+{
+ PCIDevice *pci_dev = PCI_DEVICE(qdev);
+ NvmeCtrl *n = NVME(pci_dev);
+
+ trace_pci_nvme_pci_reset();
+ nvme_ctrl_reset(n, NVME_RESET_FUNCTION);
+}
+
static void nvme_sriov_pre_write_ctrl(PCIDevice *dev, uint32_t address,
uint32_t val, int len)
{
@@ -6808,6 +6843,7 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
{
nvme_sriov_pre_write_ctrl(dev, address, val, len);
pci_default_write_config(dev, address, val, len);
+ pcie_cap_flr_write_config(dev, address, val, len);
}
static const VMStateDescription nvme_vmstate = {
@@ -6830,6 +6866,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
dc->desc = "Non-Volatile Memory Express";
device_class_set_props(dc, nvme_props);
dc->vmsd = &nvme_vmstate;
+ dc->reset = nvme_pci_reset;
}
static void nvme_instance_init(Object *obj)
@@ -471,6 +471,11 @@ typedef struct NvmeCtrl {
NvmeSecCtrlList sec_ctrl_list;
} NvmeCtrl;
+typedef enum NvmeResetType {
+ NVME_RESET_FUNCTION = 0,
+ NVME_RESET_CONTROLLER = 1,
+} NvmeResetType;
+
static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
{
if (!nsid || nsid > NVME_MAX_NAMESPACES) {
@@ -105,6 +105,7 @@ pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone de
pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32""
pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state"
pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state"
+pci_nvme_pci_reset(void) "PCI Function Level Reset"
# error conditions
pci_nvme_err_mdts(size_t len) "len %zu"