return ret;
 }
 
+static int init_tdmr(struct tdmr_info *tdmr)
+{
+       u64 next;
+
+       /*
+        * Initializing a TDMR can be time consuming.  To avoid long
+        * SEAMCALLs, the TDX module may only initialize a part of the
+        * TDMR in each call.
+        */
+       do {
+               struct tdx_module_args args = {
+                       .rcx = tdmr->base,
+               };
+               int ret;
+
+               ret = seamcall_prerr_ret(TDH_SYS_TDMR_INIT, &args);
+               if (ret)
+                       return ret;
+               /*
+                * RDX contains 'next-to-initialize' address if
+                * TDH.SYS.TDMR.INIT did not fully complete and
+                * should be retried.
+                */
+               next = args.rdx;
+               cond_resched();
+               /* Keep making SEAMCALLs until the TDMR is done */
+       } while (next < tdmr->base + tdmr->size);
+
+       return 0;
+}
+
+static int init_tdmrs(struct tdmr_info_list *tdmr_list)
+{
+       int i;
+
+       /*
+        * This operation is costly.  It can be parallelized,
+        * but keep it simple for now.
+        */
+       for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+               int ret;
+
+               ret = init_tdmr(tdmr_entry(tdmr_list, i));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int init_tdx_module(void)
 {
        struct tdx_tdmr_sysinfo tdmr_sysinfo;
        if (ret)
                goto err_reset_pamts;
 
-       /*
-        * TODO:
-        *
-        *  - Configure the global KeyID on all packages.
-        *  - Initialize all TDMRs.
-        *
-        *  Return error before all steps are done.
-        */
-       ret = -EINVAL;
+       /* Initialize TDMRs to complete the TDX module initialization */
+       ret = init_tdmrs(&tdx_tdmr_list);
        if (ret)
                goto err_reset_pamts;