factory_ufs: Add support for enabling per-LU WB

This change adds write booster support for devices that only support
per-LU WB, without this, such devices would have potentially 1/3rd of
the write performance.

BUG=b:433333075
TEST=chromeos-install on xol, verified dLUNumWriteBoosterBufferAllocUnits for LUN0
and fWriteBoosterEn := 0x1

Change-Id: Icb11b956b4a6d3a8359cc7b6dffd1ed379fc6b98
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/factory_installer/+/6803510
Commit-Queue: Sarthak Kukreti <sarthakkukreti@google.com>
Reviewed-by: Sarthak Kukreti <sarthakkukreti@google.com>
Tested-by: Alexis Savery <asavery@chromium.org>
Auto-Submit: Alexis Savery <asavery@chromium.org>
Tested-by: Sarthak Kukreti <sarthakkukreti@google.com>
diff --git a/rust/src/factory_ufs/action/provision.rs b/rust/src/factory_ufs/action/provision.rs
index 5196d56..c6f5bbe 100644
--- a/rust/src/factory_ufs/action/provision.rs
+++ b/rust/src/factory_ufs/action/provision.rs
@@ -249,6 +249,10 @@
         }
         _ => false,
     };
+    let support_lu_based_buffer = match FromPrimitive::from_u32(wb_sup_wb_type) {
+        Some(SupportedWBBufferTypes::LUBased) | Some(SupportedWBBufferTypes::SupportBoth) => true,
+        _ => false,
+    };
 
     println!(
         "DEVICE_DESC.dExtendedUFSFeaturesSupport: {}",
@@ -280,6 +284,22 @@
             "{} units is allocated for write booster buffer.",
             wb_alloc_units
         );
+    } else if support_write_booster && support_preserver_user_space && support_lu_based_buffer {
+        // Reads the GEOM_DESC.dWriteBoosterBufferMaxNAllocUnits bits.
+        // This is the maximum total write booster buffer size which is
+        // supported by the entire device.
+        let wb_max_alloc_units =
+            file_utils::read_geometry_descriptor(&sys_dev_path, "wb_max_alloc_units")?;
+        println!(
+            "GEOM_DESC.dWriteBoosterBufferMaxNAllocUnits: {}",
+            wb_max_alloc_units
+        );
+        println!("Enable LU-based write booster...");
+        let wb_alloc_units = ufs_config.enable_lu_write_booster(wb_max_alloc_units)?;
+        println!(
+            "{} units is allocated for write booster buffer.",
+            wb_alloc_units
+        );
     } else {
         println!("Disable write booster...");
         ufs_config.disable_write_booster()?;
diff --git a/rust/src/factory_ufs/ufs/descriptor/config.rs b/rust/src/factory_ufs/ufs/descriptor/config.rs
index 4080445..44bb684 100644
--- a/rust/src/factory_ufs/ufs/descriptor/config.rs
+++ b/rust/src/factory_ufs/ufs/descriptor/config.rs
@@ -1,4 +1,4 @@
-// Copyright 2022 The ChromiumOS Authors.
+// Copyright 2022 The ChromiumOS Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,7 +7,7 @@
 
 use crate::factory_ufs::ufs::descriptor::common::CommonDescriptorTrait;
 use crate::factory_ufs::ufs::descriptor::device::WriteBooster;
-use crate::factory_ufs::ufs::descriptor::unit::{GetUnitField, ProvisionLun};
+use crate::factory_ufs::ufs::descriptor::unit::{EnableLUWriteBooster, GetUnitField, ProvisionLun};
 
 /// Defines the the config descriptor for UFS provisioning.
 ///
@@ -64,13 +64,14 @@
 pub trait WriteBoosterConfig {
     fn support_write_booster(&self) -> bool;
     fn enable_write_booster(&mut self, wb_max_alloc_units: u32) -> Result<u32>;
+    fn enable_lu_write_booster(&mut self, wb_max_alloc_units: u32) -> Result<u32>;
     fn disable_write_booster(&mut self) -> Result<()>;
 }
 
 impl<D, U> WriteBoosterConfig for ConfigDescriptor<D, U>
 where
     D: WriteBooster,
-    U: GetUnitField,
+    U: GetUnitField + EnableLUWriteBooster,
 {
     fn support_write_booster(&self) -> bool {
         self.device_config.support_write_booster()
@@ -81,6 +82,12 @@
             .enable_write_booster(wb_max_alloc_units, self.units_config[0].get_alloc_units())
     }
 
+    fn enable_lu_write_booster(&mut self, wb_max_alloc_units: u32) -> Result<u32> {
+        self.device_config.enable_lu_write_booster()?;
+        self.units_config[0]
+            .enable_lu_write_booster(wb_max_alloc_units, self.units_config[0].get_alloc_units())
+    }
+
     fn disable_write_booster(&mut self) -> Result<()> {
         self.device_config.disable_write_booster()
     }
diff --git a/rust/src/factory_ufs/ufs/descriptor/device.rs b/rust/src/factory_ufs/ufs/descriptor/device.rs
index bc3a7c7..ed859a2 100644
--- a/rust/src/factory_ufs/ufs/descriptor/device.rs
+++ b/rust/src/factory_ufs/ufs/descriptor/device.rs
@@ -1,4 +1,4 @@
-// Copyright 2022 The ChromiumOS Authors.
+// Copyright 2022 The ChromiumOS Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -12,6 +12,7 @@
         wb_max_alloc_units: u32,
         lun0_alloc_units: u32,
     ) -> Result<u32>;
+    fn enable_lu_write_booster(&mut self) -> Result<()>;
     fn disable_write_booster(&mut self) -> Result<()>;
 }
 
diff --git a/rust/src/factory_ufs/ufs/descriptor/unit.rs b/rust/src/factory_ufs/ufs/descriptor/unit.rs
index 39bcdd1..62f0ac0 100644
--- a/rust/src/factory_ufs/ufs/descriptor/unit.rs
+++ b/rust/src/factory_ufs/ufs/descriptor/unit.rs
@@ -1,7 +1,9 @@
-// Copyright 2022 The ChromiumOS Authors.
+// Copyright 2022 The ChromiumOS Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use anyhow::Result;
+
 pub trait ProvisionLun {
     fn provision_lun(&mut self, alloc_units: u32);
 }
@@ -11,3 +13,11 @@
     fn get_lu_enabled(&self) -> u8;
     fn get_provisioning_type(&self) -> u8;
 }
+
+pub trait EnableLUWriteBooster {
+    fn enable_lu_write_booster(
+        &mut self,
+        wb_max_alloc_units: u32,
+        lun0_alloc_units: u32,
+    ) -> Result<u32>;
+}
diff --git a/rust/src/factory_ufs/ufs/spec/ufs_2_1.rs b/rust/src/factory_ufs/ufs/spec/ufs_2_1.rs
index 1d320e2..704d310 100644
--- a/rust/src/factory_ufs/ufs/spec/ufs_2_1.rs
+++ b/rust/src/factory_ufs/ufs/spec/ufs_2_1.rs
@@ -8,7 +8,7 @@
 use crate::factory_ufs::ufs::descriptor::common::CommonDescriptorTrait;
 use crate::factory_ufs::ufs::descriptor::config::ConfigDescriptor;
 use crate::factory_ufs::ufs::descriptor::device::{GetDeviceField, WriteBooster};
-use crate::factory_ufs::ufs::descriptor::unit::{GetUnitField, ProvisionLun};
+use crate::factory_ufs::ufs::descriptor::unit::{EnableLUWriteBooster, GetUnitField, ProvisionLun};
 use crate::factory_ufs::ufs::spec::constants;
 use crate::utils::error::Error;
 
@@ -79,6 +79,10 @@
         anyhow::bail!(Error::NotImplementedError)
     }
 
+    fn enable_lu_write_booster(&mut self) -> Result<()> {
+        anyhow::bail!(Error::NotImplementedError)
+    }
+
     fn disable_write_booster(&mut self) -> Result<()> {
         anyhow::bail!(Error::NotImplementedError)
     }
@@ -139,6 +143,16 @@
     }
 }
 
+impl EnableLUWriteBooster for UnitConfigDescriptor {
+    fn enable_lu_write_booster(
+        &mut self,
+        _wb_max_alloc_units: u32,
+        _lun0_alloc_units: u32,
+    ) -> Result<u32> {
+        anyhow::bail!(Error::NotImplementedError)
+    }
+}
+
 impl CommonDescriptorTrait<'_> for UnitConfigDescriptor {}
 
 pub type UFS2ConfigDescriptor = ConfigDescriptor<DeviceConfigDescriptor, UnitConfigDescriptor>;
diff --git a/rust/src/factory_ufs/ufs/spec/ufs_3_1.rs b/rust/src/factory_ufs/ufs/spec/ufs_3_1.rs
index 620db75..f630865 100644
--- a/rust/src/factory_ufs/ufs/spec/ufs_3_1.rs
+++ b/rust/src/factory_ufs/ufs/spec/ufs_3_1.rs
@@ -1,4 +1,4 @@
-// Copyright 2022 The ChromiumOS Authors.
+// Copyright 2022 The ChromiumOS Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -10,7 +10,7 @@
 use crate::factory_ufs::ufs::descriptor::common::CommonDescriptorTrait;
 use crate::factory_ufs::ufs::descriptor::config::ConfigDescriptor;
 use crate::factory_ufs::ufs::descriptor::device::{GetDeviceField, WriteBooster};
-use crate::factory_ufs::ufs::descriptor::unit::{GetUnitField, ProvisionLun};
+use crate::factory_ufs::ufs::descriptor::unit::{EnableLUWriteBooster, GetUnitField, ProvisionLun};
 use crate::factory_ufs::ufs::spec::constants;
 
 /// Defines the config descriptor for device.
@@ -96,6 +96,13 @@
         Ok(self.d_num_shared_write_booster_buffer_alloc_units)
     }
 
+    fn enable_lu_write_booster(&mut self) -> Result<()> {
+        self.b_write_booster_buffer_preserve_user_space_en = 0x1;
+        self.b_write_booster_buffer_type = 0x0;
+        self.d_num_shared_write_booster_buffer_alloc_units = 0x0;
+        Ok(())
+    }
+
     fn disable_write_booster(&mut self) -> Result<()> {
         self.b_write_booster_buffer_preserve_user_space_en = 0x0;
         self.b_write_booster_buffer_type = 0x0;
@@ -121,10 +128,10 @@
     pub w_context_capabilities: u16,
     pub reserved_empty_1: u16,
     pub reserved_empty_2: u8,
-    pub reserved_hpb: u16,
+    pub w_lu_max_active_hpb_regions: u16,
     pub w_hpb_pinned_region_start_idx: u16,
     pub w_num_hpb_pinned_regions: u16,
-    pub w_lu_max_active_hpb_regions: u32,
+    pub d_lu_num_write_booster_buffer_alloc_units: u32,
 }
 
 impl Default for UnitConfigDescriptor {
@@ -141,10 +148,10 @@
             w_context_capabilities: 0x0,
             reserved_empty_1: 0x0,
             reserved_empty_2: 0x0,
-            reserved_hpb: 0x0,
+            w_lu_max_active_hpb_regions: 0x0,
             w_hpb_pinned_region_start_idx: 0x0,
             w_num_hpb_pinned_regions: 0x0,
-            w_lu_max_active_hpb_regions: 0x0,
+            d_lu_num_write_booster_buffer_alloc_units: 0x0,
         }
     }
 }
@@ -169,6 +176,20 @@
     }
 }
 
+impl EnableLUWriteBooster for UnitConfigDescriptor {
+    fn enable_lu_write_booster(
+        &mut self,
+        wb_max_alloc_units: u32,
+        lun0_alloc_units: u32,
+    ) -> Result<u32> {
+        // min(10% of total capacity, the maximum allowed value)
+        let ten_percent_total_alloc = lun0_alloc_units / 10;
+        self.d_lu_num_write_booster_buffer_alloc_units =
+            min(ten_percent_total_alloc, wb_max_alloc_units);
+        Ok(self.d_lu_num_write_booster_buffer_alloc_units)
+    }
+}
+
 impl CommonDescriptorTrait<'_> for UnitConfigDescriptor {}
 
 pub type UFS3ConfigDescriptor = ConfigDescriptor<DeviceConfigDescriptor, UnitConfigDescriptor>;