return ret;
 }
 
+static const char *nps_desc[] = {
+       [AMDGPU_NPS1_PARTITION_MODE] = "NPS1",
+       [AMDGPU_NPS2_PARTITION_MODE] = "NPS2",
+       [AMDGPU_NPS3_PARTITION_MODE] = "NPS3",
+       [AMDGPU_NPS4_PARTITION_MODE] = "NPS4",
+       [AMDGPU_NPS6_PARTITION_MODE] = "NPS6",
+       [AMDGPU_NPS8_PARTITION_MODE] = "NPS8",
+};
+
+static ssize_t available_memory_partition_show(struct device *dev,
+                                              struct device_attribute *addr,
+                                              char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(ddev);
+       int size = 0, mode;
+       char *sep = "";
+
+       for_each_inst(mode, adev->gmc.supported_nps_modes) {
+               size += sysfs_emit_at(buf, size, "%s%s", sep, nps_desc[mode]);
+               sep = ", ";
+       }
+       size += sysfs_emit_at(buf, size, "\n");
+
+       return size;
+}
+
+static ssize_t current_memory_partition_store(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t count)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(ddev);
+       enum amdgpu_memory_partition mode;
+       struct amdgpu_hive_info *hive;
+       int i;
+
+       mode = UNKNOWN_MEMORY_PARTITION_MODE;
+       for_each_inst(i, adev->gmc.supported_nps_modes) {
+               if (!strncasecmp(nps_desc[i], buf, strlen(nps_desc[i]))) {
+                       mode = i;
+                       break;
+               }
+       }
+
+       if (mode == UNKNOWN_MEMORY_PARTITION_MODE)
+               return -EINVAL;
+
+       if (mode == adev->gmc.gmc_funcs->query_mem_partition_mode(adev)) {
+               dev_info(
+                       adev->dev,
+                       "requested NPS mode is same as current NPS mode, skipping\n");
+               return count;
+       }
+
+       /* If device is part of hive, all devices in the hive should request the
+        * same mode. Hence store the requested mode in hive.
+        */
+       hive = amdgpu_get_xgmi_hive(adev);
+       if (hive) {
+               atomic_set(&hive->requested_nps_mode, mode);
+               amdgpu_put_xgmi_hive(hive);
+       } else {
+               adev->gmc.requested_nps_mode = mode;
+       }
+
+       dev_info(
+               adev->dev,
+               "NPS mode change requested, please remove and reload the driver\n");
+
+       return count;
+}
+
 static ssize_t current_memory_partition_show(
        struct device *dev, struct device_attribute *addr, char *buf)
 {
        enum amdgpu_memory_partition mode;
 
        mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev);
-       switch (mode) {
-       case AMDGPU_NPS1_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS1\n");
-       case AMDGPU_NPS2_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS2\n");
-       case AMDGPU_NPS3_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS3\n");
-       case AMDGPU_NPS4_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS4\n");
-       case AMDGPU_NPS6_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS6\n");
-       case AMDGPU_NPS8_PARTITION_MODE:
-               return sysfs_emit(buf, "NPS8\n");
-       default:
+       if ((mode > ARRAY_SIZE(nps_desc)) ||
+           (BIT(mode) & AMDGPU_ALL_NPS_MASK) != BIT(mode))
                return sysfs_emit(buf, "UNKNOWN\n");
-       }
+
+       return sysfs_emit(buf, "%s\n", nps_desc[mode]);
 }
 
-static DEVICE_ATTR_RO(current_memory_partition);
+static DEVICE_ATTR_RW(current_memory_partition);
+static DEVICE_ATTR_RO(available_memory_partition);
 
 int amdgpu_gmc_sysfs_init(struct amdgpu_device *adev)
 {
+       bool nps_switch_support;
+       int r = 0;
+
        if (!adev->gmc.gmc_funcs->query_mem_partition_mode)
                return 0;
 
+       nps_switch_support = (hweight32(adev->gmc.supported_nps_modes &
+                                       AMDGPU_ALL_NPS_MASK) > 1);
+       if (!nps_switch_support)
+               dev_attr_current_memory_partition.attr.mode &=
+                       ~(S_IWUSR | S_IWGRP | S_IWOTH);
+       else
+               r = device_create_file(adev->dev,
+                                      &dev_attr_available_memory_partition);
+
+       if (r)
+               return r;
+
        return device_create_file(adev->dev,
                                  &dev_attr_current_memory_partition);
 }
 
 void amdgpu_gmc_sysfs_fini(struct amdgpu_device *adev)
 {
+       if (!adev->gmc.gmc_funcs->query_mem_partition_mode)
+               return;
+
        device_remove_file(adev->dev, &dev_attr_current_memory_partition);
+       device_remove_file(adev->dev, &dev_attr_available_memory_partition);
 }
 
 int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev,