diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp
index 9f104ce801dc4e3b33e10f9f29a7b683dcef73af..54614bc25efd4916a2eb7f3fdbfecb506d916df0 100644
--- a/Marlin/src/gcode/queue.cpp
+++ b/Marlin/src/gcode/queue.cpp
@@ -361,19 +361,25 @@ inline void get_serial_commands() {
           || ((sd_char == '#' || sd_char == ':') && !sd_comment_mode)
       ) {
         if (card_eof) {
-          SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
+
           card.printingHasFinished();
-          #if ENABLED(PRINTER_EVENT_LEDS)
-            LCD_MESSAGEPGM(MSG_INFO_COMPLETED_PRINTS);
-            set_led_color(0, 255, 0); // Green
-            #if HAS_RESUME_CONTINUE
-              enqueue_and_echo_commands_P(PSTR("M0")); // end of the queue!
-            #else
-              safe_delay(1000);
+
+          if (card.sdprinting)
+            sd_count = 0; // If a sub-file was printing, continue from call point
+          else {
+            SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
+            #if ENABLED(PRINTER_EVENT_LEDS)
+              LCD_MESSAGEPGM(MSG_INFO_COMPLETED_PRINTS);
+              set_led_color(0, 255, 0); // Green
+              #if HAS_RESUME_CONTINUE
+                enqueue_and_echo_commands_P(PSTR("M0")); // end of the queue!
+              #else
+                safe_delay(1000);
+              #endif
+              set_led_color(0, 0, 0);   // OFF
             #endif
-            set_led_color(0, 0, 0);   // OFF
-          #endif
-          card.checkautostart(true);
+            card.checkautostart(true);
+          }
         }
         else if (n == -1) {
           SERIAL_ERROR_START();
diff --git a/Marlin/src/gcode/sdcard/M20-M30_M32-M34_M928.cpp b/Marlin/src/gcode/sdcard/M20-M30_M32-M34_M928.cpp
index 001783585fea8748ba4b719e92fd7f5e2e69cdb6..566a8801036f3643d233b7c27abd3d88ee871746 100644
--- a/Marlin/src/gcode/sdcard/M20-M30_M32-M34_M928.cpp
+++ b/Marlin/src/gcode/sdcard/M20-M30_M32-M34_M928.cpp
@@ -124,19 +124,23 @@ void GcodeSuite::M30() {
 
 /**
  * M32: Select file and start SD Print
+ *
+ * Examples:
+ *
+ *    M32 !PATH/TO/FILE.GCO#      ; Start FILE.GCO
+ *    M32 P !PATH/TO/FILE.GCO#    ; Start FILE.GCO as a procedure
+ *    M32 S60 !PATH/TO/FILE.GCO#  ; Start FILE.GCO at byte 60
+ *
  */
 void GcodeSuite::M32() {
-  if (IS_SD_PRINTING)
-    stepper.synchronize();
-
-  char* namestartpos = parser.string_arg;
-  const bool call_procedure = parser.boolval('P');
+  if (card.sdprinting) stepper.synchronize();
 
   if (card.cardOK) {
-    card.openFile(namestartpos, true, call_procedure);
+    const bool call_procedure = parser.boolval('P');
+
+    card.openFile(parser.string_arg, true, call_procedure);
 
-    if (parser.seenval('S'))
-      card.setIndex(parser.value_long());
+    if (parser.seenval('S')) card.setIndex(parser.value_long());
 
     card.startFileprint();
 
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
index b68911d0c011b49c88072903b49ff72d5e98a206..663b788321fdd1fff7781d0e0b8fe02987843feb 100644
--- a/Marlin/src/sd/cardreader.cpp
+++ b/Marlin/src/sd/cardreader.cpp
@@ -310,26 +310,33 @@ void CardReader::openLogFile(char* name) {
   openFile(name, false);
 }
 
+void appendAtom(SdFile &file, char *& dst, uint8_t &cnt) {
+  file.getFilename(dst);
+  while (*dst && cnt < MAXPATHNAMELENGTH) { dst++; cnt++; }
+  if (cnt < MAXPATHNAMELENGTH) { *dst = '/'; dst++; cnt++; }
+}
+
 void CardReader::getAbsFilename(char *t) {
-  uint8_t cnt = 0;
-  *t = '/'; t++; cnt++;
-  for (uint8_t i = 0; i < workDirDepth; i++) {
-    workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
-    while (*t && cnt < MAXPATHNAMELENGTH) { t++; cnt++; } //crawl counter forward.
+  *t++ = '/';                                               // Root folder
+  uint8_t cnt = 1;
+
+  for (uint8_t i = 0; i < workDirDepth; i++)                // Loop to current work dir
+    appendAtom(workDirParents[i], t, cnt);
+
+  if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH)) {
+    appendAtom(file, t, cnt);
+    --t;
   }
-  if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH))
-    file.getFilename(t);
-  else
-    t[0] = 0;
+  *t = '\0';
 }
 
-void CardReader::openFile(char* name, bool read, bool push_current/*=false*/) {
+void CardReader::openFile(char* name, const bool read, const bool subcall/*=false*/) {
 
   if (!cardOK) return;
 
   uint8_t doing = 0;
-  if (isFileOpen()) { //replacing current file by new file, or subfile call
-    if (push_current) {
+  if (isFileOpen()) {                     // Replacing current file or doing a subroutine
+    if (subcall) {
       if (file_subcall_ctr > SD_PROCEDURE_DEPTH - 1) {
         SERIAL_ERROR_START();
         SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
@@ -338,20 +345,24 @@ void CardReader::openFile(char* name, bool read, bool push_current/*=false*/) {
         return;
       }
 
-      // Store current filename and position
+      // Store current filename (based on workDirParents) and position
       getAbsFilename(proc_filenames[file_subcall_ctr]);
+      filespos[file_subcall_ctr] = sdpos;
 
       SERIAL_ECHO_START();
       SERIAL_ECHOPAIR("SUBROUTINE CALL target:\"", name);
       SERIAL_ECHOPAIR("\" parent:\"", proc_filenames[file_subcall_ctr]);
       SERIAL_ECHOLNPAIR("\" pos", sdpos);
-      filespos[file_subcall_ctr] = sdpos;
       file_subcall_ctr++;
     }
     else
       doing = 1;
   }
-  else { // Opening fresh file
+  else if (subcall) {     // Returning from a subcall?
+    SERIAL_ECHO_START();
+    SERIAL_ECHOLNPGM("END SUBROUTINE");
+  }
+  else {                  // Opening fresh file
     doing = 2;
     file_subcall_ctr = 0; // Reset procedure depth in case user cancels print while in procedure
   }
@@ -600,20 +611,20 @@ uint16_t CardReader::getnrfilenames() {
 }
 
 void CardReader::chdir(const char * relpath) {
-  SdFile newfile;
+  SdFile newDir;
   SdFile *parent = &root;
 
   if (workDir.isOpen()) parent = &workDir;
 
-  if (!newfile.open(*parent, relpath, O_READ)) {
+  if (!newDir.open(*parent, relpath, O_READ)) {
     SERIAL_ECHO_START();
     SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
     SERIAL_ECHOLN(relpath);
   }
   else {
+    workDir = newDir;
     if (workDirDepth < MAX_DIR_DEPTH)
-      workDirParents[workDirDepth++] = *parent;
-    workDir = newfile;
+      workDirParents[workDirDepth++] = workDir;
     #if ENABLED(SDCARD_SORT_ALPHA)
       presort();
     #endif
@@ -621,8 +632,8 @@ void CardReader::chdir(const char * relpath) {
 }
 
 void CardReader::updir() {
-  if (workDirDepth > 0) {
-    workDir = workDirParents[--workDirDepth];
+  if (workDirDepth > 0) {                                           // At least 1 dir has been saved
+    workDir = --workDirDepth ? workDirParents[workDirDepth] : root; // Use parent, or root if none
     #if ENABLED(SDCARD_SORT_ALPHA)
       presort();
     #endif
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index 1a9a6c1115bdd3e67d093d8fbd0e8f8fa1afe8ab..5d10e34a68ab9228f78c1fea0d373a0f57267dfa 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -41,7 +41,7 @@ public:
   // device is available soon after a reset.
 
   void checkautostart(bool x);
-  void openFile(char* name, bool read, bool push_current=false);
+  void openFile(char* name, const bool read, const bool subcall=false);
   void openLogFile(char* name);
   void removeFile(const char * const name);
   void closefile(bool store_location=false);