mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	dt: Add a check for undocumented compatible strings in kernel
Add a make target, dt_compatible_check, to extract compatible strings from kernel sources and check if they are documented by a schema. At least version v2022.08 of dtschema with dt-check-compatible is required. This check can also be run manually on specific files or directories: scripts/dtc/dt-extract-compatibles drivers/clk/ | \ xargs dt-check-compatible -v -s Documentation/devicetree/bindings/processed-schema.json Currently, there are about 3800 undocumented compatible strings. Most of these are cases where the binding is not yet converted (given there are 1900 .txt binding files remaining). Link: https://lore.kernel.org/all/20220916012510.2718170-1-robh@kernel.org/ Signed-off-by: Rob Herring <robh@kernel.org>
This commit is contained in:
		
							parent
							
								
									d7c6ea024c
								
							
						
					
					
						commit
						b6acf80735
					
				
					 3 changed files with 76 additions and 0 deletions
				
			
		|  | @ -75,3 +75,6 @@ always-$(CHECK_DT_BINDING) += $(patsubst $(srctree)/$(src)/%.yaml,%.example.dtb, | |||
| # build artifacts here before they are processed by scripts/Makefile.clean
 | ||||
| clean-files = $(shell find $(obj) \( -name '*.example.dts' -o \
 | ||||
| 			-name '*.example.dtb' \) -delete 2>/dev/null) | ||||
| 
 | ||||
| dt_compatible_check: $(obj)/processed-schema.json | ||||
| 	$(Q)$(srctree)/scripts/dtc/dt-extract-compatibles $(srctree) | xargs dt-check-compatible -v -s $< | ||||
|  |  | |||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							|  | @ -1419,6 +1419,10 @@ PHONY += dt_binding_check | |||
| dt_binding_check: scripts_dtc | ||||
| 	$(Q)$(MAKE) $(build)=Documentation/devicetree/bindings | ||||
| 
 | ||||
| PHONY += dt_compatible_check | ||||
| dt_compatible_check: dt_binding_check | ||||
| 	$(Q)$(MAKE) $(build)=Documentation/devicetree/bindings $@ | ||||
| 
 | ||||
| # ---------------------------------------------------------------------------
 | ||||
| # Modules
 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										69
									
								
								scripts/dtc/dt-extract-compatibles
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								scripts/dtc/dt-extract-compatibles
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| #!/usr/bin/env python3 | ||||
| # SPDX-License-Identifier: GPL-2.0-only | ||||
| 
 | ||||
| import os | ||||
| import glob | ||||
| import re | ||||
| import argparse | ||||
| 
 | ||||
| 
 | ||||
| def parse_of_declare_macros(data): | ||||
| 	""" Find all compatible strings in OF_DECLARE() style macros """ | ||||
| 	compat_list = [] | ||||
| 	# CPU_METHOD_OF_DECLARE does not have a compatible string | ||||
| 	for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data): | ||||
| 		try: | ||||
| 			compat = re.search(r'"(.*?)"', m[0])[1] | ||||
| 		except: | ||||
| 			# Fails on compatible strings in #define, so just skip | ||||
| 			continue | ||||
| 		compat_list += [compat] | ||||
| 
 | ||||
| 	return compat_list | ||||
| 
 | ||||
| 
 | ||||
| def parse_of_device_id(data): | ||||
| 	""" Find all compatible strings in of_device_id structs """ | ||||
| 	compat_list = [] | ||||
| 	for m in re.finditer(r'of_device_id\s+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data): | ||||
| 		compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1]) | ||||
| 
 | ||||
| 	return compat_list | ||||
| 
 | ||||
| 
 | ||||
| def parse_compatibles(file): | ||||
| 	with open(file, 'r', encoding='utf-8') as f: | ||||
| 		data = f.read().replace('\n', '') | ||||
| 
 | ||||
| 	compat_list = parse_of_declare_macros(data) | ||||
| 	compat_list += parse_of_device_id(data) | ||||
| 
 | ||||
| 	return compat_list | ||||
| 
 | ||||
| def print_compat(filename, compatibles): | ||||
| 	if not compatibles: | ||||
| 		return | ||||
| 	if show_filename: | ||||
| 		compat_str = ' '.join(compatibles) | ||||
| 		print(filename + ": compatible(s): " + compat_str) | ||||
| 	else: | ||||
| 		print(*compatibles, sep='\n') | ||||
| 
 | ||||
| show_filename = False | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
| 	ap = argparse.ArgumentParser() | ||||
| 	ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") | ||||
| 	ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") | ||||
| 	args = ap.parse_args() | ||||
| 
 | ||||
| 	show_filename = args.with_filename | ||||
| 
 | ||||
| 	for f in args.cfile: | ||||
| 		if os.path.isdir(f): | ||||
| 			for filename in glob.iglob(f + "/**/*.c", recursive=True): | ||||
| 				compat_list = parse_compatibles(filename) | ||||
| 				print_compat(filename, compat_list) | ||||
| 		else: | ||||
| 			compat_list = parse_compatibles(f) | ||||
| 			print_compat(f, compat_list) | ||||
		Loading…
	
		Reference in a new issue
	
	 Rob Herring
						Rob Herring