diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index aea04365bc69..f3a89301e3ab 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -174,6 +174,7 @@ my %nosymbol_table = ();
 my $declaration_start_line;
 my ($type, $declaration_name, $return_type);
 my ($newsection, $newcontents, $prototype, $brcount, %source_map);
+my %asmprototypes;
 
 if (defined($ENV{'KBUILD_VERBOSE'})) {
 	$verbose = "$ENV{'KBUILD_VERBOSE'}";
@@ -248,7 +249,7 @@ my $doc_decl = $doc_com . '(\w+)';
 # while trying to not match literal block starts like "example::"
 #
 my $doc_sect = $doc_com .
-    '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$';
+    '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|prototype|notes?|examples?)\s*:([^:].*)?$';
 my $doc_content = $doc_com_body . '(.*)';
 my $doc_block = $doc_com . 'DOC:\s*(.*)?';
 my $doc_inline_start = '^\s*/\*\*\s*$';
@@ -277,6 +278,7 @@ my $section_intro = "Introduction";
 my $section = $section_default;
 my $section_context = "Context";
 my $section_return = "Return";
+my $section_asmprototype = "Prototype";
 
 my $undescribed = "-- undescribed --";
 
@@ -468,6 +470,13 @@ sub dump_section {
             $new_start_line = 0;
 	}
     }
+
+    if ($name eq $section_asmprototype) {
+        # extract the function name for future matching to SYM_FUNC_START.*(name)
+        # since that doesn't include arguments like a C function call
+        my ($func) = ($contents =~ /^.*\s+(\S+)\(/);
+	$asmprototypes{$func} = $contents;
+    }
 }
 
 ##
@@ -1848,9 +1857,31 @@ sub syscall_munge() {
 sub process_proto_function($$) {
     my $x = shift;
     my $file = shift;
+    my $funcname;
 
     $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
 
+    # support asm functions declared with one of these starting in
+    # the first column:
+    #     SYM_FUNC_START(name)
+    #     SYM_FUNC_START_LOCAL(name)
+    #     SYM_FUNC_START_WEAK(name)
+    # or for nested macros:
+    #     SOMESTRING<whitespace>name
+    if ($file =~ /\.S$/) {
+        if ($x =~ /^SYM_FUNC_START/) {
+	    ($funcname) = ($x =~ /^SYM_FUNC_START.*\((.*)\)/);
+        } elsif ($x =~ /^[A-Za-z0-9_]+\s+[A-Za-z0-9_]+/) {
+	    ($funcname) = ($x =~ /^[A-Za-z0-9_]+\s+([A-Za-z0-9_]+)/);
+        }
+    }
+    if (defined $funcname) {
+	$prototype = $asmprototypes{$funcname};
+	dump_function($asmprototypes{$funcname}, $file);
+	reset_state();
+	return;
+    }
+
     if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) {
 	# do nothing
     }
@@ -2085,6 +2116,8 @@ sub process_body($$) {
 	    $newsection = $section_default;
 	} elsif ($newsection =~ m/^context$/i) {
 	    $newsection = $section_context;
+	} elsif ($newsection =~ m/^prototype$/i) {
+	    $newsection = $section_asmprototype;
 	} elsif ($newsection =~ m/^returns?$/i) {
 	    $newsection = $section_return;
 	} elsif ($newsection =~ m/^\@return$/) {
@@ -2135,6 +2168,16 @@ sub process_body($$) {
 		$contents = "";
 		$new_start_line = $.;
 		$state = STATE_BODY;
+	    } elsif ($section eq $section_asmprototype) {
+		my ($protoline) = /Prototype:\s+(.+)$/;
+		my ($funcname) = $protoline =~ /Prototype\.*\s+(\S+)\(/;
+
+		$asmprototypes{$funcname} = $protoline;
+		dump_section($file, $section, $contents);
+		$section = $section_default;
+		$contents = "";
+		$new_start_line = $.;
+		$state = STATE_BODY;
 	    } else {
 		if ($section ne $section_default) {
 		    $state = STATE_BODY_WITH_BLANK_LINE;
@@ -2150,7 +2193,7 @@ sub process_body($$) {
 	    $declaration_purpose =~ s/\s+/ /g;
 	} else {
 	    my $cont = $1;
-	    if ($section =~ m/^@/ || $section eq $section_context) {
+	    if ($section =~ m/^@/ || $section eq $section_context || $section eq $section_asmprototype) {
 		if (!defined $leading_space) {
 		    if ($cont =~ m/^(\s+)/) {
 			$leading_space = $1;
@@ -2286,6 +2329,7 @@ sub process_file($) {
 	}
 	# Replace tabs by spaces
         while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {};
+
 	# Hand this line to the appropriate state handler
 	if ($state == STATE_NORMAL) {
 	    process_normal();
