commands.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // SPDX-License-Identifier: GPL-2.0
  2. use core::{
  3. array,
  4. convert::Infallible,
  5. ffi::FromBytesUntilNulError,
  6. str::Utf8Error, //
  7. };
  8. use kernel::{
  9. device,
  10. pci,
  11. prelude::*,
  12. time::Delta,
  13. transmute::{
  14. AsBytes,
  15. FromBytes, //
  16. }, //
  17. };
  18. use crate::{
  19. driver::Bar0,
  20. gsp::{
  21. cmdq::{
  22. Cmdq,
  23. CommandToGsp,
  24. MessageFromGsp, //
  25. },
  26. fw::{
  27. commands::*,
  28. MsgFunction, //
  29. },
  30. },
  31. sbuffer::SBufferIter,
  32. };
  33. /// The `GspSetSystemInfo` command.
  34. pub(crate) struct SetSystemInfo<'a> {
  35. pdev: &'a pci::Device<device::Bound>,
  36. }
  37. impl<'a> SetSystemInfo<'a> {
  38. /// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`.
  39. pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self {
  40. Self { pdev }
  41. }
  42. }
  43. impl<'a> CommandToGsp for SetSystemInfo<'a> {
  44. const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;
  45. type Command = GspSetSystemInfo;
  46. type InitError = Error;
  47. fn init(&self) -> impl Init<Self::Command, Self::InitError> {
  48. GspSetSystemInfo::init(self.pdev)
  49. }
  50. }
  51. struct RegistryEntry {
  52. key: &'static str,
  53. value: u32,
  54. }
  55. /// The `SetRegistry` command.
  56. pub(crate) struct SetRegistry {
  57. entries: [RegistryEntry; Self::NUM_ENTRIES],
  58. }
  59. impl SetRegistry {
  60. // For now we hard-code the registry entries. Future work will allow others to
  61. // be added as module parameters.
  62. const NUM_ENTRIES: usize = 3;
  63. /// Creates a new `SetRegistry` command, using a set of hardcoded entries.
  64. pub(crate) fn new() -> Self {
  65. Self {
  66. entries: [
  67. // RMSecBusResetEnable - enables PCI secondary bus reset
  68. RegistryEntry {
  69. key: "RMSecBusResetEnable",
  70. value: 1,
  71. },
  72. // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
  73. // any PCI reset.
  74. RegistryEntry {
  75. key: "RMForcePcieConfigSave",
  76. value: 1,
  77. },
  78. // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
  79. // in the internal product name database.
  80. RegistryEntry {
  81. key: "RMDevidCheckIgnore",
  82. value: 1,
  83. },
  84. ],
  85. }
  86. }
  87. }
  88. impl CommandToGsp for SetRegistry {
  89. const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
  90. type Command = PackedRegistryTable;
  91. type InitError = Infallible;
  92. fn init(&self) -> impl Init<Self::Command, Self::InitError> {
  93. PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)
  94. }
  95. fn variable_payload_len(&self) -> usize {
  96. let mut key_size = 0;
  97. for i in 0..Self::NUM_ENTRIES {
  98. key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
  99. }
  100. Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size
  101. }
  102. fn init_variable_payload(
  103. &self,
  104. dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
  105. ) -> Result {
  106. let string_data_start_offset =
  107. size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>();
  108. // Array for string data.
  109. let mut string_data = KVec::new();
  110. for entry in self.entries.iter().take(Self::NUM_ENTRIES) {
  111. dst.write_all(
  112. PackedRegistryEntry::new(
  113. (string_data_start_offset + string_data.len()) as u32,
  114. entry.value,
  115. )
  116. .as_bytes(),
  117. )?;
  118. let key_bytes = entry.key.as_bytes();
  119. string_data.extend_from_slice(key_bytes, GFP_KERNEL)?;
  120. string_data.push(0, GFP_KERNEL)?;
  121. }
  122. dst.write_all(string_data.as_slice())
  123. }
  124. }
  125. /// Message type for GSP initialization done notification.
  126. struct GspInitDone;
  127. // SAFETY: `GspInitDone` is a zero-sized type with no bytes, therefore it
  128. // trivially has no uninitialized bytes.
  129. unsafe impl FromBytes for GspInitDone {}
  130. impl MessageFromGsp for GspInitDone {
  131. const FUNCTION: MsgFunction = MsgFunction::GspInitDone;
  132. type InitError = Infallible;
  133. type Message = ();
  134. fn read(
  135. _msg: &Self::Message,
  136. _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
  137. ) -> Result<Self, Self::InitError> {
  138. Ok(GspInitDone)
  139. }
  140. }
  141. /// Waits for GSP initialization to complete.
  142. pub(crate) fn wait_gsp_init_done(cmdq: &mut Cmdq) -> Result {
  143. loop {
  144. match cmdq.receive_msg::<GspInitDone>(Delta::from_secs(10)) {
  145. Ok(_) => break Ok(()),
  146. Err(ERANGE) => continue,
  147. Err(e) => break Err(e),
  148. }
  149. }
  150. }
  151. /// The `GetGspStaticInfo` command.
  152. struct GetGspStaticInfo;
  153. impl CommandToGsp for GetGspStaticInfo {
  154. const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
  155. type Command = GspStaticConfigInfo;
  156. type InitError = Infallible;
  157. fn init(&self) -> impl Init<Self::Command, Self::InitError> {
  158. GspStaticConfigInfo::init_zeroed()
  159. }
  160. }
  161. /// The reply from the GSP to the [`GetGspInfo`] command.
  162. pub(crate) struct GetGspStaticInfoReply {
  163. gpu_name: [u8; 64],
  164. }
  165. impl MessageFromGsp for GetGspStaticInfoReply {
  166. const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
  167. type Message = GspStaticConfigInfo;
  168. type InitError = Infallible;
  169. fn read(
  170. msg: &Self::Message,
  171. _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
  172. ) -> Result<Self, Self::InitError> {
  173. Ok(GetGspStaticInfoReply {
  174. gpu_name: msg.gpu_name_str(),
  175. })
  176. }
  177. }
  178. /// Error type for [`GetGspStaticInfoReply::gpu_name`].
  179. #[derive(Debug)]
  180. pub(crate) enum GpuNameError {
  181. /// The GPU name string does not contain a null terminator.
  182. NoNullTerminator(FromBytesUntilNulError),
  183. /// The GPU name string contains invalid UTF-8.
  184. #[expect(dead_code)]
  185. InvalidUtf8(Utf8Error),
  186. }
  187. impl GetGspStaticInfoReply {
  188. /// Returns the name of the GPU as a string.
  189. ///
  190. /// Returns an error if the string given by the GSP does not contain a null terminator or
  191. /// contains invalid UTF-8.
  192. pub(crate) fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
  193. CStr::from_bytes_until_nul(&self.gpu_name)
  194. .map_err(GpuNameError::NoNullTerminator)?
  195. .to_str()
  196. .map_err(GpuNameError::InvalidUtf8)
  197. }
  198. }
  199. /// Send the [`GetGspInfo`] command and awaits for its reply.
  200. pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GetGspStaticInfoReply> {
  201. cmdq.send_command(bar, GetGspStaticInfo)?;
  202. loop {
  203. match cmdq.receive_msg::<GetGspStaticInfoReply>(Delta::from_secs(5)) {
  204. Ok(info) => return Ok(info),
  205. Err(ERANGE) => continue,
  206. Err(e) => return Err(e),
  207. }
  208. }
  209. }