diff options
author | Dave Airlie <airlied@redhat.com> | 2016-06-16 05:49:32 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-06-16 05:49:32 +1000 |
commit | a0877f52035280370707bdefeddc6faa6478b892 (patch) | |
tree | 165757a83f5283aab0d1b12b404d84d6a5055ae3 | |
parent | 27287abb442999810eb15cd3ea35a790dd3f9c63 (diff) | |
parent | 7deef7f1ae5d0bf98c1ec9eb4bc87b29478c2adb (diff) | |
download | op-kernel-dev-a0877f52035280370707bdefeddc6faa6478b892.zip op-kernel-dev-a0877f52035280370707bdefeddc6faa6478b892.tar.gz |
Merge tag 'topic/drm-misc-2016-06-15' of git://anongit.freedesktop.org/drm-intel into drm-next
- best_encoder cleanup from Boris.
- drm_simple_display_pipe helpers from Noralf. Looks really neat imo, and
there's 2-3 in-flight drivers which look like they could/should use it.
Anyway, with this we have now helpers and everything in place to write
drivers for simple hw with fewer complexity in the driver than what
fbdev would need. That was the last complaint I've heard from embedded
folks after we made atomic happen. Mission accomplished!
- nonblocking commit helpers for atomic, plus a bunch of driver patches
for that.
- Prep patch from Laurent for cleaned up pixel format functions.
- More of Gustavo's cleanup for drm vblank functions.
- and a few oddball things in between
Plus the merge of docs-next to prep the docbook->sphinx conversion as
discussed. Jon cc'ed as fyi.
* tag 'topic/drm-misc-2016-06-15' of git://anongit.freedesktop.org/drm-intel: (108 commits)
drm/atomic-helpers: Clear up cleanup_done a bit
drm/atomic-helpers: Stall on the right commit
drm/vmwgfx: use *_32_bits() macros
drm/virtio: Don't reinvent a flipping wheel
drm/i915: Fix missing unlock on error in i915_ppgtt_info()
drm/gma500: use drm_crtc_vblank_{on,off}()
drm/radeon: use crtc directly in drm_crtc_vblank_put()
drm/amdgpu: use crtc directly in drm_crtc_vblank_put()
drm/radeon: use drm_crtc_vblank_{on,off}()
drm/amdgpu: use drm_crtc_vblank_{on,off}()
drm: make drm_vblank_{get,put}() static
drm: remove legacy drm_arm_vblank_event()
drm: remove legacy drm_send_vblank_event()
drm/nouveau: replace legacy vblank helpers
drm/prime: fix error path deadlock fail
drm/dsi: Add uevent callback
drm: fb: cma: fix memory leak
drm: i915: Rely on the default ->best_encoder() behavior where appropriate
drm: Add helper for simple display pipeline
drm/bridge: dw-hdmi: Use drm_atomic_helper_best_encoder()
...
125 files changed, 2935 insertions, 1640 deletions
diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 0000000..53752db --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1 @@ +output diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index d70f9b6..e0c7e1e 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -33,10 +33,6 @@ PDF_METHOD = $(prefer-db2x) PS_METHOD = $(prefer-db2x) -### -# The targets that may be used. -PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs - targets += $(DOCBOOKS) BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) xmldocs: $(BOOKS) @@ -63,6 +59,9 @@ installmandocs: mandocs sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \ xargs install -m 644 -t /usr/local/man/man9/ +# no-op for the DocBook toolchain +epubdocs: + ### #External programs used KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl index dac18b4..d09536c 100644 --- a/Documentation/DocBook/gpu.tmpl +++ b/Documentation/DocBook/gpu.tmpl @@ -1018,6 +1018,11 @@ int max_width, max_height;</synopsis> </para> </sect2> <sect2> + <title>DRM Format Handling</title> +!Iinclude/drm/drm_fourcc.h +!Edrivers/gpu/drm/drm_fourcc.c + </sect2> + <sect2> <title>Dumb Buffer Objects</title> <para> The KMS API doesn't standardize backing storage object creation and @@ -1683,6 +1688,12 @@ void intel_crt_init(struct drm_device *dev) !Edrivers/gpu/drm/drm_panel.c !Pdrivers/gpu/drm/drm_panel.c drm panel </sect2> + <sect2> + <title>Simple KMS Helper Reference</title> +!Iinclude/drm/drm_simple_kms_helper.h +!Edrivers/gpu/drm/drm_simple_kms_helper.c +!Pdrivers/gpu/drm/drm_simple_kms_helper.c overview + </sect2> </sect1> <!-- Internals: kms properties --> diff --git a/Documentation/Makefile.sphinx b/Documentation/Makefile.sphinx new file mode 100644 index 0000000..addf323 --- /dev/null +++ b/Documentation/Makefile.sphinx @@ -0,0 +1,63 @@ +# -*- makefile -*- +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXBUILD = sphinx-build +SPHINXOPTS = +PAPER = +BUILDDIR = $(obj)/output + +# User-friendly check for sphinx-build +HAVE_SPHINX := $(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi) + +ifeq ($(HAVE_SPHINX),0) + +.DEFAULT: + $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.) + @echo " SKIP Sphinx $@ target." + +else # HAVE_SPHINX + +# User-friendly check for rst2pdf +HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi) + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +KERNELDOC = $(srctree)/scripts/kernel-doc +KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC) +ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src) +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +quiet_cmd_sphinx = SPHINX $@ + cmd_sphinx = $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2 + +htmldocs: + $(call cmd,sphinx,html) + +pdfdocs: +ifeq ($(HAVE_RST2PDF),0) + $(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.) + @echo " SKIP Sphinx $@ target." +else # HAVE_RST2PDF + $(call cmd,sphinx,pdf) +endif # HAVE_RST2PDF + +epubdocs: + $(call cmd,sphinx,epub) + +xmldocs: + $(call cmd,sphinx,xml) + +# no-ops for the Sphinx toolchain +sgmldocs: +psdocs: +mandocs: +installmandocs: + +cleandocs: + $(Q)rm -rf $(BUILDDIR) + +endif # HAVE_SPHINX diff --git a/Documentation/conf.py b/Documentation/conf.py new file mode 100644 index 0000000..6cc41a0 --- /dev/null +++ b/Documentation/conf.py @@ -0,0 +1,414 @@ +# -*- coding: utf-8 -*- +# +# The Linux Kernel documentation build configuration file, created by +# sphinx-quickstart on Fri Feb 12 13:51:46 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('sphinx')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['kernel-doc'] + +# Gracefully handle missing rst2pdf. +try: + import rst2pdf + extensions += ['rst2pdf.pdfbuilder'] +except ImportError: + pass + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'The Linux Kernel' +copyright = '2016, The kernel development community' +author = 'The kernel development community' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# In a normal build, version and release are are set to KERNELVERSION and +# KERNELRELEASE, respectively, from the Makefile via Sphinx command line +# arguments. +# +# The following code tries to extract the information by reading the Makefile, +# when Sphinx is run directly (e.g. by Read the Docs). +try: + makefile_version = None + makefile_patchlevel = None + for line in open('../Makefile'): + key, val = [x.strip() for x in line.split('=', 2)] + if key == 'VERSION': + makefile_version = val + elif key == 'PATCHLEVEL': + makefile_patchlevel = val + if makefile_version and makefile_patchlevel: + break +except: + pass +finally: + if makefile_version and makefile_patchlevel: + version = release = makefile_version + '.' + makefile_patchlevel + else: + sys.stderr.write('Warning: Could not extract kernel version\n') + version = release = "unknown version" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['output'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +primary_domain = 'C' +highlight_language = 'C' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +# The Read the Docs theme is available from +# - https://github.com/snide/sphinx_rtd_theme +# - https://pypi.python.org/pypi/sphinx_rtd_theme +# - python-sphinx-rtd-theme package (on Debian) +try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +except ImportError: + sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n') + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'TheLinuxKerneldoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation', + 'The kernel development community', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'thelinuxkernel', 'The Linux Kernel Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'TheLinuxKernel', 'The Linux Kernel Documentation', + author, 'TheLinuxKernel', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + +#======= +# rst2pdf +# +# Grouping the document tree into PDF files. List of tuples +# (source start file, target name, title, author, options). +# +# See the Sphinx chapter of http://ralsina.me/static/manual.pdf +# +# FIXME: Do not add the index file here; the result will be too big. Adding +# multiple PDF files here actually tries to get the cross-referencing right +# *between* PDF files. +pdf_documents = [ + ('index', u'Kernel', u'Kernel', u'J. Random Bozo'), +] + +# kernel-doc extension configuration for running Sphinx directly (e.g. by Read +# the Docs). In a normal build, these are supplied from the Makefile via command +# line arguments. +kerneldoc_bin = '../scripts/kernel-doc' +kerneldoc_srctree = '..' diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt index 122b7f4..91ce82d 100644 --- a/Documentation/dmaengine/provider.txt +++ b/Documentation/dmaengine/provider.txt @@ -323,7 +323,7 @@ supported. * device_resume - Resumes a transfer on the channel - This command should operate synchronously on the channel, - pausing right away the work of the given channel + resuming right away the work of the given channel * device_terminate_all - Aborts all the pending and ongoing transfers on the channel diff --git a/Documentation/index.rst b/Documentation/index.rst new file mode 100644 index 0000000..71a276f --- /dev/null +++ b/Documentation/index.rst @@ -0,0 +1,23 @@ +.. The Linux Kernel documentation master file, created by + sphinx-quickstart on Fri Feb 12 13:51:46 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to The Linux Kernel's documentation! +============================================ + +Nothing for you to see here *yet*. Please move along. + +Contents: + +.. toctree:: + :maxdepth: 2 + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c9..a2a662d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3992,8 +3992,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. trace_event=[event-list] [FTRACE] Set and start specified trace events in order - to facilitate early boot debugging. - See also Documentation/trace/events.txt + to facilitate early boot debugging. The event-list is a + comma separated list of trace events to enable. See + also Documentation/trace/events.txt trace_options=[option-list] [FTRACE] Enable or disable tracer options at boot. diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c index 30fb842..49db1de 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/Documentation/mic/mpssd/mpssd.c @@ -1538,9 +1538,9 @@ set_cmdline(struct mic_info *mic) len = snprintf(buffer, PATH_MAX, "clocksource=tsc highres=off nohz=off "); - len += snprintf(buffer + len, PATH_MAX, + len += snprintf(buffer + len, PATH_MAX - len, "cpufreq_on;corec6_off;pc3_off;pc6_off "); - len += snprintf(buffer + len, PATH_MAX, + len += snprintf(buffer + len, PATH_MAX - len, "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0", mic->id + 1); diff --git a/Documentation/security/self-protection.txt b/Documentation/security/self-protection.txt index babd637..3010576 100644 --- a/Documentation/security/self-protection.txt +++ b/Documentation/security/self-protection.txt @@ -183,8 +183,9 @@ provide meaningful defenses. ### Canaries, blinding, and other secrets It should be noted that things like the stack canary discussed earlier -are technically statistical defenses, since they rely on a (leakable) -secret value. +are technically statistical defenses, since they rely on a secret value, +and such values may become discoverable through an information exposure +flaw. Blinding literal values for things like JITs, where the executable contents may be partially under the control of userspace, need a similar @@ -199,8 +200,8 @@ working?) in order to maximize their success. Since the location of kernel memory is almost always instrumental in mounting a successful attack, making the location non-deterministic raises the difficulty of an exploit. (Note that this in turn makes -the value of leaks higher, since they may be used to discover desired -memory locations.) +the value of information exposures higher, since they may be used to +discover desired memory locations.) #### Text and module base @@ -222,14 +223,21 @@ become more difficult to locate. Much of the kernel's dynamic memory (e.g. kmalloc, vmalloc, etc) ends up being relatively deterministic in layout due to the order of early-boot initializations. If the base address of these areas is not the same -between boots, targeting them is frustrated, requiring a leak specific -to the region. +between boots, targeting them is frustrated, requiring an information +exposure specific to the region. + +#### Structure layout + +By performing a per-build randomization of the layout of sensitive +structures, attacks must either be tuned to known kernel builds or expose +enough kernel memory to determine structure layouts before manipulating +them. -## Preventing Leaks +## Preventing Information Exposures Since the locations of sensitive structures are the primary target for -attacks, it is important to defend against leaks of both kernel memory +attacks, it is important to defend against exposure of both kernel memory addresses and kernel memory contents (since they may contain kernel addresses or other sensitive things like canary values). @@ -250,8 +258,8 @@ sure structure holes are cleared. When releasing memory, it is best to poison the contents (clear stack on syscall return, wipe heap memory on a free), to avoid reuse attacks that rely on the old contents of memory. This frustrates many uninitialized -variable attacks, stack info leaks, heap info leaks, and use-after-free -attacks. +variable attacks, stack content exposures, heap content exposures, and +use-after-free attacks. ### Destination tracking diff --git a/Documentation/sphinx/convert_template.sed b/Documentation/sphinx/convert_template.sed new file mode 100644 index 0000000..c1503fc --- /dev/null +++ b/Documentation/sphinx/convert_template.sed @@ -0,0 +1,18 @@ +# +# Pandoc doesn't grok <function> or <structname>, so convert them +# ahead of time. +# +# Use the following escapes to pass through pandoc: +# $bq = "`" +# $lt = "<" +# $gt = ">" +# +s%<function>\([^<(]\+\)()</function>%:c:func:$bq\1()$bq%g +s%<function>\([^<(]\+\)</function>%:c:func:$bq\1()$bq%g +s%<structname>struct *\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +s%struct <structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +s%<structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +# +# Wrap docproc directives in para and code blocks. +# +s%^\(!.*\)$%<para><code>DOCPROC: \1</code></para>% diff --git a/Documentation/sphinx/kernel-doc.py b/Documentation/sphinx/kernel-doc.py new file mode 100644 index 0000000..4adfb0e --- /dev/null +++ b/Documentation/sphinx/kernel-doc.py @@ -0,0 +1,127 @@ +# coding=utf-8 +# +# Copyright © 2016 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Jani Nikula <jani.nikula@intel.com> +# +# Please make sure this works on both python2 and python3. +# + +import os +import subprocess +import sys +import re + +from docutils import nodes, statemachine +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives +from sphinx.util.compat import Directive + +class KernelDocDirective(Directive): + """Extract kernel-doc comments from the specified file""" + required_argument = 1 + optional_arguments = 4 + option_spec = { + 'doc': directives.unchanged_required, + 'functions': directives.unchanged_required, + 'export': directives.flag, + 'internal': directives.flag, + } + has_content = False + + def run(self): + env = self.state.document.settings.env + cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] + + filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] + + # Tell sphinx of the dependency + env.note_dependency(os.path.abspath(filename)) + + tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) + source = filename + + # FIXME: make this nicer and more robust against errors + if 'export' in self.options: + cmd += ['-export'] + elif 'internal' in self.options: + cmd += ['-internal'] + elif 'doc' in self.options: + cmd += ['-function', str(self.options.get('doc'))] + elif 'functions' in self.options: + for f in str(self.options.get('functions')).split(' '): + cmd += ['-function', f] + + cmd += [filename] + + try: + env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd))) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + out, err = p.communicate() + + # python2 needs conversion to unicode. + # python3 with universal_newlines=True returns strings. + if sys.version_info.major < 3: + out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8') + + if p.returncode != 0: + sys.stderr.write(err) + + env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + elif env.config.kerneldoc_verbosity > 0: + sys.stderr.write(err) + + lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) + result = ViewList() + + lineoffset = 0; + line_regex = re.compile("^#define LINENO ([0-9]+)$") + for line in lines: + match = line_regex.search(line) + if match: + # sphinx counts lines from 0 + lineoffset = int(match.group(1)) - 1 + # we must eat our comments since the upset the markup + else: + result.append(line, source, lineoffset) + lineoffset += 1 + + node = nodes.section() + node.document = self.state.document + self.state.nested_parse(result, self.content_offset, node) + + return node.children + + except Exception as e: + env.app.warn('kernel-doc \'%s\' processing failed with: %s' % + (" ".join(cmd), str(e))) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + +def setup(app): + app.add_config_value('kerneldoc_bin', None, 'env') + app.add_config_value('kerneldoc_srctree', None, 'env') + app.add_config_value('kerneldoc_verbosity', 1, 'env') + + app.add_directive('kernel-doc', KernelDocDirective) diff --git a/Documentation/sphinx/post_convert.sed b/Documentation/sphinx/post_convert.sed new file mode 100644 index 0000000..392770b --- /dev/null +++ b/Documentation/sphinx/post_convert.sed @@ -0,0 +1,23 @@ +# +# Unescape. +# +s/$bq/`/g +s/$lt/</g +s/$gt/>/g +# +# pandoc thinks that both "_" needs to be escaped. Remove the extra +# backslashes. +# +s/\\_/_/g +# +# Unwrap docproc directives. +# +s/^``DOCPROC: !E\(.*\)``$/.. kernel-doc:: \1\n :export:/ +s/^``DOCPROC: !I\(.*\)``$/.. kernel-doc:: \1\n :internal:/ +s/^``DOCPROC: !F\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :functions: \2/ +s/^``DOCPROC: !P\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :doc: \2/ +s/^``DOCPROC: \(!.*\)``$/.. WARNING: DOCPROC directive not supported: \1/ +# +# Trim trailing whitespace. +# +s/[[:space:]]*$// diff --git a/Documentation/sphinx/tmplcvt b/Documentation/sphinx/tmplcvt new file mode 100755 index 0000000..909a730 --- /dev/null +++ b/Documentation/sphinx/tmplcvt @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Convert a template file into something like RST +# +# fix <function> +# feed to pandoc +# fix \_ +# title line? +# + +in=$1 +rst=$2 +tmp=$rst.tmp + +cp $in $tmp +sed --in-place -f convert_template.sed $tmp +pandoc -s -S -f docbook -t rst -o $rst $tmp +sed --in-place -f post_convert.sed $rst +rm $tmp diff --git a/Documentation/sync_file.txt b/Documentation/sync_file.txt index eaf8297..e8e2eba 100644 --- a/Documentation/sync_file.txt +++ b/Documentation/sync_file.txt @@ -6,8 +6,8 @@ This document serves as a guide for device drivers writers on what the sync_file API is, and how drivers can support it. Sync file is the carrier of -the fences(struct fence) that needs to synchronized between drivers or across -process boundaries. +the fences(struct fence) that are needed to synchronize between drivers or +across process boundaries. The sync_file API is meant to be used to send and receive fence information to/from userspace. It enables userspace to do explicit fencing, where instead @@ -32,7 +32,7 @@ in-fences and out-fences Sync files can go either to or from userspace. When a sync_file is sent from the driver to userspace we call the fences it contains 'out-fences'. They are related to a buffer that the driver is processing or is going to process, so -the driver an create out-fence to be able to notify, through fence_signal(), +the driver creates an out-fence to be able to notify, through fence_signal(), when it has finished using (or processing) that buffer. Out-fences are fences that the driver creates. diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle index 654afd7..bbb9d6a 100644 --- a/Documentation/zh_CN/CodingStyle +++ b/Documentation/zh_CN/CodingStyle @@ -24,34 +24,33 @@ Documentation/CodingStyleç„ä¸æ–‡ç¿»è¯‘ Linuxå†…æ ¸ä»£ç é£æ ¼ -这是一个简çŸç„文档,æ述了linuxå†…æ ¸ç„首选代ç é£æ ¼ă€‚代ç é£æ ¼æ˜¯å› 人而异ç„,而且我 -ä¸æ„¿æ„æ我ç„观点强å 给任何人,ä¸è¿‡è¿™é‡Œæ‰€è®²è¿°ç„是我必须è¦ç»´æ¤ç„代ç 所éµå®ˆç„é£æ ¼ï¼Œ -并且我也希望ç»å¤§å¤æ•°å…¶ä»–代ç 也能éµå®ˆè¿™ä¸ªé£æ ¼ă€‚请在写代ç æ—¶è‡³å°‘è€ƒè™‘ä¸€ä¸‹æœ¬æ–‡æ‰€è¿°ç„ -é£æ ¼ă€‚ +这是一个简çŸç„文档,æ述了 linux å†…æ ¸ç„首选代ç é£æ ¼ă€‚代ç é£æ ¼æ˜¯å› 人而异ç„,而且我 +ä¸æ„¿æ„æ自己ç„观点强å 给任何人,但这就åƒæˆ‘å»å任何事情都必须éµå¾ªç„åŸåˆ™é‚£æ ·ï¼Œæˆ‘也 +希望在ç»å¤§å¤æ•°äº‹ä¸ä¿æŒè¿™ç§ç„æ€åº¦ă€‚请(在写代ç 时)至少考虑一下这里ç„代ç é£æ ¼ă€‚ -é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½GNU代ç 规范,然åä¸è¦è¯»å®ƒă€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§ -æ„义ç„å¨ä½œă€‚ +é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½ GNU 代ç 规范,然åä¸è¦è¯»ă€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§æ„义 +ç„å¨ä½œă€‚ ä¸ç®¡æ€æ ·ï¼Œç°åœ¨æˆ‘ä»¬å¼€å§‹ï¼ - ç¬¬ä¸€ç« ï¼ç¼©è¿› + ç¬¬ä¸€ç« ï¼ç¼©è¿› -制表符是8个å—符,所以缩进也是8个å—ç¬¦ă€‚æœ‰äº›å¼‚ç«¯è¿å¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º4(乃至2)个å—符 -æ·±ï¼Œè¿™å‡ ä¹ç›¸å½“äºå°è¯•å°†åœ†å‘¨ç‡ç„值å®ä¹‰ä¸º3。 +制表符是 8 个å—符,所以缩进也是 8 个å—ç¬¦ă€‚æœ‰äº›å¼‚ç«¯è¿å¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º 4(ç”至 2ï¼ï¼‰ +个å—ç¬¦æ·±ï¼Œè¿™å‡ ä¹ç›¸å½“äºå°è¯•å°†åœ†å‘¨ç‡ç„值å®ä¹‰ä¸º 3。 ç†ç”±ï¼ç¼©è¿›ç„全部æ„义就在äºæ¸…æ¥ç„å®ä¹‰ä¸€ä¸ªæ§åˆ¶å—èµ·æ¢äºä½•å¤„ă€‚å°¤å…¶æ˜¯å½“ä½ ç›¯ç€ä½ ç„å±å¹• -è¿ç»çœ‹äº†20å°æ—¶ä¹‹åï¼Œä½ å°†ä¼å‘ç°å¤§ä¸€ç‚¹ç„缩进ä¼ä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ă€‚ +è¿ç»çœ‹äº† 20 å°æ—¶ä¹‹åï¼Œä½ å°†ä¼å‘ç°å¤§ä¸€ç‚¹ç„缩进ä¼ä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ă€‚ -ç°åœ¨ï¼Œæœ‰äº›äººä¼æ±æ€¨8个å—符ç„缩进ä¼ä½¿ä»£ç å‘å³è¾¹ç§»å¨ç„太远,在80个å—符ç„终端å±å¹•ä¸ -就很é¾è¯»è¿™æ ·ç„代ç ă€‚è¿™ä¸ªé—®é¢˜ç„ç”案是,如æœä½ 需è¦3级以ä¸ç„缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ +ç°åœ¨ï¼Œæœ‰äº›äººä¼æ±æ€¨ 8 个å—符ç„缩进ä¼ä½¿ä»£ç å‘å³è¾¹ç§»å¨ç„太远,在 80 个å—符ç„终端å±å¹•ä¸ +就很é¾è¯»è¿™æ ·ç„代ç ă€‚è¿™ä¸ªé—®é¢˜ç„ç”案是,如æœä½ éœ€è¦ 3 级以ä¸ç„缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ ç„代ç å·²ç»æœ‰é—®é¢˜äº†ï¼Œåº”该修æ£ä½ ç„程åºă€‚ -简而言之,8个å—符ç„缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ ç„å‡½æ•°åµŒå¥—å¤ªæ·±ç„ +简而言之,8 个å—符ç„缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ ç„å‡½æ•°åµŒå¥—å¤ªæ·±ç„ æ—¶å€™å¯ä»¥ç»™ä½ è¦å‘ă€‚ç•™å¿ƒè¿™ä¸ªè¦å‘。 -在switchè¯å¥ä¸æ¶ˆé™¤å¤çº§ç¼©è¿›ç„首选ç„æ–¹å¼æ˜¯è®©â€œswitchâ€å’Œä»å±äºå®ƒç„“caseâ€æ ‡ç¾å¯¹é½äºåŒ -一列,而ä¸è¦â€œä¸¤æ¬¡ç¼©è¿›â€â€œcaseâ€æ ‡ç¾ă€‚æ¯”å¦‚ï¼ +在 switch è¯å¥ä¸æ¶ˆé™¤å¤çº§ç¼©è¿›ç„首选ç„æ–¹å¼æ˜¯è®© “switch†和ä»å±äºå®ƒç„ “caseâ€ æ ‡ç¾ +对é½äºåŒä¸€åˆ—,而ä¸è¦ “两次缩进†“caseâ€ æ ‡ç¾ă€‚æ¯”å¦‚ï¼ switch (suffix) { case 'G': @@ -70,7 +69,6 @@ Documentation/CodingStyleç„ä¸æ–‡ç¿»è¯‘ break; } - ä¸è¦æå¤ä¸ªè¯å¥æ”¾åœ¨ä¸€è¡Œé‡Œï¼Œé™¤éä½ æœ‰ä»€ä¹ˆä¸œè¥¿è¦éè—ï¼ if (condition) do_this; @@ -79,7 +77,7 @@ Documentation/CodingStyleç„ä¸æ–‡ç¿»è¯‘ 也ä¸è¦åœ¨ä¸€è¡Œé‡Œæ”¾å¤ä¸ªèµ‹å€¼è¯å¥ă€‚å†…æ ¸ä»£ç é£æ ¼è¶…级简å•ă€‚就是é¿å…å¯èƒ½å¯¼è‡´åˆ«äººè¯¯è¯»ç„表 è¾¾å¼ă€‚ -除了注é‡ă€æ–‡æ¡£å’ŒKconfig之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢ç„例å是例外,是有æ„ä¸ºä¹‹ă€‚ +除了注é‡ă€æ–‡æ¡£å’Œ Kconfig 之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢ç„例å是例外,是有æ„ä¸ºä¹‹ă€‚ 选用一个好ç„编辑器,ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºæ ¼ă€‚ @@ -88,27 +86,18 @@ Documentation/CodingStyleç„ä¸æ–‡ç¿»è¯‘ 代ç é£æ ¼ç„æ„义就在äºä½¿ç”¨å¹³å¸¸ä½¿ç”¨ç„工具æ¥ç»´æŒä»£ç ç„å¯è¯»æ€§å’Œå¯ç»´æ¤æ€§ă€‚ -æ¯ä¸€è¡Œç„长度ç„é™åˆ¶æ˜¯80列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ă€‚ +æ¯ä¸€è¡Œç„长度ç„é™åˆ¶æ˜¯ 80 列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ă€‚ -é•¿äº80列ç„è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义ç„ç‰‡æ®µă€‚æ¯ä¸ªç‰‡æ®µè¦æ˜æ˜¾çŸäºåŸæ¥ç„è¯å¥ï¼Œè€Œä¸”放置ç„ä½ç½® -也æ˜æ˜¾ç„é å³ă€‚åŒæ ·ç„规则也适用äºæœ‰å¾ˆé•¿å‚数列表ç„å‡½æ•°å¤´ă€‚é•¿å—符串也è¦æ‰“æ•£æˆè¾ƒçŸç„ -å—ç¬¦ä¸²ă€‚å”¯ä¸€ç„例外是超过80列å¯ä»¥å¤§å¹…度æ高å¯è¯»æ€§å¹¶ä¸”ä¸ä¼éè—ä¿¡æ¯ç„æƒ…å†µă€‚ - -void fun(int a, int b, int c) -{ - if (condition) - printk(KERN_WARNING "Warning this is a long printk with " - "3 parameters a: %u b: %u " - "c: %u \n", a, b, c); - else - next_statement; -} +é•¿äº 80 列ç„è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义ç„ç‰‡æ®µă€‚é™¤é超过 80 列能显著å¢å å¯è¯»æ€§ï¼Œå¹¶ä¸”ä¸ä¼éè— +ä¿¡æ¯ă€‚å片段è¦æ˜æ˜¾çŸäºæ¯ç‰‡æ®µï¼Œå¹¶æ˜æ˜¾é å³ă€‚è¿™åŒæ ·é€‚用äºæœ‰ç€å¾ˆé•¿å‚数列表ç„å‡½æ•°å¤´ă€‚ +然而,ç»å¯¹ä¸è¦æ‰“散对用户å¯è§ç„å—符串,例如 printk ä¿¡æ¯ï¼Œå› ä¸ºè¿™å°†å¯¼è‡´æ— æ³• grep 这些 +ä¿¡æ¯ă€‚ ç¬¬ä¸‰ç« ï¼å¤§æ‹¬å·å’Œç©ºæ ¼ç„放置 Cè¯è¨€é£æ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·ç„æ”¾ç½®ă€‚å’Œç¼©è¿›å¤§å°ä¸åŒï¼Œé€‰æ‹©æˆ–弃用æŸç§æ”¾ç½®ç– -略并没有å¤å°‘æ€æœ¯ä¸ç„åŸå› ,ä¸è¿‡é¦–选ç„æ–¹å¼ï¼Œå°±åƒKernighanå’ŒRitchie展示给我们ç„,是 -æ起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€Œæ结æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–ï¼Œæ‰€ä»¥ï¼ +略并没有å¤å°‘æ€æœ¯ä¸ç„åŸå› ,ä¸è¿‡é¦–选ç„æ–¹å¼ï¼Œå°±åƒ Kernighan å’Œ Ritchie 展示给我们ç„, +是æ起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€Œæ结æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–ï¼Œæ‰€ä»¥ï¼ if (x is true) { we do y @@ -134,12 +123,12 @@ Cè¯è¨€é£æ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·ç„æ”¾ç½®ă€‚å’Œç¼©è¿›å¤§å°ä body of function } -全世界ç„异端å¯èƒ½ä¼æ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´ç„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨ç„人都知é“( -a)K&R是_æ£ç¡®ç„_,并且(b)K&R是æ£ç¡®ç„。æ¤å¤–,ä¸ç®¡æ€æ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®ç„(在Cè¯è¨€ä¸ -,函数是ä¸èƒ½åµŒå¥—ç„ï¼‰ă€‚ +全世界ç„异端å¯èƒ½ä¼æ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´ç„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨ç„äººéƒ½çŸ¥é“ +(a) K&R 是 _æ£ç¡®ç„_,并且 (b) K&R 是æ£ç¡®ç„。æ¤å¤–,ä¸ç®¡æ€æ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®ç„(C +函数是ä¸èƒ½åµŒå¥—ç„ï¼‰ă€‚ -注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤é它åé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥ç„剩余部分,也就是doè¯å¥ä¸ç„ -“whileâ€æˆ–者ifè¯å¥ä¸ç„“elseâ€ï¼Œåƒè¿™æ ·ï¼ +注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤é它åé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥ç„剩余部分,也就是 do è¯å¥ä¸ç„ +“while†或者 if è¯å¥ä¸ç„ “elseâ€ï¼Œåƒè¿™æ ·ï¼ do { body of do-loop @@ -158,41 +147,50 @@ a)K&R是_æ£ç¡®ç„_,并且(b)K&R是æ£ç¡®ç„。æ¤å¤–,ä¸ç®¡æ€æ ·å‡½æ ç†ç”±ï¼K&R。 也请注æ„è¿™ç§å¤§æ‹¬å·ç„放置方å¼ä¹Ÿèƒ½ä½¿ç©ºï¼ˆæˆ–者差ä¸å¤ç©ºç„)行ç„æ•°é‡æœ€å°åŒ–,åŒæ—¶ä¸å¤±å¯ -è¯»æ€§ă€‚å› æ¤ï¼Œç”±äºä½ ç„å±å¹•ä¸ç„新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³25è¡Œç„终端å±å¹•ï¼‰ï¼Œä½ å°†ä¼æœ‰æ›´ +è¯»æ€§ă€‚å› æ¤ï¼Œç”±äºä½ ç„å±å¹•ä¸ç„新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³ 25 è¡Œç„终端å±å¹•ï¼‰ï¼Œä½ å°†ä¼æœ‰æ›´ å¤ç„空行æ¥æ”¾ç½®æ³¨é‡ă€‚ 当åªæœ‰ä¸€ä¸ªå•ç‹¬ç„è¯å¥ç„时候,ä¸ç”¨å ä¸å¿…è¦ç„大括å·ă€‚ -if (condition) - action(); + if (condition) + action(); + +å’Œ + + if (condition) + do_this(); + else + do_that(); -这点ä¸é€‚用äºæœ¬èº«ä¸ºæŸä¸ªæ¡ä»¶è¯å¥ç„一个分支ç„å•ç‹¬è¯å¥ă€‚这时需è¦åœ¨ä¸¤ä¸ªåˆ†æ”¯é‡Œéƒ½ä½¿ç”¨å¤§ -括å·ă€‚ +这并ä¸é€‚用äºåªæœ‰ä¸€ä¸ªæ¡ä»¶åˆ†æ”¯æ˜¯å•è¯å¥ç„情况;这时所有分支都è¦ä½¿ç”¨å¤§æ‹¬å·ï¼ -if (condition) { - do_this(); - do_that(); -} else { - otherwise(); -} + if (condition) { + do_this(); + do_that(); + } else { + otherwise(); + } 3.1ï¼ç©ºæ ¼ -Linuxå†…æ ¸ç„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决äºå®ƒæ˜¯ç”¨äºå‡½æ•°è¿˜æ˜¯å…³é”®å—ă€‚ï¼ˆå¤§å¤æ•°ï¼‰å…³é”®å—å -è¦å ä¸€ä¸ªç©ºæ ¼ă€‚å€¼å¾—æ³¨æ„ç„例外是sizeofă€typeofă€alignofå’Œ__attribute__ï¼Œè¿™äº›å…³é”®å— -æŸäº›ç¨‹åº¦ä¸çœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨Linux里也常常伴éå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨Cè¯è¨€é‡Œè¿™æ · -ç„å°æ‹¬å·ä¸æ˜¯å¿…需ç„,就åƒâ€œstruct fileinfo infoâ€å£°æ˜è¿‡åç„“sizeof infoâ€ï¼‰ă€‚ +Linux å†…æ ¸ç„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决äºå®ƒæ˜¯ç”¨äºå‡½æ•°è¿˜æ˜¯å…³é”®å—ă€‚ï¼ˆå¤§å¤æ•°ï¼‰å…³é”®å—å +è¦å ä¸€ä¸ªç©ºæ ¼ă€‚å€¼å¾—æ³¨æ„ç„例外是 sizeofă€typeofă€alignof å’Œ __attribute__,这些 +关键å—æŸäº›ç¨‹åº¦ä¸çœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨ Linux 里也常常伴éå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨ C 里 +è¿™æ ·ç„å°æ‹¬å·ä¸æ˜¯å¿…需ç„ï¼Œå°±åƒ â€œstruct fileinfo info†声æ˜è¿‡åç„ â€œsizeof infoâ€ï¼‰ă€‚ 所以在这些关键å—之åæ”¾ä¸€ä¸ªç©ºæ ¼ï¼ + if, switch, case, for, do, while -但是ä¸è¦åœ¨sizeofă€typeofă€alignof或者__attribute__这些关键å—之åæ”¾ç©ºæ ¼ă€‚ä¾‹å¦‚ï¼Œ + +但是ä¸è¦åœ¨ sizeofă€typeofă€alignof 或者 __attribute__ 这些关键å—之åæ”¾ç©ºæ ¼ă€‚ä¾‹å¦‚ï¼Œ + s = sizeof(struct file); ä¸è¦åœ¨å°æ‹¬å·é‡Œç„表达å¼ä¸¤ä¾§å ç©ºæ ¼ă€‚è¿™æ˜¯ä¸€ä¸ªåä¾‹ï¼ s = sizeof( struct file ); -当声æ˜æŒ‡é’ˆç±»å‹æˆ–者返å›æŒ‡é’ˆç±»å‹ç„函数时,“*â€ç„首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函 +当声æ˜æŒ‡é’ˆç±»å‹æˆ–者返å›æŒ‡é’ˆç±»å‹ç„函数时,“*†ç„首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函 æ•°å,而ä¸æ˜¯é è¿‘ç±»å‹åă€‚ä¾‹åï¼ char *linux_banner; @@ -204,15 +202,18 @@ Linuxå†…æ ¸ç„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决äºå®ƒæ˜¯ç”¨äºå‡½æ•°è¿˜æ˜¯å…³ = + - < > * / % | & ^ <= >= == != ? : 但是一元æ“作符åä¸è¦å ç©ºæ ¼ï¼ + & * + - ~ ! sizeof typeof alignof __attribute__ defined å缀自å 和自å‡ä¸€å…ƒæ“作符å‰ä¸å ç©ºæ ¼ï¼ + ++ -- å‰ç¼€è‡ªå 和自å‡ä¸€å…ƒæ“作符åä¸å ç©ºæ ¼ï¼ + ++ -- -“.â€å’Œâ€œ->â€ç»“æ„体æˆå‘˜æ“作符å‰åä¸å ç©ºæ ¼ă€‚ +‘.’ å’Œ “->†结æ„体æˆå‘˜æ“作符å‰åä¸å ç©ºæ ¼ă€‚ ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºç™½ă€‚有些å¯ä»¥è‡ªå¨ç¼©è¿›ç„编辑器ä¼åœ¨æ–°è¡Œç„行首å 入适é‡ç„空白,然åä½ å°±å¯ä»¥ç›´æ¥åœ¨é‚£ä¸€è¡Œè¾“入代ç 。ä¸è¿‡å‡å¦‚ä½ æœ€å没有在那一行输入代ç ï¼Œæœ‰äº›ç¼–è¾‘å™¨å°±ä¸ @@ -225,23 +226,23 @@ Linuxå†…æ ¸ç„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决äºå®ƒæ˜¯ç”¨äºå‡½æ•°è¿˜æ˜¯å…³ ç¬¬å››ç« ï¼å‘½å -C是一个简朴ç„è¯è¨€ï¼Œä½ ç„命åä¹Ÿåº”è¯¥è¿™æ ·ă€‚å’ŒModula-2å’ŒPascal程åºå‘˜ä¸åŒï¼ŒC程åºå‘˜ä¸ä½¿ -用类似ThisVariableIsATemporaryCounterè¿™æ ·å丽ç„åå—。C程åºå‘˜ä¼ç§°é‚£ä¸ªå˜é‡ä¸ºâ€œtmp†-ï¼Œè¿™æ ·å†™èµ·æ¥ä¼æ›´å®¹æ˜“,而且至少ä¸ä¼ä»¤å…¶é¾äºç†è§£ă€‚ +C是一个简朴ç„è¯è¨€ï¼Œä½ ç„命åä¹Ÿåº”è¯¥è¿™æ ·ă€‚å’Œ Modula-2 å’Œ Pascal 程åºå‘˜ä¸åŒï¼ŒC 程åºå‘˜ +ä¸ä½¿ç”¨ç±»ä¼¼ ThisVariableIsATemporaryCounter è¿™æ ·å丽ç„åå—。C 程åºå‘˜ä¼ç§°é‚£ä¸ªå˜é‡ +为 “tmpâ€ï¼Œè¿™æ ·å†™èµ·æ¥ä¼æ›´å®¹æ˜“,而且至少ä¸ä¼ä»¤å…¶é¾äºç†è§£ă€‚ ä¸è¿‡ï¼Œè™½ç„¶æ··ç”¨å¤§å°å†™ç„åå—是ä¸æ倡使用ç„,但是全局å˜é‡è¿˜æ˜¯éœ€è¦ä¸€ä¸ªå…·æ述性ç„åå— -ă€‚ç§°ä¸€ä¸ªå…¨å±€å‡½æ•°ä¸ºâ€œfooâ€æ˜¯ä¸€ä¸ªé¾ä»¥é¥¶æ•ç„é”™è¯¯ă€‚ +ă€‚ç§°ä¸€ä¸ªå…¨å±€å‡½æ•°ä¸º “foo†是一个é¾ä»¥é¥¶æ•ç„é”™è¯¯ă€‚ 全局å˜é‡ï¼ˆåªæœ‰å½“ä½ çœŸæ£éœ€è¦å®ƒä»¬ç„时候å†ç”¨å®ƒï¼‰éœ€è¦æœ‰ä¸€ä¸ªå…·æ述性ç„åå—,就åƒå…¨å±€å‡½ -æ•°ă€‚å¦‚æœä½ 有一个å¯ä»¥è®¡ç®—æ´»å¨ç”¨æˆ·æ•°é‡ç„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒâ€œcount_active_users()â€æˆ–者 -类似ç„åå—ï¼Œä½ ä¸åº”该å«å®ƒâ€œcntuser()â€ă€‚ +æ•°ă€‚å¦‚æœä½ 有一个å¯ä»¥è®¡ç®—æ´»å¨ç”¨æˆ·æ•°é‡ç„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒ “count_active_users()†+或者类似ç„åå—ï¼Œä½ ä¸åº”该å«å®ƒ “cntuser()â€ă€‚ 在函数åä¸åŒ…å«å‡½æ•°ç±»å‹ï¼ˆæ‰€è°“ç„匈牙利命å法)是脑å出了问题——编译器知é“那些类å‹è€Œ 且能够检查那些类å‹ï¼Œè¿™æ ·ååªèƒ½æ程åºå‘˜å¼„ç³æ¶‚äº†ă€‚é¾æ€ªå¾®è½¯æ€»æ˜¯åˆ¶é€ 出有问题ç„程åºă€‚ 本地å˜é‡å应该简çŸï¼Œè€Œä¸”能够表达相关ç„å«ä¹‰ă€‚如æœä½ 有一些é机ç„æ•´æ•°å‹ç„循ç¯è®¡æ•°å™¨ -,它应该被称为“iâ€ă€‚å«å®ƒâ€œloop_counterâ€å¹¶æ— ç›å¤„,如æœå®ƒæ²¡æœ‰è¢«è¯¯è§£ç„å¯èƒ½ç„è¯ă€‚类似 -ç„,“tmpâ€å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„ç±»å‹ç„临时å˜é‡ă€‚ +,它应该被称为 “iâ€ă€‚å«å®ƒ “loop_counterâ€ å¹¶æ— ç›å¤„,如æœå®ƒæ²¡æœ‰è¢«è¯¯è§£ç„å¯èƒ½ç„è¯ă€‚ +类似ç„,“tmp†å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„ç±»å‹ç„临时å˜é‡ă€‚ 如æœä½ æ€•æ··æ·†äº†ä½ ç„本地å˜é‡åï¼Œä½ å°±é‡åˆ°å¦ä¸€ä¸ªé—®é¢˜äº†ï¼Œå«å函数å¢é•¿è·å°”蒙失衡综åˆç—‡ ă€‚è¯·çœ‹ç¬¬å…ç« ï¼ˆå‡½æ•°ï¼‰ă€‚ @@ -249,9 +250,9 @@ C是一个简朴ç„è¯è¨€ï¼Œä½ ç„命åä¹Ÿåº”è¯¥è¿™æ ·ă€‚å’ŒModula-2å’ŒPascalç¨ ç¬¬äº”ç« ï¼Typedef -ä¸è¦ä½¿ç”¨ç±»ä¼¼â€œvps_tâ€ä¹‹ç±»ç„ä¸œè¥¿ă€‚ +ä¸è¦ä½¿ç”¨ç±»ä¼¼ “vps_t†之类ç„ä¸œè¥¿ă€‚ -对结æ„体和指针使用typedefæ˜¯ä¸€ä¸ªé”™è¯¯ă€‚å½“ä½ åœ¨ä»£ç é‡Œçœ‹åˆ°ï¼ +对结æ„体和指针使用 typedef æ˜¯ä¸€ä¸ªé”™è¯¯ă€‚å½“ä½ åœ¨ä»£ç é‡Œçœ‹åˆ°ï¼ vps_t a; @@ -261,91 +262,91 @@ C是一个简朴ç„è¯è¨€ï¼Œä½ ç„命åä¹Ÿåº”è¯¥è¿™æ ·ă€‚å’ŒModula-2å’ŒPascalç¨ struct virtual_container *a; -ä½ å°±çŸ¥é““aâ€æ˜¯ä»€ä¹ˆäº†ă€‚ +ä½ å°±çŸ¥é“ â€œaâ€ æ˜¯ä»€ä¹ˆäº†ă€‚ -很å¤äººè®¤ä¸ºtypedef“能æ高å¯è¯»æ€§â€ă€‚å®é™…ä¸æ˜¯è¿™æ ·ç„ă€‚å®ƒä»¬åªåœ¨ä¸‹åˆ—æƒ…å†µä¸‹æœ‰ç”¨ï¼ +很å¤äººè®¤ä¸º typedef “能æ高å¯è¯»æ€§â€ă€‚å®é™…ä¸æ˜¯è¿™æ ·ç„ă€‚å®ƒä»¬åªåœ¨ä¸‹åˆ—æƒ…å†µä¸‹æœ‰ç”¨ï¼ - (a) 完全ä¸é€æ˜ç„对象(这ç§æƒ…况下è¦ä¸»å¨ä½¿ç”¨typedefæ¥éè—这个对象å®é™…ä¸æ˜¯ä»€ä¹ˆï¼‰ă€‚ + (a) 完全ä¸é€æ˜ç„对象(这ç§æƒ…况下è¦ä¸»å¨ä½¿ç”¨ typedef æ¥éè—这个对象å®é™…ä¸æ˜¯ä»€ä¹ˆï¼‰ă€‚ - 例如ï¼â€œpte_tâ€ç‰ä¸é€æ˜å¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚ç„访问函数æ¥è®¿é—®å®ƒä»¬ă€‚ + 例如ï¼â€œpte_t†ç‰ä¸é€æ˜å¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚ç„访问函数æ¥è®¿é—®å®ƒä»¬ă€‚ - 注æ„ï¼ä¸é€æ˜æ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½ç„ă€‚æˆ‘ä»¬ä½¿ç”¨pte_tç‰ç±»å‹ç„åŸå› 在äºçœŸç„是 + 注æ„ï¼ä¸é€æ˜æ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½ç„ă€‚æˆ‘ä»¬ä½¿ç”¨ pte_t ç‰ç±»å‹ç„åŸå› 在äºçœŸç„是 完全没有任何共用ç„å¯è®¿é—®ä¿¡æ¯ă€‚ - (b) 清æ¥ç„æ•´æ•°ç±»å‹ï¼Œå¦‚æ¤ï¼Œè¿™å±‚æ½è±¡å°±å¯ä»¥å¸®å©æ¶ˆé™¤åˆ°åº•æ˜¯â€œintâ€è¿˜æ˜¯â€œlongâ€ç„æ··æ·†ă€‚ + (b) 清æ¥ç„æ•´æ•°ç±»å‹ï¼Œå¦‚æ¤ï¼Œè¿™å±‚æ½è±¡å°±å¯ä»¥å¸®å©æ¶ˆé™¤åˆ°åº•æ˜¯ “int†还是 “long†ç„æ··æ·†ă€‚ - u8/u16/u32是完全没有问题ç„typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ«(d)而ä¸æ˜¯è¿™é‡Œă€‚ + u8/u16/u32 æ˜¯å®Œå…¨æ²¡æœ‰é—®é¢˜ç„ typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ« (d) 而ä¸æ˜¯è¿™é‡Œă€‚ - å†æ¬¡æ³¨æ„ï¼è¦è¿™æ ·åï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ă€‚å¦‚æœæŸä¸ªå˜é‡æ˜¯â€œunsigned longâ€œï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ + å†æ¬¡æ³¨æ„ï¼è¦è¿™æ ·åï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ă€‚å¦‚æœæŸä¸ªå˜é‡æ˜¯ “unsigned longâ€œï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ typedef unsigned long myflags_t; - ä¸è¿‡å¦‚æœæœ‰ä¸€ä¸ªæ˜ç¡®ç„åŸå› ,比如它在æŸç§æƒ…况下å¯èƒ½ä¼æ˜¯ä¸€ä¸ªâ€œunsigned intâ€è€Œåœ¨ - 其他情况下å¯èƒ½ä¸ºâ€œunsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦ç¹è±«ï¼Œè¯·å¡å¿…使用typedef。 + ä¸è¿‡å¦‚æœæœ‰ä¸€ä¸ªæ˜ç¡®ç„åŸå› ,比如它在æŸç§æƒ…况下å¯èƒ½ä¼æ˜¯ä¸€ä¸ª “unsigned int†而在 + 其他情况下å¯èƒ½ä¸º “unsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦ç¹è±«ï¼Œè¯·å¡å¿…使用 typedef。 (c) å½“ä½ ä½¿ç”¨sparse按å—é¢ç„创建一个新类å‹æ¥åç±»å‹æ£€æŸ¥ç„æ—¶å€™ă€‚ (d) å’Œæ ‡å‡†C99ç±»å‹ç›¸åŒç„ç±»å‹ï¼Œåœ¨æŸäº›ä¾‹å¤–ç„æƒ…å†µä¸‹ă€‚ - 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚应新ç„æ ‡å‡†ç±»å‹æ¯”如“uint32_tâ€ä¸éœ€è¦è±å¾ˆå¤æ—¶é—´ï¼Œå¯æ˜¯æœ‰äº› + 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚应新ç„æ ‡å‡†ç±»å‹æ¯”如 “uint32_t†ä¸éœ€è¦è±å¾ˆå¤æ—¶é—´ï¼Œå¯æ˜¯æœ‰äº› 人ä»ç„¶æ‹’ç»ä½¿ç”¨å®ƒä»¬ă€‚ - å› æ¤ï¼ŒLinux特有ç„ç‰åŒäºæ ‡å‡†ç±»å‹ç„“u8/u16/u32/u64â€ç±»å‹å’Œå®ƒä»¬ç„有符å·ç±»å‹æ˜¯è¢« + å› æ¤ï¼ŒLinux 特有ç„ç‰åŒäºæ ‡å‡†ç±»å‹ç„ “u8/u16/u32/u64†类å‹å’Œå®ƒä»¬ç„有符å·ç±»å‹æ˜¯è¢« å…许ç„â€”â€”å°½ç®¡åœ¨ä½ è‡ªå·±ç„新代ç ä¸ï¼Œå®ƒä»¬ä¸æ˜¯å¼ºåˆ¶è¦æ±‚è¦ä½¿ç”¨ç„。 当编辑已ç»ä½¿ç”¨äº†æŸä¸ªç±»å‹é›†ç„已有代ç æ—¶ï¼Œä½ åº”è¯¥éµå¾ªé‚£äº›ä»£ç ä¸å·²ç»å出ç„é€‰æ‹©ă€‚ (e) å¯ä»¥åœ¨ç”¨æˆ·ç©ºé—´å®‰å…¨ä½¿ç”¨ç„ç±»å‹ă€‚ - 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§ç„结æ„体里,我们ä¸èƒ½è¦æ±‚C99ç±»å‹è€Œä¸”ä¸èƒ½ç”¨ä¸é¢æ到ç„“u32†- ç±»å‹ă€‚å› æ¤ï¼Œæˆ‘们在ä¸ç”¨æˆ·ç©ºé—´å…±äº«ç„所有结æ„体ä¸ä½¿ç”¨__u32和类似ç„ç±»å‹ă€‚ + 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§ç„结æ„体里,我们ä¸èƒ½è¦æ±‚C99ç±»å‹è€Œä¸”ä¸èƒ½ç”¨ä¸é¢æåˆ°ç„ â€œu32†+ ç±»å‹ă€‚å› æ¤ï¼Œæˆ‘们在ä¸ç”¨æˆ·ç©ºé—´å…±äº«ç„所有结æ„体ä¸ä½¿ç”¨ __u32 和类似ç„ç±»å‹ă€‚ -å¯èƒ½è¿˜æœ‰å…¶ä»–ç„情况,ä¸è¿‡åŸºæœ¬ç„规则是永远ä¸è¦ä½¿ç”¨typedef,除éä½ å¯ä»¥æ˜ç¡®ç„åº”ç”¨ä¸ +å¯èƒ½è¿˜æœ‰å…¶ä»–ç„情况,ä¸è¿‡åŸºæœ¬ç„规则是永远ä¸è¦ä½¿ç”¨ typedef,除éä½ å¯ä»¥æ˜ç¡®ç„åº”ç”¨ä¸ è¿°æŸä¸ªè§„则ä¸ç„ä¸€ä¸ªă€‚ 总ç„æ¥è¯´ï¼Œå¦‚æœä¸€ä¸ªæŒ‡é’ˆæˆ–者一个结æ„体里ç„å…ƒç´ å¯ä»¥åˆç†ç„被直æ¥è®¿é—®åˆ°ï¼Œé‚£ä¹ˆå®ƒä»¬å°±ä¸ -应该是一个typedef。 +应该是一个 typedef。 第å…ç« ï¼å‡½æ•° 函数应该简çŸè€Œæ¼‚亮,并且åªå®Œæˆä¸€ä»¶äº‹æƒ…ă€‚å‡½æ•°åº”è¯¥å¯ä»¥ä¸€å±æˆ–者两å±æ˜¾ç¤ºå®Œï¼ˆæˆ‘们都知 -é“ISO/ANSIå±å¹•å¤§å°æ˜¯80x24),åªå一件事情,而且æ它åå¥½ă€‚ +é“ ISO/ANSI å±å¹•å¤§å°æ˜¯ 80x24),åªå一件事情,而且æ它åå¥½ă€‚ 一个函数ç„最大长度是和该函数ç„å¤æ‚度和缩进级数æˆå比ç„ă€‚æ‰€ä»¥ï¼Œå¦‚æœä½ 有一个ç†è®ºä¸ -很简å•ç„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•ï¼‰ç„caseè¯å¥ç„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ªcase里å很å¤å¾ˆ -å°ç„äº‹æƒ…ï¼Œè¿™æ ·ç„函数尽管很长,但也是å¯ä»¥ç„。 +很简å•ç„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•ï¼‰ç„ case è¯å¥ç„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ª case 里å +很å¤å¾ˆå°ç„äº‹æƒ…ï¼Œè¿™æ ·ç„函数尽管很长,但也是å¯ä»¥ç„。 ä¸è¿‡ï¼Œå¦‚æœä½ 有一个å¤æ‚ç„å‡½æ•°ï¼Œè€Œä¸”ä½ æ€€ç–‘ä¸€ä¸ªå¤©åˆ†ä¸æ˜¯å¾ˆé«˜ç„高ä¸ä¸€å¹´çº§å¦ç”Ÿå¯èƒ½ç”至 æä¸æ¸…æ¥è¿™ä¸ªå‡½æ•°ç„ç›®ç„ï¼Œä½ åº”è¯¥ä¸¥æ ¼ç„éµå®ˆå‰é¢æ到ç„长度é™åˆ¶ă€‚使用辅å©å‡½æ•°ï¼Œå¹¶ä¸ºä¹‹ å–个具æ述性ç„åå—(如æœä½ 觉得它们ç„性能很é‡è¦ç„è¯ï¼Œå¯ä»¥è®©ç¼–译器内è”å®ƒä»¬ï¼Œè¿™æ ·ç„ æ•ˆæœå¾€å¾€ä¼æ¯”ä½ å†™ä¸€ä¸ªå¤æ‚函数ç„效æœè¦å¥½ă€‚) -函数ç„å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡ç„æ•°é‡ă€‚æ¤æ•°é‡ä¸åº”超过5ï¼10个,å¦åˆ™ä½ ç„函数就有 +函数ç„å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡ç„æ•°é‡ă€‚æ¤æ•°é‡ä¸åº”超过 5ï¼10 个,å¦åˆ™ä½ ç„函数就有 é—®é¢˜äº†ă€‚é‡æ–°è€ƒè™‘ä¸€ä¸‹ä½ ç„函数,æ它分拆æˆæ›´å°ç„å‡½æ•°ă€‚äººç„大脑一般å¯ä»¥è½»æ¾ç„åŒæ—¶è·Ÿ -踪7个ä¸åŒç„事物,如æœå†å¢å¤ç„è¯ï¼Œå°±ä¼ç³æ¶‚äº†ă€‚å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯èƒ½ä¼è®°ä¸æ¸…ä½ 2 -个星期å‰å过ç„äº‹æƒ…ă€‚ +踪 7 个ä¸åŒç„事物,如æœå†å¢å¤ç„è¯ï¼Œå°±ä¼ç³æ¶‚äº†ă€‚å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯èƒ½ä¼è®°ä¸æ¸…ä½ +2 个星期å‰å过ç„äº‹æƒ…ă€‚ -在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œé”å¼€ä¸åŒç„å‡½æ•°ă€‚å¦‚æœè¯¥å‡½æ•°éœ€è¦è¢«å¯¼å‡ºï¼Œå®ƒç„EXPORT*å®åº”该紧贴 +在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œé”å¼€ä¸åŒç„å‡½æ•°ă€‚å¦‚æœè¯¥å‡½æ•°éœ€è¦è¢«å¯¼å‡ºï¼Œå®ƒç„ EXPORT* å®åº”该紧贴 在它ç„结æŸå¤§æ‹¬å·ä¹‹ä¸‹ă€‚æ¯”å¦‚ï¼ -int system_is_up(void) -{ - return system_state == SYSTEM_RUNNING; -} -EXPORT_SYMBOL(system_is_up); + int system_is_up(void) + { + return system_state == SYSTEM_RUNNING; + } + EXPORT_SYMBOL(system_is_up); -在函数åŸå‹ä¸ï¼ŒåŒ…å«å‡½æ•°å和它们ç„æ•°æ®ç±»å‹ă€‚虽然Cè¯è¨€é‡Œæ²¡æœ‰è¿™æ ·ç„è¦æ±‚,在Linux里这 +在函数åŸå‹ä¸ï¼ŒåŒ…å«å‡½æ•°å和它们ç„æ•°æ®ç±»å‹ă€‚虽然Cè¯è¨€é‡Œæ²¡æœ‰è¿™æ ·ç„è¦æ±‚,在 Linux 里这 是æ倡ç„åæ³•ï¼Œå› ä¸ºè¿™æ ·å¯ä»¥å¾ˆç®€å•ç„给读者æ供更å¤ç„有价值ç„ä¿¡æ¯ă€‚ ç¬¬ä¸ƒç« ï¼é›†ä¸ç„函数退出途径 -虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯gotoè¯å¥ç„ç‰ä»·ç‰©è¿˜æ˜¯ç»å¸¸è¢«ç¼–译器所使用,具体形å¼æ˜¯ +虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯ goto è¯å¥ç„ç‰ä»·ç‰©è¿˜æ˜¯ç»å¸¸è¢«ç¼–译器所使用,具体形å¼æ˜¯ æ— æ¡ä»¶è·³è½¬æŒ‡ä»¤ă€‚ -当一个函数ä»å¤ä¸ªä½ç½®é€€å‡ºå¹¶ä¸”需è¦å一些é€ç”¨ç„清ç†å·¥ä½œç„时候,gotoç„好处就显ç°å‡ºæ¥ -äº†ă€‚ +当一个函数ä»å¤ä¸ªä½ç½®é€€å‡ºï¼Œå¹¶ä¸”需è¦å一些类似清ç†ç„常è§æ“作时,goto è¯å¥å°±å¾ˆæ–¹ä¾¿äº†ă€‚ +如æœå¹¶ä¸éœ€è¦æ¸…ç†æ“ä½œï¼Œé‚£ä¹ˆç›´æ¥ return å³å¯ă€‚ ç†ç”±æ˜¯ï¼ @@ -354,26 +355,37 @@ EXPORT_SYMBOL(system_is_up); - å¯ä»¥é¿å…ç”±äºä¿®æ”¹æ—¶å¿˜è®°æ›´æ–°æŸä¸ªå•ç‹¬ç„退出点而导致ç„错误 - å‡è½»äº†ç¼–译器ç„å·¥ä½œï¼Œæ— éœ€åˆ é™¤å†—ä½™ä»£ç ;) -int fun(int a) -{ - int result = 0; - char *buffer = kmalloc(SIZE); - - if (buffer == NULL) - return -ENOMEM; - - if (condition1) { - while (loop1) { - ... + int fun(int a) + { + int result = 0; + char *buffer; + + buffer = kmalloc(SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out_buffer; } - result = 1; - goto out; + ... + out_buffer: + kfree(buffer); + return result; } - ... -out: - kfree(buffer); - return result; -} + +一个需è¦æ³¨æ„ç„常è§é”™è¯¯æ˜¯â€œä¸€ä¸ª err 错误â€ï¼Œå°±åƒè¿™æ ·ï¼ + + err: + kfree(foo->bar); + kfree(foo); + return ret; + +这段代ç ç„错误是,在æŸäº›é€€å‡ºè·¯å¾„ä¸ â€œfoo†是 NULL。é€å¸¸æƒ…况下,é€è¿‡æ它分离æˆä¸¤ä¸ª +é”™è¯¯æ ‡ç¾ â€œerr_bar:†和 “err_foo:†æ¥ä¿®å¤è¿™ä¸ªé”™è¯¯ă€‚ ç¬¬å…«ç« ï¼æ³¨é‡ @@ -386,10 +398,10 @@ out: å 太å¤ă€‚ä½ åº”è¯¥åç„,是æ注é‡æ”¾åœ¨å‡½æ•°ç„头部,å‘诉人们它å了什么,也å¯ä»¥å ä¸å®ƒåè¿™ 些事情ç„åŸå› 。 -当注é‡å†…æ ¸API函数时,请使用kernel-docæ ¼å¼ă€‚请看 -Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc以è·å¾—详细信æ¯ă€‚ +当注é‡å†…æ ¸API函数时,请使用 kernel-doc æ ¼å¼ă€‚请看 +Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc 以è·å¾—详细信æ¯ă€‚ -Linuxç„注é‡é£æ ¼æ˜¯C89“/* ... */â€é£æ ¼ă€‚ä¸è¦ä½¿ç”¨C99é£æ ¼â€œ// ...â€æ³¨é‡ă€‚ +Linuxç„注é‡é£æ ¼æ˜¯ C89 “/* ... */†é£æ ¼ă€‚ä¸è¦ä½¿ç”¨ C99 é£æ ¼ “// ...†注é‡ă€‚ 长(å¤è¡Œï¼‰ç„首选注é‡é£æ ¼æ˜¯ï¼ @@ -402,6 +414,15 @@ Linuxç„注é‡é£æ ¼æ˜¯C89“/* ... */â€é£æ ¼ă€‚ä¸è¦ä½¿ç”¨C99é£æ ¼â€œ// ... * with beginning and ending almost-blank lines. */ +对äºåœ¨ net/ å’Œ drivers/net/ ç„文件,首选ç„长(å¤è¡Œï¼‰æ³¨é‡é£æ ¼æœ‰äº›ä¸åŒă€‚ + + /* The preferred comment style for files in net/ and drivers/net + * looks like this. + * + * It is nearly the same as the generally preferred comment style, + * but there is no initial almost-blank line. + */ + 注é‡æ•°æ®ä¹Ÿæ˜¯å¾ˆé‡è¦ç„,ä¸ç®¡æ˜¯åŸºæœ¬ç±»å‹è¿˜æ˜¯è¡ç”Ÿç±»å‹ă€‚为了方便å®ç°è¿™ä¸€ç‚¹ï¼Œæ¯ä¸€è¡Œåº”åª å£°æ˜ä¸€ä¸ªæ•°æ®ï¼ˆä¸è¦ä½¿ç”¨é€—å·æ¥ä¸€æ¬¡å£°æ˜å¤ä¸ªæ•°æ®ï¼‰ă€‚è¿™æ ·ä½ å°±æœ‰ç©ºé—´æ¥ä¸ºæ¯ä¸ªæ•°æ®å†™ä¸€æ®µ å°æ³¨é‡æ¥è§£é‡å®ƒä»¬ç„ç”¨é€”äº†ă€‚ @@ -409,49 +430,63 @@ Linuxç„注é‡é£æ ¼æ˜¯C89“/* ... */â€é£æ ¼ă€‚ä¸è¦ä½¿ç”¨C99é£æ ¼â€œ// ... 第ä¹ç« ï¼ä½ å·²ç»æ事情弄糟了 -è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ă€‚å¯èƒ½ä½ ç„使用了很长时间Unixç„朋å‹å·²ç»å‘è¯‰ä½ â€œGNU emacsâ€èƒ½ -自å¨å¸®ä½ æ ¼å¼åŒ–Cæºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„到了,确å®æ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒæ‰€ä½¿ç”¨ç„默认值和我们 -想è¦ç„相å»ç”远(å®é™…ä¸ï¼Œç”至比é机打ç„还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å在GNU emacs里打å—æ°¸è¿œä¸ -ä¼åˆ›é€ 出一个好程åºï¼‰ï¼ˆè¯‘注ï¼è¯·å‚考Infinite Monkey Theorem) - -æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒGNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†ç„设å®ă€‚è¦é‡‡ç”¨åä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯ -以æ下é¢è¿™æ®µç²˜è´´åˆ°ä½ ç„.emacsæ–‡ä»¶é‡Œă€‚ - -(defun linux-c-mode () - "C mode with adjusted defaults for use with the Linux kernel." - (interactive) - (c-mode) - (c-set-style "K&R") - (setq tab-width 8) - (setq indent-tabs-mode t) - (setq c-basic-offset 8)) - -è¿™æ ·å°±å®ä¹‰äº†M-x linux-c-modeå‘½ä»¤ă€‚å½“ä½ hack一个模å—ç„时候,如æœä½ æå—符串 --*- linux-c -*-放在头两行ç„æŸä¸ªä½ç½®ï¼Œè¿™ä¸ªæ¨¡å¼å°†ä¼è¢«è‡ªå¨è°ƒç”¨ă€‚如æœä½ å¸Œæœ›åœ¨ä½ ä¿®æ”¹ -/usr/src/linux里ç„文件时é”术般自å¨æ‰“å¼€linux-c-modeç„è¯ï¼Œä½ 也å¯èƒ½éœ€è¦æ·»å - -(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) - auto-mode-alist)) - -åˆ°ä½ ç„.emacsæ–‡ä»¶é‡Œă€‚ - -ä¸è¿‡å°±ç®—ä½ å°è¯•è®©emacsæ£ç¡®ç„æ ¼å¼åŒ–代ç 失败了,也并ä¸æ„味ç€ä½ 失å»äº†ä¸€åˆ‡ï¼è¿˜å¯ä»¥ç”¨â€œ -indentâ€ă€‚ - -ä¸è¿‡ï¼ŒGNU indent也有和GNU emacsä¸€æ ·æœ‰é—®é¢˜ç„设å®ï¼Œæ‰€ä»¥ä½ 需è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ă€‚ä¸ -过,这还ä¸ç®—å¤ªç³Ÿç³•ï¼Œå› ä¸ºå°±ç®—æ˜¯GNU indentç„作者也认åŒK&Rç„æƒå¨æ€§ï¼ˆGNUç„人并ä¸æ˜¯å -人,他们åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸è¢«ä¸¥é‡ç„è¯¯å¯¼äº†ï¼‰ï¼Œæ‰€ä»¥ä½ åªè¦ç»™indent指å®é€‰é¡¹â€œ-kr -i8†-(代表“K&R,8个å—符缩进â€ï¼‰ï¼Œæˆ–者使用“scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦ç„æ–¹å¼ +è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ă€‚å¯èƒ½ä½ ç„使用了很长时间 Unix ç„朋å‹å·²ç»å‘è¯‰ä½ â€œGNU emacs†能 +自å¨å¸®ä½ æ ¼å¼åŒ– C æºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„到了,确å®æ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒæ‰€ä½¿ç”¨ç„默认值和我们 +想è¦ç„相å»ç”远(å®é™…ä¸ï¼Œç”至比é机打ç„还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å在 GNU emacs 里打å—æ°¸è¿œä¸ +ä¼åˆ›é€ 出一个好程åºï¼‰ï¼ˆè¯‘注ï¼è¯·å‚考 Infinite Monkey Theorem) + +æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒ GNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†ç„设å®ă€‚è¦é‡‡ç”¨åä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯ +以æ下é¢è¿™æ®µç²˜è´´åˆ°ä½ ç„ .emacs æ–‡ä»¶é‡Œă€‚ + +(defun c-lineup-arglist-tabs-only (ignored) + "Line up argument lists by tabs, not spaces" + (let* ((anchor (c-langelem-pos c-syntactic-element)) + (column (c-langelem-2nd-pos c-syntactic-element)) + (offset (- (1+ column) anchor)) + (steps (floor offset c-basic-offset))) + (* (max steps 1) + c-basic-offset))) + +(add-hook 'c-mode-common-hook + (lambda () + ;; Add kernel style + (c-add-style + "linux-tabs-only" + '("linux" (c-offsets-alist + (arglist-cont-nonempty + c-lineup-gcc-asm-reg + c-lineup-arglist-tabs-only)))))) + +(add-hook 'c-mode-hook + (lambda () + (let ((filename (buffer-file-name))) + ;; Enable kernel mode for the appropriate files + (when (and filename + (string-match (expand-file-name "~/src/linux-trees") + filename)) + (setq indent-tabs-mode t) + (setq show-trailing-whitespace t) + (c-set-style "linux-tabs-only"))))) + +è¿™ä¼è®© emacs 在 ~/src/linux-trees ç›®å½•ä¸‹ç„ C æºæ–‡ä»¶è·å¾—更好ç„å†…æ ¸ä»£ç é£æ ¼ă€‚ + +ä¸è¿‡å°±ç®—ä½ å°è¯•è®© emacs æ£ç¡®ç„æ ¼å¼åŒ–代ç 失败了,也并ä¸æ„味ç€ä½ 失å»äº†ä¸€åˆ‡ï¼è¿˜å¯ä»¥ç”¨ +“indentâ€ă€‚ + +ä¸è¿‡ï¼ŒGNU indent 也有和 GNU emacs ä¸€æ ·æœ‰é—®é¢˜ç„设å®ï¼Œæ‰€ä»¥ä½ 需è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ă€‚ä¸ +过,这还ä¸ç®—å¤ªç³Ÿç³•ï¼Œå› ä¸ºå°±ç®—æ˜¯ GNU indent ç„ä½œè€…ä¹Ÿè®¤åŒ K&R ç„æƒå¨æ€§ï¼ˆGNU ç„人并ä¸æ˜¯ +å人,他们åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸è¢«ä¸¥é‡ç„è¯¯å¯¼äº†ï¼‰ï¼Œæ‰€ä»¥ä½ åªè¦ç»™ indent 指å®é€‰é¡¹ “-kr -i8†+(代表 “K&R,8 个å—符缩进â€ï¼‰ï¼Œæˆ–者使用 “scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦ç„æ–¹å¼ ç¼©è¿›æºä»£ç 。 -“indentâ€æœ‰å¾ˆå¤é€‰é¡¹ï¼Œç‰¹åˆ«æ˜¯é‡æ–°æ ¼å¼åŒ–注é‡ç„æ—¶å€™ï¼Œä½ å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒç„æ‰‹å†Œé¡µă€‚ä¸è¿‡ -è®°ä½ï¼â€œindentâ€ä¸èƒ½ä¿®æ£åç„ç¼–ç¨‹ä¹ æƒ¯ă€‚ +“indent†有很å¤é€‰é¡¹ï¼Œç‰¹åˆ«æ˜¯é‡æ–°æ ¼å¼åŒ–注é‡ç„æ—¶å€™ï¼Œä½ å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒç„æ‰‹å†Œé¡µă€‚ä¸è¿‡ +è®°ä½ï¼â€œindent†ä¸èƒ½ä¿®æ£åç„ç¼–ç¨‹ä¹ æƒ¯ă€‚ - 第åç« ï¼Kconfigé…置文件 + 第åç« ï¼Kconfig é…置文件 -对äºé布æºç æ ‘ç„所有Kconfig*é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸C代ç 相比有所ä¸åŒă€‚紧挨 -在“configâ€å®ä¹‰ä¸‹é¢ç„行缩进一个制表符,帮å©ä¿¡æ¯åˆ™å†å¤ç¼©è¿›2ä¸ªç©ºæ ¼ă€‚æ¯”å¦‚ï¼ +对äºé布æºç æ ‘ç„所有 Kconfig* é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸ C 代ç 相比有所ä¸åŒă€‚紧挨 +在 “config†å®ä¹‰ä¸‹é¢ç„行缩进一个制表符,帮å©ä¿¡æ¯åˆ™å†å¤ç¼©è¿› 2 ä¸ªç©ºæ ¼ă€‚æ¯”å¦‚ï¼ config AUDIT bool "Auditing support" @@ -470,7 +505,7 @@ config ADFS_FS_RW depends on ADFS_FS ... -è¦æŸ¥çœ‹é…置文件ç„完整文档,请看Documentation/kbuild/kconfig-language.txt。 +è¦æŸ¥çœ‹é…置文件ç„完整文档,请看 Documentation/kbuild/kconfig-language.txt。 第åä¸€ç« ï¼æ•°æ®ç»“æ„ @@ -489,11 +524,11 @@ config ADFS_FS_RW 很å¤æ•°æ®ç»“æ„å®é™…ä¸æœ‰2级引用计数,它们é€å¸¸æœ‰ä¸åŒâ€œç±»â€ç„ç”¨æˆ·ă€‚å类计数器统计å类用 户ç„æ•°é‡ï¼Œæ¯å½“å类计数器å‡è‡³é›¶æ—¶ï¼Œå…¨å±€è®¡æ•°å™¨å‡ä¸€ă€‚ -è¿™ç§â€œå¤çº§å¼•ç”¨è®¡æ•°â€ç„例åå¯ä»¥åœ¨å†…å˜ç®¡ç†ï¼ˆâ€œstruct mm_structâ€ï¼mm_userså’Œmm_count) +è¿™ç§â€œå¤çº§å¼•ç”¨è®¡æ•°â€ç„例åå¯ä»¥åœ¨å†…å˜ç®¡ç†ï¼ˆâ€œstruct mm_structâ€ï¼mm_users å’Œ mm_count) 和文件系统(“struct super_blockâ€ï¼s_countå’Œs_active)ä¸æ‰¾åˆ°ă€‚ è®°ä½ï¼å¦‚æœå¦ä¸€ä¸ªæ‰§è¡Œçº¿ç´¢å¯ä»¥æ‰¾åˆ°ä½ ç„æ•°æ®ç»“æ„,但是这个数æ®ç»“æ„没有引用计数器,这 -é‡Œå‡ ä¹è‚¯å®æ˜¯ä¸€ä¸ªbug。 +é‡Œå‡ ä¹è‚¯å®æ˜¯ä¸€ä¸ª bug。 第åäºŒç« ï¼å®ï¼Œæ举和RTL @@ -508,102 +543,128 @@ config ADFS_FS_RW 一般ç„,如æœèƒ½å†™æˆå†…è”函数就ä¸è¦å†™æˆåƒå‡½æ•°ç„å®ă€‚ -å«æœ‰å¤ä¸ªè¯å¥ç„å®åº”该被包å«åœ¨ä¸€ä¸ªdo-while代ç å—é‡Œï¼ +å«æœ‰å¤ä¸ªè¯å¥ç„å®åº”该被包å«åœ¨ä¸€ä¸ª do-while 代ç å—é‡Œï¼ -#define macrofun(a, b, c) \ - do { \ - if (a == 5) \ - do_this(b, c); \ - } while (0) + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) 使用å®ç„时候应é¿å…ç„äº‹æƒ…ï¼ 1) å½±å“æ§åˆ¶æµç¨‹ç„å®ï¼ -#define FOO(x) \ - do { \ - if (blah(x) < 0) \ - return -EBUGGERED; \ - } while(0) + #define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while (0) é常ä¸å¥½ă€‚它看起æ¥åƒä¸€ä¸ªå‡½æ•°ï¼Œä¸è¿‡å´èƒ½å¯¼è‡´â€œè°ƒç”¨â€å®ƒç„函数退出;ä¸è¦æ‰“乱读者大脑里 ç„è¯æ³•åˆ†æå™¨ă€‚ 2) ä¾èµ–äºä¸€ä¸ªå›ºå®åå—ç„本地å˜é‡ç„å®ï¼ -#define FOO(val) bar(index, val) + #define FOO(val) bar(index, val) å¯èƒ½çœ‹èµ·æ¥åƒæ˜¯ä¸ªä¸é”™ç„东西,ä¸è¿‡å®ƒé常容易æ读代ç ç„人æç³æ¶‚ï¼Œè€Œä¸”å®¹æ˜“å¯¼è‡´çœ‹èµ·æ¥ ä¸ç›¸å…³ç„改å¨å¸¦æ¥é”™è¯¯ă€‚ -3) 作为左值ç„带å‚æ•°ç„å®ï¼ FOO(x) = y;如æœæœ‰äººæFOOå˜æˆä¸€ä¸ªå†…è”函数ç„è¯ï¼Œè¿™ç§ç”¨ +3) 作为左值ç„带å‚æ•°ç„å®ï¼ FOO(x) = y;如æœæœ‰äººæ FOO å˜æˆä¸€ä¸ªå†…è”函数ç„è¯ï¼Œè¿™ç§ç”¨ 法就ä¼å‡ºé”™äº†ă€‚ 4) 忘记了优先级ï¼ä½¿ç”¨è¡¨è¾¾å¼å®ä¹‰å¸¸é‡ç„å®å¿…须将表达å¼ç½®äºä¸€å¯¹å°æ‹¬å·ä¹‹å†…ă€‚å¸¦å‚æ•°ç„ å®ä¹Ÿè¦æ³¨æ„æ¤ç±»é—®é¢˜ă€‚ -#define CONSTANT 0x4000 -#define CONSTEXP (CONSTANT | 3) + #define CONSTANT 0x4000 + #define CONSTEXP (CONSTANT | 3) + +5) 在å®é‡Œå®ä¹‰ç±»ä¼¼å‡½æ•°ç„本地å˜é‡æ—¶å‘½å冲çªï¼ -cpp手册对å®ç„è®²è§£å¾ˆè¯¦ç»†ă€‚Gcc internals手册也详细讲解了RTL(译注ï¼register + #define FOO(x) \ + ({ \ + typeof(x) ret; \ + ret = calc_ret(x); \ + (ret); \ + }) + +ret 是本地å˜é‡ç„é€ç”¨åå— - __foo_ret æ›´ä¸å®¹æ˜“ä¸ä¸€ä¸ªå·²å˜åœ¨ç„å˜é‡å†²çªă€‚ + +cpp 手册对å®ç„è®²è§£å¾ˆè¯¦ç»†ă€‚gcc internals 手册也详细讲解了 RTL(译注ï¼register transfer languageï¼‰ï¼Œå†…æ ¸é‡Œç„汇编è¯è¨€ç»å¸¸ç”¨åˆ°å®ƒă€‚ 第åä¸‰ç« ï¼æ‰“å°å†…æ ¸æ¶ˆæ¯ å†…æ ¸å¼€å‘者应该是å—过良好教育ç„ă€‚è¯·ä¸€å®æ³¨æ„å†…æ ¸ä¿¡æ¯ç„拼写,以给人以好ç„å°è±¡ă€‚ä¸è¦ -用ä¸è§„范ç„å•è¯æ¯”如“dontâ€ï¼Œè€Œè¦ç”¨â€œdo notâ€æˆ–者“don'tâ€ă€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ă€æ˜äº†ă€æ— -æ§ä¹‰ă€‚ +用ä¸è§„范ç„å•è¯æ¯”如 “dontâ€ï¼Œè€Œè¦ç”¨ “do notâ€æˆ–者 “don'tâ€ă€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ă€æ˜äº†ă€ +æ— æ§ä¹‰ă€‚ å†…æ ¸ä¿¡æ¯ä¸å¿…以å¥å·ï¼ˆè¯‘注ï¼è‹±æ–‡å¥å·ï¼Œå³ç‚¹ï¼‰ç»“æŸă€‚ -在å°æ‹¬å·é‡Œæ‰“å°æ•°å—(%d)没有任何价值,应该é¿å…è¿™æ ·å。 +在å°æ‹¬å·é‡Œæ‰“å°æ•°å— (%d) 没有任何价值,应该é¿å…è¿™æ ·å。 -<linux/device.h>里有一些驱å¨æ¨¡å‹è¯æ–å®ï¼Œä½ 应该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”äºæ£ç¡®ç„ -设备和驱å¨ï¼Œå¹¶ä¸”è¢«æ ‡è®°äº†æ£ç¡®ç„消æ¯çº§åˆ«ă€‚这些å®æœ‰ï¼dev_err(), dev_warn(), -dev_info()ç‰ç‰ă€‚对äºé‚£äº›ä¸å’ŒæŸä¸ªç‰¹å®è®¾å¤‡ç›¸å…³è¿ç„ä¿¡æ¯ï¼Œ<linux/kernel.h>å®ä¹‰äº† -pr_debug()å’Œpr_info()。 +<linux/device.h> 里有一些驱å¨æ¨¡å‹è¯æ–å®ï¼Œä½ 应该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”äºæ£ç¡®ç„ +设备和驱å¨ï¼Œå¹¶ä¸”è¢«æ ‡è®°äº†æ£ç¡®ç„消æ¯çº§åˆ«ă€‚这些å®æœ‰ï¼dev_err(),dev_warn(), +dev_info() ç‰ç‰ă€‚对äºé‚£äº›ä¸å’ŒæŸä¸ªç‰¹å®è®¾å¤‡ç›¸å…³è¿ç„ä¿¡æ¯ï¼Œ<linux/printk.h> å®ä¹‰äº† +pr_notice(),pr_info(),pr_warn(),pr_err() å’Œå…¶ä»–ă€‚ -写出好ç„调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§ç„æŒ‘æˆ˜ï¼›å½“ä½ å†™å‡ºæ¥ä¹‹å,这些信æ¯åœ¨è¿œç¨‹é™¤é”™ç„时候 -å°±ä¼æˆä¸ºæ大ç„帮å©ă€‚当DEBUG符å·æ²¡æœ‰è¢«å®ä¹‰ç„时候,这些信æ¯ä¸åº”è¯¥è¢«ç¼–è¯‘è¿›å†…æ ¸é‡Œ -(也就是说,默认地,它们ä¸åº”该被包å«åœ¨å†…ï¼‰ă€‚å¦‚æœä½ 使用dev_dbg()或者pr_debug(), -就能自å¨è¾¾åˆ°è¿™ä¸ªæ•ˆæœă€‚很å¤å系统拥有Kconfig选项æ¥å¯ç”¨-DDEBUGă€‚è¿˜æœ‰ä¸€ä¸ªç›¸å…³ç„惯例 -是使用VERBOSE_DEBUGæ¥æ·»å dev_vdbg()消æ¯åˆ°é‚£äº›å·²ç»ç”±DEBUGå¯ç”¨ç„消æ¯ä¹‹ä¸ă€‚ +写出好ç„调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§ç„æŒ‘æˆ˜ï¼›ä¸€æ—¦ä½ å†™å‡ºå,这些信æ¯åœ¨è¿œç¨‹é™¤é”™æ—¶èƒ½æä¾›æ大 +ç„帮å©ă€‚然而打å°è°ƒè¯•ä¿¡æ¯ç„处ç†æ–¹å¼åŒæ‰“å°é调试信æ¯ä¸åŒă€‚其他 pr_XXX() å‡½æ•°èƒ½æ— æ¡ä»¶åœ° +打å°ï¼Œpr_debug() å´ä¸ï¼›é»˜è®¤æƒ…况下它ä¸ä¼è¢«ç¼–译,除éå®ä¹‰äº† DEBUG 或设å®äº† +CONFIG_DYNAMIC_DEBUG。å®é™…è¿™åŒæ ·æ˜¯ä¸ºäº† dev_dbg(),一个相关约å®æ˜¯åœ¨ä¸€ä¸ªå·²ç»å¼€å¯äº† +DEBUG 时,使用 VERBOSE_DEBUG æ¥æ·»å dev_vdbg()。 + +许å¤å系统拥有 Kconfig 调试选项æ¥å¼€å¯ -DDEBUG åœ¨å¯¹åº”ç„ Makefile 里é¢ï¼›åœ¨å…¶ä»– +情况下,特æ®æ–‡ä»¶ä½¿ç”¨ #define DEBUGă€‚å½“ä¸€æ¡è°ƒè¯•ä¿¡æ¯éœ€è¦è¢«æ— æ¡ä»¶æ‰“å°æ—¶ï¼Œä¾‹å¦‚ï¼Œå¦‚æœ +å·²ç»åŒ…å«ä¸€ä¸ªè°ƒè¯•ç›¸å…³ç„ #ifdef æ¡ä»¶ï¼Œprintk(KERN_DEBUG ...) å°±å¯è¢«ä½¿ç”¨ă€‚ 第åå››ç« ï¼åˆ†é…å†…å˜ -å†…æ ¸æ供了下é¢ç„一般用途ç„内å˜åˆ†é…函数ï¼kmalloc(),kzalloc(),kcalloc()å’Œ -vmalloc()ă€‚è¯·å‚考API文档以è·å–有关它们ç„详细信æ¯ă€‚ +å†…æ ¸æ供了下é¢ç„一般用途ç„内å˜åˆ†é…å‡½æ•°ï¼ +kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc() å’Œ vzalloc()。 +请å‚考 API 文档以è·å–有关它们ç„详细信æ¯ă€‚ ä¼ é€’ç»“æ„体大å°ç„首选形å¼æ˜¯è¿™æ ·ç„ï¼ p = kmalloc(sizeof(*p), ...); -å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeofç„æ“作数是结æ„体ç„åå—ï¼Œè¿™æ ·ä¼é™ä½å¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼å¼• -å…¥bugă€‚æœ‰å¯èƒ½æŒ‡é’ˆå˜é‡ç±»å‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”ç„ä¼ é€’ç»™å†…å˜åˆ†é…函数ç„sizeofç„结æœä¸å˜ă€‚ +å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeof ç„æ“作数是结æ„体ç„åå—ï¼Œè¿™æ ·ä¼é™ä½å¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼å¼• +å…¥ bugă€‚æœ‰å¯èƒ½æŒ‡é’ˆå˜é‡ç±»å‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”ç„ä¼ é€’ç»™å†…å˜åˆ†é…å‡½æ•°ç„ sizeof ç„结æœä¸å˜ă€‚ -强制转æ¢ä¸€ä¸ªvoid指针返å›å€¼æ˜¯å¤ä½™ç„。Cè¯è¨€æœ¬èº«ä¿è¯äº†ä»voidæŒ‡é’ˆåˆ°å…¶ä»–ä»»ä½•æŒ‡é’ˆç±»å‹ +强制转æ¢ä¸€ä¸ª void 指针返å›å€¼æ˜¯å¤ä½™ç„。C è¯è¨€æœ¬èº«ä¿è¯äº†ä» void æŒ‡é’ˆåˆ°å…¶ä»–ä»»ä½•æŒ‡é’ˆç±»å‹ ç„转æ¢æ˜¯æ²¡æœ‰é—®é¢˜ç„。 +分é…一个数组ç„首选形å¼æ˜¯è¿™æ ·ç„ï¼ + + p = kmalloc_array(n, sizeof(...), ...); + +分é…一个零长数组ç„首选形å¼æ˜¯è¿™æ ·ç„ï¼ + + p = kcalloc(n, sizeof(...), ...); + +两ç§å½¢å¼æ£€æŸ¥åˆ†é…å¤§å° n * sizeof(...) ç„溢出,如æœæº¢å‡ºè¿”å› NULL。 + 第åäº”ç« ï¼å†…è”å¼ç—… -有一个常è§ç„误解是内è”函数是gccæä¾›ç„å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«ç„ä¸€ä¸ªé€‰é¡¹ă€‚è™½ç„¶ä½¿ç”¨å†…è” +有一个常è§ç„误解是内è”函数是 gcc æä¾›ç„å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«ç„ä¸€ä¸ªé€‰é¡¹ă€‚è™½ç„¶ä½¿ç”¨å†…è” å‡½æ•°æœ‰æ—¶å€™æ˜¯æ°å½“ç„(比如作为一ç§æ›¿ä»£å®ç„æ–¹å¼ï¼Œè¯·çœ‹ç¬¬åäºŒç« ï¼‰ï¼Œä¸è¿‡å¾ˆå¤æƒ…况下ä¸æ˜¯ -è¿™æ ·ă€‚inline关键å—ç„过度使用ä¼ä½¿å†…æ ¸å˜å¤§ï¼Œä»è€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ă€‚å› ä¸ºå¤§å†…æ ¸ +è¿™æ ·ă€‚inline 关键å—ç„过度使用ä¼ä½¿å†…æ ¸å˜å¤§ï¼Œä»è€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ă€‚å› ä¸ºå¤§å†…æ ¸ ä¼å 用更å¤ç„指令高速缓å˜ï¼ˆè¯‘注ï¼ä¸€çº§ç¼“å˜é€å¸¸æ˜¯æŒ‡ä»¤ç¼“å˜å’Œæ•°æ®ç¼“å˜åˆ†å¼€ç„)而且ä¼å¯¼ -致pagecacheç„å¯ç”¨å†…å˜å‡å°‘ă€‚æƒ³è±¡ä¸€ä¸‹ï¼Œä¸€æ¬¡pagecache未命ä¸å°±ä¼å¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œå°† -耗时5æ¯«ç§’ă€‚5毫秒ç„时间内CPU能执行很å¤å¾ˆå¤æŒ‡ä»¤ă€‚ +致 pagecache ç„å¯ç”¨å†…å˜å‡å°‘ă€‚æƒ³è±¡ä¸€ä¸‹ï¼Œä¸€æ¬¡pagecache未命ä¸å°±ä¼å¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œ +将耗时 5 æ¯«ç§’ă€‚5 毫秒ç„时间内 CPU 能执行很å¤å¾ˆå¤æŒ‡ä»¤ă€‚ -一个基本ç„åŸåˆ™æ˜¯å¦‚æœä¸€ä¸ªå‡½æ•°æœ‰3行以ä¸ï¼Œå°±ä¸è¦æ它å˜æˆå†…è”å‡½æ•°ă€‚è¿™ä¸ªåŸåˆ™ç„一个例 +一个基本ç„åŸåˆ™æ˜¯å¦‚æœä¸€ä¸ªå‡½æ•°æœ‰ 3 行以ä¸ï¼Œå°±ä¸è¦æ它å˜æˆå†…è”å‡½æ•°ă€‚è¿™ä¸ªåŸåˆ™ç„一个例 外是,如æœä½ 知é“æŸä¸ªå‚数是一个编译时常é‡ï¼Œè€Œä¸”å› ä¸ºè¿™ä¸ªå¸¸é‡ä½ ç¡®å®ç¼–译器在编译时能 -优化æ‰ä½ ç„函数ç„大部分代ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒå ä¸inline关键å—。kmalloc()内è”函数就 +优化æ‰ä½ ç„函数ç„大部分代ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒå ä¸ inline 关键å—。kmalloc() 内è”函数就 是一个很好ç„例å。 -人们ç»å¸¸ä¸»å¼ ç»™staticç„而且åªç”¨äº†ä¸€æ¬¡ç„函数å ä¸inline,如æ¤ä¸ä¼æœ‰ä»»ä½•æŸå¤±ï¼Œå› 为没 -有什么好æƒè¡¡ç„ă€‚è™½ç„¶ä»æ€æœ¯ä¸è¯´è¿™æ˜¯æ£ç¡®ç„,但是å®é™…ä¸è¿™ç§æƒ…况下å³ä½¿ä¸å inline gcc -也å¯ä»¥è‡ªå¨ä½¿å…¶å†…è”ă€‚è€Œä¸”å…¶ä»–ç”¨æˆ·å¯èƒ½ä¼è¦æ±‚移除inline,由æ¤è€Œæ¥ç„争论ä¼æµæ¶ˆinline +人们ç»å¸¸ä¸»å¼ ç»™ static ç„而且åªç”¨äº†ä¸€æ¬¡ç„函数å ä¸ inline,如æ¤ä¸ä¼æœ‰ä»»ä½•æŸå¤±ï¼Œå› 为没 +有什么好æƒè¡¡ç„ă€‚è™½ç„¶ä»æ€æœ¯ä¸è¯´è¿™æ˜¯æ£ç¡®ç„,但是å®é™…ä¸è¿™ç§æƒ…况下å³ä½¿ä¸å inline gcc +也å¯ä»¥è‡ªå¨ä½¿å…¶å†…è”ă€‚è€Œä¸”å…¶ä»–ç”¨æˆ·å¯èƒ½ä¼è¦æ±‚移除 inline,由æ¤è€Œæ¥ç„争论ä¼æµæ¶ˆ inline 自身ç„潜在价值,得ä¸å¿å¤±ă€‚ @@ -613,37 +674,37 @@ vmalloc()ă€‚è¯·å‚考API文档以è·å–有关它们ç„详细信æ¯ă€‚ ç„一个值å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªé”™è¯¯ä»£ç 整数(-Exxxï¼å¤±è´¥ï¼Œ0ï¼æˆåŸï¼‰æˆ–者一个“æˆåŸâ€å¸ƒå°”值( 0ï¼å¤±è´¥ï¼Œé0ï¼æˆåŸï¼‰ă€‚ -æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯é¾äºå‘ç°ç„bugç„æ¥æºă€‚如æœCè¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œå¸ƒå°”å‹å˜ -é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘ç°è¿™äº›é”™è¯¯â€¦â€¦ä¸è¿‡Cè¯è¨€ä¸åŒºåˆ†ă€‚为了é¿å…产生这ç§bug,请 +æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯é¾äºå‘ç°ç„ bug ç„æ¥æºă€‚å¦‚æœ C è¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œå¸ƒå°”å‹å˜ +é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘ç°è¿™äº›é”™è¯¯â€¦â€¦ä¸è¿‡ C è¯è¨€ä¸åŒºåˆ†ă€‚为了é¿å…äº§ç”Ÿè¿™ç§ bug,请 éµå¾ªä¸‹é¢ç„æƒ¯ä¾‹ï¼ å¦‚æœå‡½æ•°ç„åå—是一个å¨ä½œæˆ–者强制性ç„命令,那么这个函数应该返å›é”™è¯¯ä»£ç æ•´ æ•°ă€‚å¦‚æœæ˜¯ä¸€ä¸ªåˆ¤æ–,那么函数应该返å›ä¸€ä¸ªâ€œæˆåŸâ€å¸ƒå°”å€¼ă€‚ -比如,“add workâ€æ˜¯ä¸€ä¸ªå‘½ä»¤ï¼Œæ‰€ä»¥add_work()函数在æˆåŸæ—¶è¿”å›0,在失败时返å›-EBUSY。 -类似ç„ï¼Œå› ä¸ºâ€œPCI device presentâ€æ˜¯ä¸€ä¸ªåˆ¤æ–,所以pci_dev_present()函数在æˆåŸæ‰¾åˆ° -一个匹é…ç„设备时应该返å›1,如æœæ‰¾ä¸åˆ°æ—¶åº”该返å›0。 +比如,“add work†是一个命令,所以 add_work() 函数在æˆåŸæ—¶è¿”å› 0ï¼Œåœ¨å¤±è´¥æ—¶è¿”å› -EBUSY。 +类似ç„ï¼Œå› ä¸º “PCI device present†是一个判æ–,所以 pci_dev_present() 函数在æˆåŸæ‰¾åˆ° +一个匹é…ç„è®¾å¤‡æ—¶åº”è¯¥è¿”å› 1,如æœæ‰¾ä¸åˆ°æ—¶åº”è¯¥è¿”å› 0。 所有导出(译注ï¼EXPORT)ç„函数都必须éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ï¼Œæ‰€æœ‰ç„公共函数也都应该如æ¤ă€‚ç§ æœ‰ï¼ˆstatic)函数ä¸éœ€è¦å¦‚æ¤ï¼Œä½†æ˜¯æˆ‘们也æ¨èè¿™æ ·å。 è¿”å›å€¼æ˜¯å®é™…计算结æœè€Œä¸æ˜¯è®¡ç®—是å¦æˆåŸç„æ ‡å¿—ç„函数ä¸å—æ¤æƒ¯ä¾‹ç„é™åˆ¶ă€‚一般ç„,他们 é€è¿‡è¿”å›ä¸€äº›æ£å¸¸å€¼èŒƒå›´ä¹‹å¤–ç„结æœæ¥è¡¨ç¤ºå‡ºé”™ă€‚å…¸å‹ç„例å是返å›æŒ‡é’ˆç„函数,他们使用 -NULL或者ERR_PTR机制æ¥æ¥å‘é”™è¯¯ă€‚ +NULL 或者 ERR_PTR 机制æ¥æ¥å‘é”™è¯¯ă€‚ 第åä¸ƒç« ï¼ä¸è¦é‡æ–°å‘æ˜å†…æ ¸å® -头文件include/linux/kernel.h包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬ç„ +头文件 include/linux/kernel.h 包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬ç„ å˜ç§ă€‚比如,如æœä½ 需è¦è®¡ç®—一个数组ç„é•¿åº¦ï¼Œä½¿ç”¨è¿™ä¸ªå® - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 类似ç„,如æœä½ è¦è®¡ç®—æŸç»“æ„体æˆå‘˜ç„大å°ï¼Œä½¿ç”¨ - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) -还有å¯ä»¥åä¸¥æ ¼ç„ç±»å‹æ£€æŸ¥ç„min()å’Œmax()å®ï¼Œå¦‚æœä½ 需è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ă€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹ +还有å¯ä»¥åä¸¥æ ¼ç„ç±»å‹æ£€æŸ¥ç„ min() å’Œ max() å®ï¼Œå¦‚æœä½ 需è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ă€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹ 那个头文件里还å®ä¹‰äº†ä»€ä¹ˆä½ å¯ä»¥æ‹¿æ¥ç”¨ç„东西,如æœæœ‰å®ä¹‰ç„è¯ï¼Œä½ å°±ä¸åº”åœ¨ä½ ç„代ç 里 自己é‡æ–°å®ä¹‰ă€‚ @@ -653,42 +714,100 @@ NULL或者ERR_PTR机制æ¥æ¥å‘é”™è¯¯ă€‚ 有一些编辑器å¯ä»¥è§£é‡åµŒå…¥åœ¨æºæ–‡ä»¶é‡Œç„由一些特æ®æ ‡è®°æ ‡æ˜ç„é…置信æ¯ă€‚比如,emacs 能够解é‡è¢«æ ‡è®°æˆè¿™æ ·ç„è¡Œï¼ --*- mode: c -*- + -*- mode: c -*- æˆ–è€…è¿™æ ·ç„ï¼ -/* -Local Variables: -compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" -End: -*/ + /* + Local Variables: + compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" + End: + */ -Vim能够解é‡è¿™æ ·ç„æ ‡è®°ï¼ +Vim 能够解é‡è¿™æ ·ç„æ ‡è®°ï¼ -/* vim:set sw=8 noet */ + /* vim:set sw=8 noet */ ä¸è¦åœ¨æºä»£ç ä¸åŒ…å«ä»»ä½•è¿™æ ·ç„å†…å®¹ă€‚æ¯ä¸ªäººéƒ½æœ‰ä»–自己ç„编辑器é…ç½®ï¼Œä½ ç„æºæ–‡ä»¶ä¸åº” 该覆盖别人ç„é…ç½®ă€‚è¿™åŒ…æ‹¬æœ‰å…³ç¼©è¿›å’Œæ¨¡å¼é…ç½®ç„æ ‡è®°ă€‚äººä»¬å¯ä»¥ä½¿ç”¨ä»–们自己å®åˆ¶ç„模 å¼ï¼Œæˆ–者使用其他å¯ä»¥äº§ç”Ÿæ£ç¡®ç„缩进ç„å·§å¦™æ–¹æ³•ă€‚ + 第åä¹ç« ï¼å†…è”汇编 + +在特å®æ¶æ„ç„代ç ä¸ï¼Œä½ 也许需è¦å†…è”汇编æ¥ä½¿ç”¨ CPU æ¥å£å’Œå¹³å°ç›¸å…³åŸèƒ½ă€‚åœ¨éœ€è¦ +这么å时,ä¸è¦ç¹è±«ă€‚然而,当 C å¯ä»¥å®Œæˆå·¥ä½œæ—¶ï¼Œä¸è¦æ— 端地使用内è”æ±‡ç¼–ă€‚å¦‚æœ +å¯èƒ½ï¼Œä½ å¯ä»¥å¹¶ä¸”应该用 C å’Œç¡¬ä»¶äº¤äº’ă€‚ + +考虑å»å†™é€ç”¨ä¸€ç‚¹ç„内è”汇编作为简æ˜ç„è¾…å©å‡½æ•°ï¼Œè€Œä¸æ˜¯é‡å¤å†™ä¸‹å®ƒä»¬ç„细è‚ă€‚è®°ä½ +内è”汇编å¯ä»¥ä½¿ç”¨ C å‚æ•°ă€‚ + +大而特æ®ç„汇编函数应该放在 .S 文件ä¸ï¼Œå¯¹åº” C ç„åŸå‹å®ä¹‰åœ¨ C 头文件ä¸ă€‚汇编 +å‡½æ•°ç„ C åŸå‹åº”该使用 “asmlinkageâ€ă€‚ + +ä½ å¯èƒ½éœ€è¦å°†ä½ ç„汇编è¯å¥æ ‡è®°ä¸º volatile,æ¥é˜»æ¢ GCC 在没å‘ç°ä»»ä½•å‰¯ä½œç”¨åå°± +ç§»é™¤äº†å®ƒă€‚ä½ ä¸å¿…æ€»æ˜¯è¿™æ ·åï¼Œè™½ç„¶ï¼Œè¿™æ ·å¯ä»¥é™åˆ¶ä¸å¿…è¦ç„ä¼˜åŒ–ă€‚ + +在写一个包å«å¤æ¡æŒ‡ä»¤ç„å•ä¸ªå†…è”汇编è¯å¥æ—¶ï¼Œææ¯æ¡æŒ‡ä»¤ç”¨å¼•å·å—符串分离,并写在 +å•ç‹¬ä¸€è¡Œï¼Œåœ¨æ¯ä¸ªå—符串结尾,除了 \n\t 结尾之外,在汇编输出ä¸é€‚当地缩进下 +一æ¡æŒ‡ä»¤ï¼ + + asm ("magic %reg1, #42\n\t" + "more_magic %reg2, %reg3" + : /* outputs */ : /* inputs */ : /* clobbers */); + + + 第二åç« ï¼æ¡ä»¶ç¼–译 + +åªè¦å¯èƒ½ï¼Œå°±ä¸è¦åœ¨ .c 文件里é¢ä½¿ç”¨é¢„处ç†æ¡ä»¶ï¼›è¿™æ ·å让代ç æ›´é¾é˜…读并且逻辑é¾ä»¥ +è·Ÿè¸ªă€‚æ›¿ä»£æ–¹æ¡ˆæ˜¯ï¼Œåœ¨å¤´æ–‡ä»¶å®ä¹‰å‡½æ•°åœ¨è¿™äº› .c 文件ä¸ä½¿ç”¨è¿™ç±»ç„æ¡ä»¶è¡¨è¾¾å¼ï¼Œæ供空 +æ“作ç„桩版本(译注ï¼æ¡©ç¨‹åºï¼Œæ˜¯æŒ‡ç”¨æ¥æ›¿æ¢ä¸€éƒ¨åˆ†åŸèƒ½ç„程åºæ®µï¼‰åœ¨ #else 情况下, +å†ä» .c 文件ä¸æ— æ¡ä»¶åœ°è°ƒç”¨è¿™äº›å‡½æ•°ă€‚编译器ä¼é¿å…生æˆä»»ä½•æ¡©è°ƒç”¨ç„代ç ,产生一致 +ç„结æœï¼Œä½†é€»è¾‘将更å æ¸…æ™°ă€‚ + +å®å¯ç¼–译整个函数,而ä¸æ˜¯éƒ¨åˆ†å‡½æ•°æˆ–部分表达å¼ă€‚而ä¸æ˜¯åœ¨ä¸€ä¸ªè¡¨è¾¾å¼æ·»å ifdef, +解æ部分或全部表达å¼åˆ°ä¸€ä¸ªå•ç‹¬ç„è¾…å©å‡½æ•°ï¼Œå¹¶åº”用æ¡ä»¶åˆ°è¯¥å‡½æ•°å†…。 + +如æœä½ 有一个在特å®é…ç½®ä¸å¯èƒ½æ˜¯æœªä½¿ç”¨ç„函数或å˜é‡ï¼Œç¼–译器将è¦å‘它å®ä¹‰äº†ä½†æœªä½¿ç”¨ï¼Œ +æ ‡è®°è¿™ä¸ªå®ä¹‰ä¸º __maybe_unused 而ä¸æ˜¯å°†å®ƒåŒ…å«åœ¨ä¸€ä¸ªé¢„处ç†æ¡ä»¶ä¸ă€‚ï¼ˆç„¶è€Œï¼Œå¦‚æœ +一个函数或å˜é‡æ€»æ˜¯æœªä½¿ç”¨ç„,就直æ¥åˆ é™¤å®ƒă€‚ï¼‰ + +在代ç ä¸ï¼Œå¯èƒ½ç„情况下,使用 IS_ENABLED å®æ¥è½¬åŒ–æŸä¸ª Kconfig æ ‡è®°ä¸º C ç„布尔 +表达å¼ï¼Œå¹¶åœ¨æ£å¸¸ç„ C æ¡ä»¶ä¸ä½¿ç”¨å®ƒï¼ + + if (IS_ENABLED(CONFIG_SOMETHING)) { + ... + } + +编译器ä¼æ— æ¡ä»¶åœ°å常数åˆå¹¶ï¼Œå°±åƒä½¿ç”¨ #ifdef é‚£æ ·ï¼ŒåŒ…å«æˆ–æ’除代ç å—,所以这ä¸ä¼ +带æ¥ä»»ä½•è¿è¡Œæ—¶å¼€é”€ă€‚然而,这ç§æ–¹æ³•ä¾æ—§å…许 C 编译器查看å—内ç„代ç ,并检查它ç„æ£ç¡® +性(è¯æ³•ï¼Œç±»å‹ï¼Œç¬¦å·å¼•ç”¨ï¼Œç‰ç‰ï¼‰ă€‚å› æ¤ï¼Œå¦‚æœæ¡ä»¶ä¸æ»¡è¶³ï¼Œä»£ç å—内ç„引用符å·å°†ä¸å˜åœ¨ï¼Œ +ä½ å¿…é¡»ç»§ç»ä½¿ç”¨ #ifdef。 + +在任何有æ„ä¹‰ç„ #if 或 #ifdef å—ç„æœ«å°¾ï¼ˆè¶…è¿‡å‡ è¡Œï¼‰ï¼Œåœ¨ #endif åŒä¸€è¡Œç„åé¢å†™ä¸‹ +注é‡ï¼ŒæŒ‡å‡ºè¯¥æ¡ä»¶è¡¨è¾¾å¼è¢«ä½¿ç”¨ă€‚ä¾‹å¦‚ï¼ + + #ifdef CONFIG_SOMETHING + ... + #endif /* CONFIG_SOMETHING */ + 附录 Iï¼å‚考 -The C Programming Language, 第二版, 作者Brian W. Kernighanå’ŒDenni -M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软ç®), -0-13-110370-9 (硬ç®). URL: http://cm.bell-labs.com/cm/cs/cbook/ +The C Programming Language, 第二版 +作者ï¼Brian W. Kernighan å’Œ Denni M. Ritchie. +Prentice Hall, Inc., 1988. +ISBN 0-13-110362-8 (软ç®), 0-13-110370-9 (硬ç®). -The Practice of Programming 作者Brian W. Kernighanå’ŒRob Pike. Addison-Wesley, -Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/ +The Practice of Programming +作者ï¼Brian W. Kernighan å’Œ Rob Pike. +Addison-Wesley, Inc., 1999. +ISBN 0-201-61586-X. -cpp,gcc,gcc internalså’Œindentç„GNU手册——和K&Rå本文相符åˆç„部分,全部å¯ä»¥åœ¨ -http://www.gnu.org/manual/找到 +GNU 手册 - éµå¾ª K&R æ ‡å‡†å’Œæ¤æ–‡æœ¬ - cpp, gcc, gcc internals and indent, +都å¯ä»¥ä» http://www.gnu.org/manual/ 找到 WG14是Cè¯è¨€ç„å›½é™…æ ‡å‡†åŒ–å·¥ä½œç»„ï¼ŒURL: http://www.open-std.org/JTC1/SC22/WG14/ -Kernel CodingStyle,作者greg@kroah.comå‘表äºOLS 2002ï¼ +Kernel CodingStyle,作者 greg@kroah.com å‘表äºOLS 2002ï¼ http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ - --- -最åæ›´æ–°äº2007å¹´7月13æ—¥ă€‚ @@ -1412,8 +1412,11 @@ $(help-board-dirs): help-%: # Documentation targets # --------------------------------------------------------------------------- -%docs: scripts_basic FORCE +DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs +PHONY += $(DOC_TARGETS) +$(DOC_TARGETS): scripts_basic FORCE $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype + $(Q)$(MAKE) $(build)=Documentation -f $(srctree)/Documentation/Makefile.sphinx $@ $(Q)$(MAKE) $(build)=Documentation/DocBook $@ else # KBUILD_EXTMOD diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index be43afb..e3dba6f 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -8,7 +8,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_lock.o drm_memory.o drm_drv.o drm_vm.o \ drm_scatter.o drm_pci.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ - drm_crtc.o drm_modes.o drm_edid.o \ + drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ @@ -23,7 +23,8 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ - drm_kms_helper_common.o drm_dp_dual_mode_helper.o + drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ + drm_simple_kms_helper.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 0b5f3ac..a6eecf6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -268,7 +268,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, return 0; vblank_cleanup: - drm_crtc_vblank_put(&amdgpu_crtc->base); + drm_crtc_vblank_put(crtc); pflip_cleanup: if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) { diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 112e358..c1b04e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2719,13 +2719,13 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); - drm_vblank_on(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_on(crtc); dce_v10_0_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_off(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (amdgpu_crtc->enabled) { dce_v10_0_vga_enable(crtc, true); amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index b522fa2..c90408b 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2730,13 +2730,13 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); - drm_vblank_on(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_on(crtc); dce_v11_0_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_off(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (amdgpu_crtc->enabled) { dce_v11_0_vga_enable(crtc, true); amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index b50ed72..300ff4a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2626,13 +2626,13 @@ static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); - drm_vblank_on(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_on(crtc); dce_v8_0_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_off(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (amdgpu_crtc->enabled) { dce_v8_0_vga_enable(crtc, true); amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE); diff --git a/drivers/gpu/drm/arc/arcpgu.h b/drivers/gpu/drm/arc/arcpgu.h index 329ac75..e8fcf3a 100644 --- a/drivers/gpu/drm/arc/arcpgu.h +++ b/drivers/gpu/drm/arc/arcpgu.h @@ -22,7 +22,6 @@ struct arcpgu_drm_private { struct clk *clk; struct drm_fbdev_cma *fbdev; struct drm_framebuffer *fb; - struct list_head event_list; struct drm_crtc crtc; struct drm_plane *plane; }; diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index 92f8bef..ee0a61c 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -145,20 +145,14 @@ static int arc_pgu_crtc_atomic_check(struct drm_crtc *crtc, static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *state) { - struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc); - unsigned long flags; - - if (crtc->state->event) { - struct drm_pending_vblank_event *event = crtc->state->event; + struct drm_pending_vblank_event *event = crtc->state->event; + if (event) { crtc->state->event = NULL; - event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - spin_lock_irqsave(&crtc->dev->event_lock, flags); - list_add_tail(&event->base.link, &arcpgu->event_list); - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); } } diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 07c1bde..381c5fc 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c @@ -32,17 +32,11 @@ static void arcpgu_fb_output_poll_changed(struct drm_device *dev) drm_fbdev_cma_hotplug_event(arcpgu->fbdev); } -static int arcpgu_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, bool async) -{ - return drm_atomic_helper_commit(dev, state, false); -} - static struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = arcpgu_fb_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = arcpgu_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static void arcpgu_setup_mode_config(struct drm_device *drm) @@ -81,22 +75,6 @@ static const struct file_operations arcpgu_drm_ops = { .mmap = arcpgu_gem_mmap, }; -static void arcpgu_preclose(struct drm_device *drm, struct drm_file *file) -{ - struct arcpgu_drm_private *arcpgu = drm->dev_private; - struct drm_pending_vblank_event *e, *t; - unsigned long flags; - - spin_lock_irqsave(&drm->event_lock, flags); - list_for_each_entry_safe(e, t, &arcpgu->event_list, base.link) { - if (e->base.file_priv != file) - continue; - list_del(&e->base.link); - kfree(&e->base); - } - spin_unlock_irqrestore(&drm->event_lock, flags); -} - static void arcpgu_lastclose(struct drm_device *drm) { struct arcpgu_drm_private *arcpgu = drm->dev_private; @@ -122,8 +100,6 @@ static int arcpgu_load(struct drm_device *drm) if (IS_ERR(arcpgu->clk)) return PTR_ERR(arcpgu->clk); - INIT_LIST_HEAD(&arcpgu->event_list); - arcpgu_setup_mode_config(drm); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -193,7 +169,6 @@ int arcpgu_unload(struct drm_device *drm) static struct drm_driver arcpgu_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, - .preclose = arcpgu_preclose, .lastclose = arcpgu_lastclose, .name = "drm-arcpgu", .desc = "ARC PGU Controller", diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c index 08b6bae..b7a8b2a 100644 --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c @@ -46,23 +46,6 @@ static int arcpgu_drm_connector_get_modes(struct drm_connector *connector) return sfuncs->get_modes(&slave->base, connector); } -struct drm_encoder * -arcpgu_drm_connector_best_encoder(struct drm_connector *connector) -{ - struct drm_encoder_slave *slave; - struct arcpgu_drm_connector *con = - container_of(connector, struct arcpgu_drm_connector, connector); - - slave = con->encoder_slave; - if (slave == NULL) { - dev_err(connector->dev->dev, - "connector_best_encoder: cannot find slave encoder for connector\n"); - return NULL; - } - - return &slave->base; -} - static enum drm_connector_status arcpgu_drm_connector_detect(struct drm_connector *connector, bool force) { @@ -97,7 +80,6 @@ static void arcpgu_drm_connector_destroy(struct drm_connector *connector) static const struct drm_connector_helper_funcs arcpgu_drm_connector_helper_funcs = { .get_modes = arcpgu_drm_connector_get_modes, - .best_encoder = arcpgu_drm_connector_best_encoder, }; static const struct drm_connector_funcs arcpgu_drm_connector_funcs = { diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 49e586d..74279be 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -106,17 +106,11 @@ static void hdlcd_fb_output_poll_changed(struct drm_device *drm) drm_fbdev_cma_hotplug_event(hdlcd->fbdev); } -static int hdlcd_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, bool nonblock) -{ - return drm_atomic_helper_commit(dev, state, false); -} - static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = hdlcd_fb_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = hdlcd_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static void hdlcd_setup_mode_config(struct drm_device *drm) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 6485fa5..9ecf16c 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -519,7 +519,7 @@ static int atmel_hlcdc_dc_atomic_commit(struct drm_device *dev, } /* Swap the state, this is the point of no return. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); if (async) queue_work(dc->wq, &commit->work); diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index 39802c0..473a475 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -113,21 +113,9 @@ static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector, return atmel_hlcdc_dc_mode_valid(rgb->dc, mode); } - - -static struct drm_encoder * -atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector) -{ - struct atmel_hlcdc_rgb_output *rgb = - drm_connector_to_atmel_hlcdc_rgb_output(connector); - - return &rgb->encoder; -} - static const struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = { .get_modes = atmel_hlcdc_panel_get_modes, .mode_valid = atmel_hlcdc_rgb_mode_valid, - .best_encoder = atmel_hlcdc_rgb_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index d087b05..f9f03bc 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -986,16 +986,8 @@ unlock: return num_modes; } -static struct drm_encoder *anx78xx_best_encoder(struct drm_connector *connector) -{ - struct anx78xx *anx78xx = connector_to_anx78xx(connector); - - return anx78xx->bridge.encoder; -} - static const struct drm_connector_helper_funcs anx78xx_connector_helper_funcs = { .get_modes = anx78xx_get_modes, - .best_encoder = anx78xx_best_encoder, }; static enum drm_connector_status anx78xx_detect(struct drm_connector *connector, diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index c9d9412..70b1f7d 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1476,15 +1476,6 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector, return mode_status; } -static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector - *connector) -{ - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); - - return hdmi->encoder; -} - static void dw_hdmi_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); @@ -1525,7 +1516,7 @@ static const struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = { static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .get_modes = dw_hdmi_connector_get_modes, .mode_valid = dw_hdmi_connector_mode_valid, - .best_encoder = dw_hdmi_connector_best_encoder, + .best_encoder = drm_atomic_helper_best_encoder, }; static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 7ecd59f..93f3dac 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -235,16 +235,8 @@ out: return num_modes; } -static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) -{ - struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); - - return ptn_bridge->bridge.encoder; -} - static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { .get_modes = ptn3460_get_modes, - .best_encoder = ptn3460_best_encoder, }; static enum drm_connector_status ptn3460_detect(struct drm_connector *connector, diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index be881e9..5cd8dd7 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -474,18 +474,8 @@ static int ps8622_get_modes(struct drm_connector *connector) return drm_panel_get_modes(ps8622->panel); } -static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector) -{ - struct ps8622_bridge *ps8622; - - ps8622 = connector_to_ps8622(connector); - - return ps8622->bridge.encoder; -} - static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { .get_modes = ps8622_get_modes, - .best_encoder = ps8622_best_encoder, }; static enum drm_connector_status ps8622_detect(struct drm_connector *connector, diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 5e4b820..d99ab2f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -33,6 +33,20 @@ #include "drm_crtc_internal.h" +static void crtc_commit_free(struct kref *kref) +{ + struct drm_crtc_commit *commit = + container_of(kref, struct drm_crtc_commit, ref); + + kfree(commit); +} + +void drm_crtc_commit_put(struct drm_crtc_commit *commit) +{ + kref_put(&commit->ref, crtc_commit_free); +} +EXPORT_SYMBOL(drm_crtc_commit_put); + /** * drm_atomic_state_default_release - * release memory initialized by drm_atomic_state_init @@ -148,6 +162,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].state); + + if (state->crtcs[i].commit) { + kfree(state->crtcs[i].commit->event); + state->crtcs[i].commit->event = NULL; + drm_crtc_commit_put(state->crtcs[i].commit); + } + + state->crtcs[i].commit = NULL; state->crtcs[i].ptr = NULL; state->crtcs[i].state = NULL; } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bb98d74..de7fddc 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -465,7 +465,7 @@ mode_fixup(struct drm_atomic_state *state) * times for the same update, e.g. when the ->atomic_check functions depend upon * the adjusted dotclock for fifo space allocation and watermark computation. * - * RETURNS + * RETURNS: * Zero for success or -errno */ int @@ -579,7 +579,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * It also sets crtc_state->planes_changed to indicate that a crtc has * updated planes. * - * RETURNS + * RETURNS: * Zero for success or -errno */ int @@ -647,7 +647,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes); * ->atomic_check functions depend upon an updated adjusted_mode.clock to * e.g. properly compute watermarks. * - * RETURNS + * RETURNS: * Zero for success or -errno */ int drm_atomic_helper_check(struct drm_device *dev, @@ -1120,22 +1120,17 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); /** - * drm_atomic_helper_commit - commit validated state object - * @dev: DRM device - * @state: the driver state object - * @nonblocking: whether nonblocking behavior is requested. + * drm_atomic_helper_commit_tail - commit atomic update to hardware + * @state: new modeset state to be committed * - * This function commits a with drm_atomic_helper_check() pre-validated state - * object. This can still fail when e.g. the framebuffer reservation fails. For - * now this doesn't implement nonblocking commits. + * This is the default implemenation for the ->atomic_commit_tail() hook of the + * &drm_mode_config_helper_funcs vtable. * - * Note that right now this function does not support nonblocking commits, hence - * driver writers must implement their own version for now. Also note that the - * default ordering of how the various stages are called is to match the legacy - * modeset helper library closest. One peculiarity of that is that it doesn't - * mesh well with runtime PM at all. + * Note that the default ordering of how the various stages are called is to + * match the legacy modeset helper library closest. One peculiarity of that is + * that it doesn't mesh well with runtime PM at all. * - * For drivers supporting runtime PM the recommended sequence is + * For drivers supporting runtime PM the recommended sequence is instead :: * * drm_atomic_helper_commit_modeset_disables(dev, state); * @@ -1143,9 +1138,75 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * * drm_atomic_helper_commit_planes(dev, state, true); * - * See the kerneldoc entries for these three functions for more details. + * for committing the atomic update to hardware. See the kerneldoc entries for + * these three functions for more details. + */ +void drm_atomic_helper_commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state, false); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + drm_atomic_helper_commit_hw_done(state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); +} +EXPORT_SYMBOL(drm_atomic_helper_commit_tail); + +static void commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_mode_config_helper_funcs *funcs; + + funcs = dev->mode_config.helper_private; + + drm_atomic_helper_wait_for_fences(dev, state); + + drm_atomic_helper_wait_for_dependencies(state); + + if (funcs && funcs->atomic_commit_tail) + funcs->atomic_commit_tail(state); + else + drm_atomic_helper_commit_tail(state); + + drm_atomic_helper_commit_cleanup_done(state); + + drm_atomic_state_free(state); +} + +static void commit_work(struct work_struct *work) +{ + struct drm_atomic_state *state = container_of(work, + struct drm_atomic_state, + commit_work); + commit_tail(state); +} + +/** + * drm_atomic_helper_commit - commit validated state object + * @dev: DRM device + * @state: the driver state object + * @nonblock: whether nonblocking behavior is requested. + * + * This function commits a with drm_atomic_helper_check() pre-validated state + * object. This can still fail when e.g. the framebuffer reservation fails. This + * function implements nonblocking commits, using + * drm_atomic_helper_setup_commit() and related functions. + * + * Note that right now this function does not support nonblocking commits, hence + * driver writers must implement their own version for now. + * + * Committing the actual hardware state is done through the + * ->atomic_commit_tail() callback of the &drm_mode_config_helper_funcs vtable, + * or it's default implementation drm_atomic_helper_commit_tail(). * - * RETURNS + * RETURNS: * Zero for success or -errno. */ int drm_atomic_helper_commit(struct drm_device *dev, @@ -1154,8 +1215,11 @@ int drm_atomic_helper_commit(struct drm_device *dev, { int ret; - if (nonblock) - return -EBUSY; + ret = drm_atomic_helper_setup_commit(state, nonblock); + if (ret) + return ret; + + INIT_WORK(&state->commit_work, commit_work); ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) @@ -1167,7 +1231,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, * the software side now. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); /* * Everything below can be run asynchronously without the need to grab @@ -1183,21 +1247,16 @@ int drm_atomic_helper_commit(struct drm_device *dev, * update. Which is important since compositors need to figure out the * composition of the next frame right after having submitted the * current layout. + * + * NOTE: Commit work has multiple phases, first hardware commit, then + * cleanup. We want them to overlap, hence need system_unbound_wq to + * make sure work items don't artifically stall on each another. */ - drm_atomic_helper_wait_for_fences(dev, state); - - drm_atomic_helper_commit_modeset_disables(dev, state); - - drm_atomic_helper_commit_planes(dev, state, false); - - drm_atomic_helper_commit_modeset_enables(dev, state); - - drm_atomic_helper_wait_for_vblanks(dev, state); - - drm_atomic_helper_cleanup_planes(dev, state); - - drm_atomic_state_free(state); + if (nonblock) + queue_work(system_unbound_wq, &state->commit_work); + else + commit_tail(state); return 0; } @@ -1206,12 +1265,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); /** * DOC: implementing nonblocking commit * - * For now the atomic helpers don't support nonblocking commit directly. If - * there is real need it could be added though, using the dma-buf fence - * infrastructure for generic synchronization with outstanding rendering. - * - * For now drivers have to implement nonblocking commit themselves, with the - * following sequence being the recommended one: + * Nonblocking atomic commits have to be implemented in the following sequence: * * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function * which commit needs to call which can fail, so we want to run it first and @@ -1223,10 +1277,14 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); * cancelled updates. Note that it is important to ensure that the framebuffer * cleanup is still done when cancelling. * - * For sufficient parallelism it is recommended to have a work item per crtc - * (for updates which don't touch global state) and a global one. Then we only - * need to synchronize with the crtc work items for changed crtcs and the global - * work item, which allows nice concurrent updates on disjoint sets of crtcs. + * Asynchronous workers need to have sufficient parallelism to be able to run + * different atomic commits on different CRTCs in parallel. The simplest way to + * achive this is by running them on the &system_unbound_wq work queue. Note + * that drivers are not required to split up atomic commits and run an + * individual commit in parallel - userspace is supposed to do that if it cares. + * But it might be beneficial to do that for modesets, since those necessarily + * must be done as one global operation, and enabling or disabling a CRTC can + * take a long time. But even that is not required. * * 3. The software state is updated synchronously with * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset @@ -1239,8 +1297,310 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and * then cleaning up the framebuffers after the old framebuffer is no longer * being displayed. + * + * The above scheme is implemented in the atomic helper libraries in + * drm_atomic_helper_commit() using a bunch of helper functions. See + * drm_atomic_helper_setup_commit() for a starting point. */ +static int stall_checks(struct drm_crtc *crtc, bool nonblock) +{ + struct drm_crtc_commit *commit, *stall_commit = NULL; + bool completed = true; + int i; + long ret = 0; + + spin_lock(&crtc->commit_lock); + i = 0; + list_for_each_entry(commit, &crtc->commit_list, commit_entry) { + if (i == 0) { + completed = try_wait_for_completion(&commit->flip_done); + /* Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. */ + if (!completed && nonblock) { + spin_unlock(&crtc->commit_lock); + return -EBUSY; + } + } else if (i == 1) { + stall_commit = commit; + drm_crtc_commit_get(stall_commit); + break; + } + + i++; + } + spin_unlock(&crtc->commit_lock); + + if (!stall_commit) + return 0; + + /* We don't want to let commits get ahead of cleanup work too much, + * stalling on 2nd previous commit means triple-buffer won't ever stall. + */ + ret = wait_for_completion_interruptible_timeout(&stall_commit->cleanup_done, + 10*HZ); + if (ret == 0) + DRM_ERROR("[CRTC:%d:%s] cleanup_done timed out\n", + crtc->base.id, crtc->name); + + drm_crtc_commit_put(stall_commit); + + return ret < 0 ? ret : 0; +} + +/** + * drm_atomic_helper_setup_commit - setup possibly nonblocking commit + * @state: new modeset state to be committed + * @nonblock: whether nonblocking behavior is requested. + * + * This function prepares @state to be used by the atomic helper's support for + * nonblocking commits. Drivers using the nonblocking commit infrastructure + * should always call this function from their ->atomic_commit hook. + * + * To be able to use this support drivers need to use a few more helper + * functions. drm_atomic_helper_wait_for_dependencies() must be called before + * actually committing the hardware state, and for nonblocking commits this call + * must be placed in the async worker. See also drm_atomic_helper_swap_state() + * and it's stall parameter, for when a driver's commit hooks look at the + * ->state pointers of struct &drm_crtc, &drm_plane or &drm_connector directly. + * + * Completion of the hardware commit step must be signalled using + * drm_atomic_helper_commit_hw_done(). After this step the driver is not allowed + * to read or change any permanent software or hardware modeset state. The only + * exception is state protected by other means than &drm_modeset_lock locks. + * Only the free standing @state with pointers to the old state structures can + * be inspected, e.g. to clean up old buffers using + * drm_atomic_helper_cleanup_planes(). + * + * At the very end, before cleaning up @state drivers must call + * drm_atomic_helper_commit_cleanup_done(). + * + * This is all implemented by in drm_atomic_helper_commit(), giving drivers a + * complete and esay-to-use default implementation of the atomic_commit() hook. + * + * The tracking of asynchronously executed and still pending commits is done + * using the core structure &drm_crtc_commit. + * + * By default there's no need to clean up resources allocated by this function + * explicitly: drm_atomic_state_default_clear() will take care of that + * automatically. + * + * Returns: + * + * 0 on success. -EBUSY when userspace schedules nonblocking commits too fast, + * -ENOMEM on allocation failures and -EINTR when a signal is pending. + */ +int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, + bool nonblock) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int i, ret; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + commit = kzalloc(sizeof(*commit), GFP_KERNEL); + if (!commit) + return -ENOMEM; + + init_completion(&commit->flip_done); + init_completion(&commit->hw_done); + init_completion(&commit->cleanup_done); + INIT_LIST_HEAD(&commit->commit_entry); + kref_init(&commit->ref); + commit->crtc = crtc; + + state->crtcs[i].commit = commit; + + ret = stall_checks(crtc, nonblock); + if (ret) + return ret; + + /* Drivers only send out events when at least either current or + * new CRTC state is active. Complete right away if everything + * stays off. */ + if (!crtc->state->active && !crtc_state->active) { + complete_all(&commit->flip_done); + continue; + } + + /* Legacy cursor updates are fully unsynced. */ + if (state->legacy_cursor_update) { + complete_all(&commit->flip_done); + continue; + } + + if (!crtc_state->event) { + commit->event = kzalloc(sizeof(*commit->event), + GFP_KERNEL); + if (!commit->event) + return -ENOMEM; + + crtc_state->event = commit->event; + } + + crtc_state->event->base.completion = &commit->flip_done; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_helper_setup_commit); + + +static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) +{ + struct drm_crtc_commit *commit; + int i = 0; + + list_for_each_entry(commit, &crtc->commit_list, commit_entry) { + /* skip the first entry, that's the current commit */ + if (i == 1) + return commit; + i++; + } + + return NULL; +} + +/** + * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits + * @state: new modeset state to be committed + * + * This function waits for all preceeding commits that touch the same CRTC as + * @state to both be committed to the hardware (as signalled by + * drm_atomic_helper_commit_hw_done) and executed by the hardware (as signalled + * by calling drm_crtc_vblank_send_event on the event member of + * &drm_crtc_state). + * + * This is part of the atomic helper support for nonblocking commits, see + * drm_atomic_helper_setup_commit() for an overview. + */ +void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int i; + long ret; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + spin_lock(&crtc->commit_lock); + commit = preceeding_commit(crtc); + if (commit) + drm_crtc_commit_get(commit); + spin_unlock(&crtc->commit_lock); + + if (!commit) + continue; + + ret = wait_for_completion_timeout(&commit->hw_done, + 10*HZ); + if (ret == 0) + DRM_ERROR("[CRTC:%d:%s] hw_done timed out\n", + crtc->base.id, crtc->name); + + /* Currently no support for overwriting flips, hence + * stall for previous one to execute completely. */ + ret = wait_for_completion_timeout(&commit->flip_done, + 10*HZ); + if (ret == 0) + DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n", + crtc->base.id, crtc->name); + + drm_crtc_commit_put(commit); + } +} +EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); + +/** + * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit + * @state: new modeset state to be committed + * + * This function is used to signal completion of the hardware commit step. After + * this step the driver is not allowed to read or change any permanent software + * or hardware modeset state. The only exception is state protected by other + * means than &drm_modeset_lock locks. + * + * Drivers should try to postpone any expensive or delayed cleanup work after + * this function is called. + * + * This is part of the atomic helper support for nonblocking commits, see + * drm_atomic_helper_setup_commit() for an overview. + */ +void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int i; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + commit = state->crtcs[i].commit; + if (!commit) + continue; + + /* backend must have consumed any event by now */ + WARN_ON(crtc->state->event); + spin_lock(&crtc->commit_lock); + complete_all(&commit->hw_done); + spin_unlock(&crtc->commit_lock); + } +} +EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); + +/** + * drm_atomic_helper_commit_cleanup_done - signal completion of commit + * @state: new modeset state to be committed + * + * This signals completion of the atomic update @state, including any cleanup + * work. If used, it must be called right before calling + * drm_atomic_state_free(). + * + * This is part of the atomic helper support for nonblocking commits, see + * drm_atomic_helper_setup_commit() for an overview. + */ +void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int i; + long ret; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + commit = state->crtcs[i].commit; + if (WARN_ON(!commit)) + continue; + + spin_lock(&crtc->commit_lock); + complete_all(&commit->cleanup_done); + WARN_ON(!try_wait_for_completion(&commit->hw_done)); + + /* commit_list borrows our reference, need to remove before we + * clean up our drm_atomic_state. But only after it actually + * completed, otherwise subsequent commits won't stall properly. */ + if (try_wait_for_completion(&commit->flip_done)) + goto del_commit; + + spin_unlock(&crtc->commit_lock); + + /* We must wait for the vblank event to signal our completion + * before releasing our reference, since the vblank work does + * not hold a reference of its own. */ + ret = wait_for_completion_timeout(&commit->flip_done, + 10*HZ); + if (ret == 0) + DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n", + crtc->base.id, crtc->name); + + spin_lock(&crtc->commit_lock); +del_commit: + list_del(&commit->commit_entry); + spin_unlock(&crtc->commit_lock); + } +} +EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); + /** * drm_atomic_helper_prepare_planes - prepare plane resources before commit * @dev: DRM device @@ -1538,8 +1898,8 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); /** * drm_atomic_helper_swap_state - store atomic state into current sw state - * @dev: DRM device * @state: atomic state + * @stall: stall for proceeding commits * * This function stores the atomic state into the current state pointers in all * driver objects. It should be called after all failing steps have been done @@ -1560,17 +1920,45 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); * * 5. Call drm_atomic_helper_cleanup_planes() with @state, which since step 3 * contains the old state. Also do any other cleanup required with that state. + * + * @stall must be set when nonblocking commits for this driver directly access + * the ->state pointer of &drm_plane, &drm_crtc or &drm_connector. With the + * current atomic helpers this is almost always the case, since the helpers + * don't pass the right state structures to the callbacks. */ -void drm_atomic_helper_swap_state(struct drm_device *dev, - struct drm_atomic_state *state) +void drm_atomic_helper_swap_state(struct drm_atomic_state *state, + bool stall) { int i; + long ret; struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_plane *plane; struct drm_plane_state *plane_state; + struct drm_crtc_commit *commit; + + if (stall) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { + spin_lock(&crtc->commit_lock); + commit = list_first_entry_or_null(&crtc->commit_list, + struct drm_crtc_commit, commit_entry); + if (commit) + drm_crtc_commit_get(commit); + spin_unlock(&crtc->commit_lock); + + if (!commit) + continue; + + ret = wait_for_completion_timeout(&commit->hw_done, + 10*HZ); + if (ret == 0) + DRM_ERROR("[CRTC:%d:%s] hw_done timed out\n", + crtc->base.id, crtc->name); + drm_crtc_commit_put(commit); + } + } for_each_connector_in_state(state, connector, conn_state, i) { connector->state->state = state; @@ -1582,6 +1970,15 @@ void drm_atomic_helper_swap_state(struct drm_device *dev, crtc->state->state = state; swap(state->crtcs[i].state, crtc->state); crtc->state->state = NULL; + + if (state->crtcs[i].commit) { + spin_lock(&crtc->commit_lock); + list_add(&state->crtcs[i].commit->commit_entry, + &crtc->commit_list); + spin_unlock(&crtc->commit_lock); + + state->crtcs[i].commit->event = NULL; + } } for_each_plane_in_state(state, plane, plane_state, i) { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index df91dfe..4ec35f9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -239,37 +239,6 @@ const char *drm_get_subpixel_order_name(enum subpixel_order order) } EXPORT_SYMBOL(drm_get_subpixel_order_name); -static char printable_char(int c) -{ - return isascii(c) && isprint(c) ? c : '?'; -} - -/** - * drm_get_format_name - return a string for drm fourcc format - * @format: format to compute name of - * - * Note that the buffer used by this function is globally shared and owned by - * the function itself. - * - * FIXME: This isn't really multithreading safe. - */ -const char *drm_get_format_name(uint32_t format) -{ - static char buf[32]; - - snprintf(buf, sizeof(buf), - "%c%c%c%c %s-endian (0x%08x)", - printable_char(format & 0xff), - printable_char((format >> 8) & 0xff), - printable_char((format >> 16) & 0xff), - printable_char((format >> 24) & 0x7f), - format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", - format); - - return buf; -} -EXPORT_SYMBOL(drm_get_format_name); - /* * Internal function to assign a slot in the object idr and optionally * register the object into the idr. @@ -669,6 +638,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; + INIT_LIST_HEAD(&crtc->commit_list); + spin_lock_init(&crtc->commit_lock); + drm_modeset_lock_init(&crtc->mutex); ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); if (ret) @@ -5503,264 +5475,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, } /** - * drm_fb_get_bpp_depth - get the bpp/depth values for format - * @format: pixel format (DRM_FORMAT_*) - * @depth: storage for the depth value - * @bpp: storage for the bpp value - * - * This only supports RGB formats here for compat with code that doesn't use - * pixel formats directly yet. - */ -void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, - int *bpp) -{ - switch (format) { - case DRM_FORMAT_C8: - case DRM_FORMAT_RGB332: - case DRM_FORMAT_BGR233: - *depth = 8; - *bpp = 8; - break; - case DRM_FORMAT_XRGB1555: - case DRM_FORMAT_XBGR1555: - case DRM_FORMAT_RGBX5551: - case DRM_FORMAT_BGRX5551: - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_ABGR1555: - case DRM_FORMAT_RGBA5551: - case DRM_FORMAT_BGRA5551: - *depth = 15; - *bpp = 16; - break; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_BGR565: - *depth = 16; - *bpp = 16; - break; - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - *depth = 24; - *bpp = 24; - break; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBX8888: - case DRM_FORMAT_BGRX8888: - *depth = 24; - *bpp = 32; - break; - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_RGBA1010102: - case DRM_FORMAT_BGRA1010102: - *depth = 30; - *bpp = 32; - break; - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - *depth = 32; - *bpp = 32; - break; - default: - DRM_DEBUG_KMS("unsupported pixel format %s\n", - drm_get_format_name(format)); - *depth = 0; - *bpp = 0; - break; - } -} -EXPORT_SYMBOL(drm_fb_get_bpp_depth); - -/** - * drm_format_num_planes - get the number of planes for format - * @format: pixel format (DRM_FORMAT_*) - * - * Returns: - * The number of planes used by the specified pixel format. - */ -int drm_format_num_planes(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 3; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - return 2; - default: - return 1; - } -} -EXPORT_SYMBOL(drm_format_num_planes); - -/** - * drm_format_plane_cpp - determine the bytes per pixel value - * @format: pixel format (DRM_FORMAT_*) - * @plane: plane index - * - * Returns: - * The bytes per pixel value for the specified plane. - */ -int drm_format_plane_cpp(uint32_t format, int plane) -{ - unsigned int depth; - int bpp; - - if (plane >= drm_format_num_planes(format)) - return 0; - - switch (format) { - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - return 2; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - return plane ? 2 : 1; - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 1; - default: - drm_fb_get_bpp_depth(format, &depth, &bpp); - return bpp >> 3; - } -} -EXPORT_SYMBOL(drm_format_plane_cpp); - -/** - * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor - * @format: pixel format (DRM_FORMAT_*) - * - * Returns: - * The horizontal chroma subsampling factor for the - * specified pixel format. - */ -int drm_format_horz_chroma_subsampling(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - return 4; - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - return 2; - default: - return 1; - } -} -EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); - -/** - * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor - * @format: pixel format (DRM_FORMAT_*) - * - * Returns: - * The vertical chroma subsampling factor for the - * specified pixel format. - */ -int drm_format_vert_chroma_subsampling(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - return 4; - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - return 2; - default: - return 1; - } -} -EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); - -/** - * drm_format_plane_width - width of the plane given the first plane - * @width: width of the first plane - * @format: pixel format - * @plane: plane index - * - * Returns: - * The width of @plane, given that the width of the first plane is @width. - */ -int drm_format_plane_width(int width, uint32_t format, int plane) -{ - if (plane >= drm_format_num_planes(format)) - return 0; - - if (plane == 0) - return width; - - return width / drm_format_horz_chroma_subsampling(format); -} -EXPORT_SYMBOL(drm_format_plane_width); - -/** - * drm_format_plane_height - height of the plane given the first plane - * @height: height of the first plane - * @format: pixel format - * @plane: plane index - * - * Returns: - * The height of @plane, given that the height of the first plane is @height. - */ -int drm_format_plane_height(int height, uint32_t format, int plane) -{ - if (plane >= drm_format_num_planes(format)) - return 0; - - if (plane == 0) - return height; - - return height / drm_format_vert_chroma_subsampling(format); -} -EXPORT_SYMBOL(drm_format_plane_height); - -/** * drm_rotation_simplify() - Try to simplify the rotation * @rotation: Rotation to be simplified * @supported_rotations: Supported rotations diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index bff8922..8b2582a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -605,8 +605,6 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); if (ret) goto err_minors; - - WARN_ON(driver->suspend || driver->resume); } if (drm_core_check_feature(dev, DRIVER_RENDER)) { diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 2e7ef0b..c0b0c71 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -346,6 +346,7 @@ static int drm_fbdev_cma_defio_init(struct fb_info *fbi, fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); if (!fbdefio || !fbops) { kfree(fbdefio); + kfree(fbops); return -ENOMEM; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index ba5aac7..0bac524 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -385,7 +385,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) drm_warn_on_modeset_not_all_locked(dev); - if (fb_helper->atomic) + if (dev->mode_config.funcs->atomic_commit) return restore_fbdev_mode_atomic(fb_helper); drm_for_each_plane(plane, dev) { @@ -716,8 +716,6 @@ int drm_fb_helper_init(struct drm_device *dev, i++; } - fb_helper->atomic = !!drm_core_check_feature(dev, DRIVER_ATOMIC); - return 0; out_free: drm_fb_helper_crtc_free(fb_helper); @@ -1344,7 +1342,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, return -EBUSY; } - if (fb_helper->atomic) { + if (dev->mode_config.funcs->atomic_commit) { ret = pan_display_atomic(var, info); goto unlock; } diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 64121f5..a27bc7cd 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -797,6 +797,12 @@ void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e) { assert_spin_locked(&dev->event_lock); + if (e->completion) { + /* ->completion might disappear as soon as it signalled. */ + complete_all(e->completion); + e->completion = NULL; + } + if (e->fence) { fence_signal(e->fence); fence_put(e->fence); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c new file mode 100644 index 0000000..0645c85 --- /dev/null +++ b/drivers/gpu/drm/drm_fourcc.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * DRM core format related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <linux/bug.h> +#include <linux/ctype.h> +#include <linux/export.h> +#include <linux/kernel.h> + +#include <drm/drmP.h> +#include <drm/drm_fourcc.h> + +static char printable_char(int c) +{ + return isascii(c) && isprint(c) ? c : '?'; +} + +/** + * drm_get_format_name - return a string for drm fourcc format + * @format: format to compute name of + * + * Note that the buffer used by this function is globally shared and owned by + * the function itself. + * + * FIXME: This isn't really multithreading safe. + */ +const char *drm_get_format_name(uint32_t format) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), + "%c%c%c%c %s-endian (0x%08x)", + printable_char(format & 0xff), + printable_char((format >> 8) & 0xff), + printable_char((format >> 16) & 0xff), + printable_char((format >> 24) & 0x7f), + format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", + format); + + return buf; +} +EXPORT_SYMBOL(drm_get_format_name); + +/** + * drm_fb_get_bpp_depth - get the bpp/depth values for format + * @format: pixel format (DRM_FORMAT_*) + * @depth: storage for the depth value + * @bpp: storage for the bpp value + * + * This only supports RGB formats here for compat with code that doesn't use + * pixel formats directly yet. + */ +void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, + int *bpp) +{ + switch (format) { + case DRM_FORMAT_C8: + case DRM_FORMAT_RGB332: + case DRM_FORMAT_BGR233: + *depth = 8; + *bpp = 8; + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_BGRA5551: + *depth = 15; + *bpp = 16; + break; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + *depth = 16; + *bpp = 16; + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + *depth = 24; + *bpp = 24; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + *depth = 24; + *bpp = 32; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_BGRA1010102: + *depth = 30; + *bpp = 32; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + *depth = 32; + *bpp = 32; + break; + default: + DRM_DEBUG_KMS("unsupported pixel format %s\n", + drm_get_format_name(format)); + *depth = 0; + *bpp = 0; + break; + } +} +EXPORT_SYMBOL(drm_fb_get_bpp_depth); + +/** + * drm_format_num_planes - get the number of planes for format + * @format: pixel format (DRM_FORMAT_*) + * + * Returns: + * The number of planes used by the specified pixel format. + */ +int drm_format_num_planes(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 3; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_num_planes); + +/** + * drm_format_plane_cpp - determine the bytes per pixel value + * @format: pixel format (DRM_FORMAT_*) + * @plane: plane index + * + * Returns: + * The bytes per pixel value for the specified plane. + */ +int drm_format_plane_cpp(uint32_t format, int plane) +{ + unsigned int depth; + int bpp; + + if (plane >= drm_format_num_planes(format)) + return 0; + + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return 2; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + return plane ? 2 : 1; + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 1; + default: + drm_fb_get_bpp_depth(format, &depth, &bpp); + return bpp >> 3; + } +} +EXPORT_SYMBOL(drm_format_plane_cpp); + +/** + * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * Returns: + * The horizontal chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_horz_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); + +/** + * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * Returns: + * The vertical chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_vert_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); + +/** + * drm_format_plane_width - width of the plane given the first plane + * @width: width of the first plane + * @format: pixel format + * @plane: plane index + * + * Returns: + * The width of @plane, given that the width of the first plane is @width. + */ +int drm_format_plane_width(int width, uint32_t format, int plane) +{ + if (plane >= drm_format_num_planes(format)) + return 0; + + if (plane == 0) + return width; + + return width / drm_format_horz_chroma_subsampling(format); +} +EXPORT_SYMBOL(drm_format_plane_width); + +/** + * drm_format_plane_height - height of the plane given the first plane + * @height: height of the first plane + * @format: pixel format + * @plane: plane index + * + * Returns: + * The height of @plane, given that the height of the first plane is @height. + */ +int drm_format_plane_height(int height, uint32_t format, int plane) +{ + if (plane >= drm_format_num_planes(format)) + return 0; + + if (plane == 0) + return height; + + return height / drm_format_vert_chroma_subsampling(format); +} +EXPORT_SYMBOL(drm_format_plane_height); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 4dc41ff..76e39c5 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1001,34 +1001,6 @@ static void send_vblank_event(struct drm_device *dev, } /** - * drm_arm_vblank_event - arm vblank event after pageflip - * @dev: DRM device - * @pipe: CRTC index - * @e: the event to prepare to send - * - * A lot of drivers need to generate vblank events for the very next vblank - * interrupt. For example when the page flip interrupt happens when the page - * flip gets armed, but not when it actually executes within the next vblank - * period. This helper function implements exactly the required vblank arming - * behaviour. - * - * Caller must hold event lock. Caller must also hold a vblank reference for - * the event @e, which will be dropped when the next vblank arrives. - * - * This is the legacy version of drm_crtc_arm_vblank_event(). - */ -void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, - struct drm_pending_vblank_event *e) -{ - assert_spin_locked(&dev->event_lock); - - e->pipe = pipe; - e->event.sequence = drm_vblank_count(dev, pipe); - list_add_tail(&e->base.link, &dev->vblank_event_list); -} -EXPORT_SYMBOL(drm_arm_vblank_event); - -/** * drm_crtc_arm_vblank_event - arm vblank event after pageflip * @crtc: the source CRTC of the vblank event * @e: the event to send @@ -1041,32 +1013,35 @@ EXPORT_SYMBOL(drm_arm_vblank_event); * * Caller must hold event lock. Caller must also hold a vblank reference for * the event @e, which will be dropped when the next vblank arrives. - * - * This is the native KMS version of drm_arm_vblank_event(). */ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e) { - drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e); + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); + + assert_spin_locked(&dev->event_lock); + + e->pipe = pipe; + e->event.sequence = drm_vblank_count(dev, pipe); + list_add_tail(&e->base.link, &dev->vblank_event_list); } EXPORT_SYMBOL(drm_crtc_arm_vblank_event); /** - * drm_send_vblank_event - helper to send vblank event after pageflip - * @dev: DRM device - * @pipe: CRTC index + * drm_crtc_send_vblank_event - helper to send vblank event after pageflip + * @crtc: the source CRTC of the vblank event * @e: the event to send * * Updates sequence # and timestamp on event, and sends it to userspace. * Caller must hold event lock. - * - * This is the legacy version of drm_crtc_send_vblank_event(). */ -void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe, - struct drm_pending_vblank_event *e) +void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) { + struct drm_device *dev = crtc->dev; + unsigned int seq, pipe = drm_crtc_index(crtc); struct timeval now; - unsigned int seq; if (dev->num_crtcs > 0) { seq = drm_vblank_count_and_time(dev, pipe, &now); @@ -1078,23 +1053,6 @@ void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe, e->pipe = pipe; send_vblank_event(dev, e, seq, &now); } -EXPORT_SYMBOL(drm_send_vblank_event); - -/** - * drm_crtc_send_vblank_event - helper to send vblank event after pageflip - * @crtc: the source CRTC of the vblank event - * @e: the event to send - * - * Updates sequence # and timestamp on event, and sends it to userspace. - * Caller must hold event lock. - * - * This is the native KMS version of drm_send_vblank_event(). - */ -void drm_crtc_send_vblank_event(struct drm_crtc *crtc, - struct drm_pending_vblank_event *e) -{ - drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e); -} EXPORT_SYMBOL(drm_crtc_send_vblank_event); /** @@ -1150,7 +1108,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) * Returns: * Zero on success or a negative error code on failure. */ -int drm_vblank_get(struct drm_device *dev, unsigned int pipe) +static int drm_vblank_get(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; @@ -1176,7 +1134,6 @@ int drm_vblank_get(struct drm_device *dev, unsigned int pipe) return ret; } -EXPORT_SYMBOL(drm_vblank_get); /** * drm_crtc_vblank_get - get a reference count on vblank events @@ -1185,8 +1142,6 @@ EXPORT_SYMBOL(drm_vblank_get); * Acquire a reference count on vblank events to avoid having them disabled * while in use. * - * This is the native kms version of drm_vblank_get(). - * * Returns: * Zero on success or a negative error code on failure. */ @@ -1206,7 +1161,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_get); * * This is the legacy version of drm_crtc_vblank_put(). */ -void drm_vblank_put(struct drm_device *dev, unsigned int pipe) +static void drm_vblank_put(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; @@ -1227,7 +1182,6 @@ void drm_vblank_put(struct drm_device *dev, unsigned int pipe) jiffies + ((drm_vblank_offdelay * HZ)/1000)); } } -EXPORT_SYMBOL(drm_vblank_put); /** * drm_crtc_vblank_put - give up ownership of vblank events @@ -1235,8 +1189,6 @@ EXPORT_SYMBOL(drm_vblank_put); * * Release ownership of a given vblank counter, turning off interrupts * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. - * - * This is the native kms version of drm_vblank_put(). */ void drm_crtc_vblank_put(struct drm_crtc *crtc) { diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 7938ce7..49311fc 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -60,6 +60,21 @@ static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) return 0; } +static int mipi_dsi_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + int err; + + err = of_device_uevent_modalias(dev, env); + if (err != -ENODEV) + return err; + + add_uevent_var(env, "MODALIAS=%s%s", MIPI_DSI_MODULE_PREFIX, + dsi->name); + + return 0; +} + static const struct dev_pm_ops mipi_dsi_device_pm_ops = { .runtime_suspend = pm_generic_runtime_suspend, .runtime_resume = pm_generic_runtime_resume, @@ -74,6 +89,7 @@ static const struct dev_pm_ops mipi_dsi_device_pm_ops = { static struct bus_type mipi_dsi_bus_type = { .name = "mipi-dsi", .match = mipi_dsi_device_match, + .uevent = mipi_dsi_uevent, .pm = &mipi_dsi_device_pm_ops, }; diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index aab0f3f..780589b 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -593,7 +593,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, get_dma_buf(dma_buf); } - /* drm_gem_handle_create_tail unlocks dev->object_name_lock. */ + /* _handle_create_tail unconditionally unlocks dev->object_name_lock. */ ret = drm_gem_handle_create_tail(file_priv, obj, handle); drm_gem_object_unreference_unlocked(obj); if (ret) @@ -601,11 +601,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, ret = drm_prime_add_buf_handle(&file_priv->prime, dma_buf, *handle); + mutex_unlock(&file_priv->prime.lock); if (ret) goto fail; - mutex_unlock(&file_priv->prime.lock); - dma_buf_put(dma_buf); return 0; @@ -615,11 +614,14 @@ fail: * to detach.. which seems ok.. */ drm_gem_handle_delete(file_priv, *handle); + dma_buf_put(dma_buf); + return ret; + out_unlock: mutex_unlock(&dev->object_name_lock); out_put: - dma_buf_put(dma_buf); mutex_unlock(&file_priv->prime.lock); + dma_buf_put(dma_buf); return ret; } EXPORT_SYMBOL(drm_gem_prime_fd_to_handle); diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c new file mode 100644 index 0000000..b2071d4 --- /dev/null +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2016 Noralf Trønnes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_simple_kms_helper.h> +#include <linux/slab.h> + +/** + * DOC: overview + * + * This helper library provides helpers for drivers for simple display + * hardware. + * + * drm_simple_display_pipe_init() initializes a simple display pipeline + * which has only one full-screen scanout buffer feeding one output. The + * pipeline is represented by struct &drm_simple_display_pipe and binds + * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed + * entity. Some flexibility for code reuse is provided through a separately + * allocated &drm_connector object and supporting optional &drm_bridge + * encoder drivers. + */ + +static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); + if (!pipe->funcs || !pipe->funcs->enable) + return; + + pipe->funcs->enable(pipe, crtc->state); +} + +static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); + if (!pipe->funcs || !pipe->funcs->disable) + return; + + pipe->funcs->disable(pipe); +} + +static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { + .disable = drm_simple_kms_crtc_disable, + .enable = drm_simple_kms_crtc_enable, +}; + +static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *plane_state) +{ + struct drm_rect src = { + .x1 = plane_state->src_x, + .y1 = plane_state->src_y, + .x2 = plane_state->src_x + plane_state->src_w, + .y2 = plane_state->src_y + plane_state->src_h, + }; + struct drm_rect dest = { + .x1 = plane_state->crtc_x, + .y1 = plane_state->crtc_y, + .x2 = plane_state->crtc_x + plane_state->crtc_w, + .y2 = plane_state->crtc_y + plane_state->crtc_h, + }; + struct drm_rect clip = { 0 }; + struct drm_simple_display_pipe *pipe; + struct drm_crtc_state *crtc_state; + bool visible; + int ret; + + pipe = container_of(plane, struct drm_simple_display_pipe, plane); + crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, + &pipe->crtc); + if (crtc_state->enable != !!plane_state->crtc) + return -EINVAL; /* plane must match crtc enable state */ + + if (!crtc_state->enable) + return 0; /* nothing to check when disabling or disabled */ + + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + ret = drm_plane_helper_check_update(plane, &pipe->crtc, + plane_state->fb, + &src, &dest, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true, &visible); + if (ret) + return ret; + + if (!visible) + return -EINVAL; + + if (!pipe->funcs || !pipe->funcs->check) + return 0; + + return pipe->funcs->check(pipe, plane_state, crtc_state); +} + +static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *pstate) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(plane, struct drm_simple_display_pipe, plane); + if (!pipe->funcs || !pipe->funcs->update) + return; + + pipe->funcs->update(pipe, pstate); +} + +static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { + .atomic_check = drm_simple_kms_plane_atomic_check, + .atomic_update = drm_simple_kms_plane_atomic_update, +}; + +static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +/** + * drm_simple_display_pipe_init - Initialize a simple display pipeline + * @dev: DRM device + * @pipe: simple display pipe object to initialize + * @funcs: callbacks for the display pipe (optional) + * @formats: array of supported formats (%DRM_FORMAT_*) + * @format_count: number of elements in @formats + * @connector: connector to attach and register + * + * Sets up a display pipeline which consist of a really simple + * plane-crtc-encoder pipe coupled with the provided connector. + * Teardown of a simple display pipe is all handled automatically by the drm + * core through calling drm_mode_config_cleanup(). Drivers afterwards need to + * release the memory for the structure themselves. + * + * Returns: + * Zero on success, negative error code on failure. + */ +int drm_simple_display_pipe_init(struct drm_device *dev, + struct drm_simple_display_pipe *pipe, + const struct drm_simple_display_pipe_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + struct drm_connector *connector) +{ + struct drm_encoder *encoder = &pipe->encoder; + struct drm_plane *plane = &pipe->plane; + struct drm_crtc *crtc = &pipe->crtc; + int ret; + + pipe->connector = connector; + pipe->funcs = funcs; + + drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs); + ret = drm_universal_plane_init(dev, plane, 0, + &drm_simple_kms_plane_funcs, + formats, format_count, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs); + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, + &drm_simple_kms_crtc_funcs, NULL); + if (ret) + return ret; + + encoder->possible_crtcs = 1 << drm_crtc_index(crtc); + ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + return drm_mode_connector_attach_encoder(connector, encoder); +} +EXPORT_SYMBOL(drm_simple_display_pipe_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index fa7fadc..32dd821 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -32,75 +32,6 @@ static struct device_type drm_sysfs_device_minor = { struct class *drm_class; -/** - * __drm_class_suspend - internal DRM class suspend routine - * @dev: Linux device to suspend - * @state: power state to enter - * - * Just figures out what the actual struct drm_device associated with - * @dev is and calls its suspend hook, if present. - */ -static int __drm_class_suspend(struct device *dev, pm_message_t state) -{ - if (dev->type == &drm_sysfs_device_minor) { - struct drm_minor *drm_minor = to_drm_minor(dev); - struct drm_device *drm_dev = drm_minor->dev; - - if (drm_minor->type == DRM_MINOR_LEGACY && - !drm_core_check_feature(drm_dev, DRIVER_MODESET) && - drm_dev->driver->suspend) - return drm_dev->driver->suspend(drm_dev, state); - } - return 0; -} - -/** - * drm_class_suspend - internal DRM class suspend hook. Simply calls - * __drm_class_suspend() with the correct pm state. - * @dev: Linux device to suspend - */ -static int drm_class_suspend(struct device *dev) -{ - return __drm_class_suspend(dev, PMSG_SUSPEND); -} - -/** - * drm_class_freeze - internal DRM class freeze hook. Simply calls - * __drm_class_suspend() with the correct pm state. - * @dev: Linux device to freeze - */ -static int drm_class_freeze(struct device *dev) -{ - return __drm_class_suspend(dev, PMSG_FREEZE); -} - -/** - * drm_class_resume - DRM class resume hook - * @dev: Linux device to resume - * - * Just figures out what the actual struct drm_device associated with - * @dev is and calls its resume hook, if present. - */ -static int drm_class_resume(struct device *dev) -{ - if (dev->type == &drm_sysfs_device_minor) { - struct drm_minor *drm_minor = to_drm_minor(dev); - struct drm_device *drm_dev = drm_minor->dev; - - if (drm_minor->type == DRM_MINOR_LEGACY && - !drm_core_check_feature(drm_dev, DRIVER_MODESET) && - drm_dev->driver->resume) - return drm_dev->driver->resume(drm_dev); - } - return 0; -} - -static const struct dev_pm_ops drm_class_dev_pm_ops = { - .suspend = drm_class_suspend, - .resume = drm_class_resume, - .freeze = drm_class_freeze, -}; - static char *drm_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); @@ -131,8 +62,6 @@ int drm_sysfs_init(void) if (IS_ERR(drm_class)) return PTR_ERR(drm_class); - drm_class->pm = &drm_class_dev_pm_ops; - err = class_create_file(drm_class, &class_attr_version.attr); if (err) { class_destroy(drm_class); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 5e38e74..ad6b73c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -93,17 +93,8 @@ static int exynos_dpi_get_modes(struct drm_connector *connector) return 0; } -static struct drm_encoder * -exynos_dpi_best_encoder(struct drm_connector *connector) -{ - struct exynos_dpi *ctx = connector_to_dpi(connector); - - return &ctx->encoder; -} - static const struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { .get_modes = exynos_dpi_get_modes, - .best_encoder = exynos_dpi_best_encoder, }; static int exynos_dpi_create_connector(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 843b21c..4a679fb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -299,7 +299,7 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, priv->pending |= commit->crtcs; spin_unlock(&priv->lock); - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) schedule_work(&commit->work); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 601ecf8..e07cb1f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1566,17 +1566,8 @@ static int exynos_dsi_get_modes(struct drm_connector *connector) return 0; } -static struct drm_encoder * -exynos_dsi_best_encoder(struct drm_connector *connector) -{ - struct exynos_dsi *dsi = connector_to_dsi(connector); - - return &dsi->encoder; -} - static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { .get_modes = exynos_dsi_get_modes, - .best_encoder = exynos_dsi_best_encoder, }; static int exynos_dsi_create_connector(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 55f1d37..77f12c0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -242,7 +242,7 @@ exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, state->v_ratio == (1 << 15)) height_ok = true; - if (width_ok & height_ok) + if (width_ok && height_ok) return 0; DRM_DEBUG_KMS("scaling mode is not supported"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 608b0af..e8f6c92 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -378,16 +378,8 @@ static int vidi_get_modes(struct drm_connector *connector) return drm_add_edid_modes(connector, edid); } -static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) -{ - struct vidi_context *ctx = ctx_from_connector(connector); - - return &ctx->encoder; -} - static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = { .get_modes = vidi_get_modes, - .best_encoder = vidi_best_encoder, }; static int vidi_create_connector(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 58de5a4..1625d7c 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -937,17 +937,9 @@ static int hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector) -{ - struct hdmi_context *hdata = connector_to_hdmi(connector); - - return &hdata->encoder; -} - static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { .get_modes = hdmi_get_modes, .mode_valid = hdmi_mode_valid, - .best_encoder = hdmi_best_encoder, }; static int hdmi_create_connector(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 89c0084..706de32 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -22,20 +22,21 @@ #include "fsl_dcu_drm_drv.h" #include "fsl_dcu_drm_plane.h" -static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc, +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { -} + struct drm_pending_vblank_event *event = crtc->state->event; -static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - return 0; -} + if (event) { + crtc->state->event = NULL; -static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) -{ + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } } static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) @@ -117,8 +118,6 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) } static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { - .atomic_begin = fsl_dcu_drm_crtc_atomic_begin, - .atomic_check = fsl_dcu_drm_crtc_atomic_check, .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, .disable = fsl_dcu_drm_disable_crtc, .enable = fsl_dcu_drm_crtc_enable, diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 98c998d..0b0989e 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -102,14 +102,6 @@ static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = { .reset = drm_atomic_helper_connector_reset, }; -static struct drm_encoder * -fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector) -{ - struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); - - return fsl_con->encoder; -} - static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) { struct fsl_dcu_drm_connector *fsl_connector; @@ -136,7 +128,6 @@ static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, } static const struct drm_connector_helper_funcs connector_helper_funcs = { - .best_encoder = fsl_dcu_drm_connector_best_encoder, .get_modes = fsl_dcu_drm_connector_get_modes, .mode_valid = fsl_dcu_drm_connector_mode_valid, }; diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 5b636bf0..1a1cf7a 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -282,7 +282,7 @@ void gma_crtc_dpms(struct drm_crtc *crtc, int mode) REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); /* Turn off vblank interrupts */ - drm_vblank_off(dev, pipe); + drm_crtc_vblank_off(crtc); /* Wait for vblank for the disable to take effect */ gma_wait_for_vblank(dev); diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index fba6372..ed76baad 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -502,13 +502,6 @@ static void ade_crtc_disable(struct drm_crtc *crtc) acrtc->enable = false; } -static int ade_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - /* do nothing */ - return 0; -} - static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct ade_crtc *acrtc = to_ade_crtc(crtc); @@ -537,6 +530,7 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc, { struct ade_crtc *acrtc = to_ade_crtc(crtc); struct ade_hw_ctx *ctx = acrtc->ctx; + struct drm_pending_vblank_event *event = crtc->state->event; void __iomem *base = ctx->base; /* only crtc is enabled regs take effect */ @@ -545,12 +539,22 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc, /* flush ade registers */ writel(ADE_ENABLE, base + ADE_EN); } + + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } } static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = { .enable = ade_crtc_enable, .disable = ade_crtc_disable, - .atomic_check = ade_crtc_atomic_check, .mode_set_nofb = ade_crtc_mode_set_nofb, .atomic_begin = ade_crtc_atomic_begin, .atomic_flush = ade_crtc_atomic_flush, diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e4f2c55..614ac08 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2393,16 +2393,16 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) task = get_pid_task(file->pid, PIDTYPE_PID); if (!task) { ret = -ESRCH; - goto out_put; + goto out_unlock; } seq_printf(m, "\nproc: %s\n", task->comm); put_task_struct(task); idr_for_each(&file_priv->context_idr, per_file_ctx, (void *)(unsigned long)m); } +out_unlock: mutex_unlock(&dev->filelist_mutex); -out_put: intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6229681..9465de4 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -753,7 +753,6 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { .mode_valid = intel_crt_mode_valid, .get_modes = intel_crt_get_modes, - .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_crt_enc_funcs = { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60cba19..49322f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13726,7 +13726,7 @@ static int intel_atomic_commit(struct drm_device *dev, return ret; } - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); dev_priv->wm.distrust_bios_wm = false; dev_priv->wm.skl_results = intel_state->wm_results; intel_shared_dpll_commit(state); @@ -16267,14 +16267,6 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_teardown_gmbus(dev); } -/* - * Return which encoder is currently attached for connector. - */ -struct drm_encoder *intel_best_encoder(struct drm_connector *connector) -{ - return &intel_attached_encoder(connector)->base; -} - void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f97cd53..be08351 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4580,7 +4580,6 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { .get_modes = intel_dp_get_modes, .mode_valid = intel_dp_mode_valid, - .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_dp_enc_funcs = { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ebe7b34..270da8d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1154,7 +1154,6 @@ struct intel_connector *intel_connector_alloc(void); bool intel_connector_get_hw_state(struct intel_connector *connector); void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); -struct drm_encoder *intel_best_encoder(struct drm_connector *connector); struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); enum pipe intel_get_pipe_from_connector(struct intel_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index c70132a..a2ead5e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1379,7 +1379,6 @@ static const struct drm_encoder_funcs intel_dsi_funcs = { static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = { .get_modes = intel_dsi_get_modes, .mode_valid = intel_dsi_mode_valid, - .best_encoder = intel_best_encoder, }; static const struct drm_connector_funcs intel_dsi_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index a456f2e..c86f88e 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -351,7 +351,6 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { .mode_valid = intel_dvo_mode_valid, .get_modes = intel_dvo_get_modes, - .best_encoder = intel_best_encoder, }; static void intel_dvo_enc_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index ef8e676..4c725ad 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -724,8 +724,6 @@ int intel_fbdev_init(struct drm_device *dev) return ret; } - ifbdev->helper.atomic = true; - dev_priv->fbdev = ifbdev; INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index eb455ea..6b29da9 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1782,7 +1782,6 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { .get_modes = intel_hdmi_get_modes, .mode_valid = intel_hdmi_mode_valid, - .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 62eaa89..e06b903 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -547,7 +547,6 @@ static int intel_lvds_set_property(struct drm_connector *connector, static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { .get_modes = intel_lvds_get_modes, .mode_valid = intel_lvds_mode_valid, - .best_encoder = intel_best_encoder, }; static const struct drm_connector_funcs intel_lvds_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 1a71456..ab2d065 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2191,7 +2191,6 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { .get_modes = intel_sdvo_get_modes, .mode_valid = intel_sdvo_mode_valid, - .best_encoder = intel_best_encoder, }; static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 1f3a0e1..7ac9e9b 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1512,7 +1512,6 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, - .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_tv_enc_funcs = { diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 06a417b..c33bf98 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -91,7 +91,7 @@ static int mtk_atomic_commit(struct drm_device *drm, mutex_lock(&private->commit.lock); flush_work(&private->commit.work); - drm_atomic_helper_swap_state(drm, state); + drm_atomic_helper_swap_state(state, true); if (async) mtk_atomic_schedule(private, state); diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 7695591..28b2044 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -575,14 +575,6 @@ static int mtk_dsi_connector_get_modes(struct drm_connector *connector) return drm_panel_get_modes(dsi->panel); } -static struct drm_encoder *mtk_dsi_connector_best_encoder( - struct drm_connector *connector) -{ - struct mtk_dsi *dsi = connector_to_dsi(connector); - - return &dsi->encoder; -} - static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = { .mode_fixup = mtk_dsi_encoder_mode_fixup, .mode_set = mtk_dsi_encoder_mode_set, @@ -603,7 +595,6 @@ static const struct drm_connector_funcs mtk_dsi_connector_funcs = { static const struct drm_connector_helper_funcs mtk_dsi_connector_helper_funcs = { .get_modes = mtk_dsi_connector_get_modes, - .best_encoder = mtk_dsi_connector_best_encoder, }; static int mtk_drm_attach_bridge(struct drm_bridge *bridge, diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c index 72360cd..5960628 100644 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -91,15 +91,6 @@ static int edp_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder * -edp_connector_best_encoder(struct drm_connector *connector) -{ - struct edp_connector *edp_connector = to_edp_connector(connector); - - DBG(""); - return edp_connector->edp->encoder; -} - static const struct drm_connector_funcs edp_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = edp_connector_detect, @@ -113,7 +104,6 @@ static const struct drm_connector_funcs edp_connector_funcs = { static const struct drm_connector_helper_funcs edp_connector_helper_funcs = { .get_modes = edp_connector_get_modes, .mode_valid = edp_connector_mode_valid, - .best_encoder = edp_connector_best_encoder, }; /* initialize connector */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index b15d726..a2515b4 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -406,13 +406,6 @@ static int msm_hdmi_connector_mode_valid(struct drm_connector *connector, return 0; } -static struct drm_encoder * -msm_hdmi_connector_best_encoder(struct drm_connector *connector) -{ - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - return hdmi_connector->hdmi->encoder; -} - static const struct drm_connector_funcs hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = hdmi_connector_detect, @@ -426,7 +419,6 @@ static const struct drm_connector_funcs hdmi_connector_funcs = { static const struct drm_connector_helper_funcs msm_hdmi_connector_helper_funcs = { .get_modes = msm_hdmi_connector_get_modes, .mode_valid = msm_hdmi_connector_mode_valid, - .best_encoder = msm_hdmi_connector_best_encoder, }; /* initialize connector */ diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c index 2648cd7..353429b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c @@ -90,14 +90,6 @@ static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder * -mdp4_lvds_connector_best_encoder(struct drm_connector *connector) -{ - struct mdp4_lvds_connector *mdp4_lvds_connector = - to_mdp4_lvds_connector(connector); - return mdp4_lvds_connector->encoder; -} - static const struct drm_connector_funcs mdp4_lvds_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = mdp4_lvds_connector_detect, @@ -111,7 +103,6 @@ static const struct drm_connector_funcs mdp4_lvds_connector_funcs = { static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = { .get_modes = mdp4_lvds_connector_get_modes, .mode_valid = mdp4_lvds_connector_mode_valid, - .best_encoder = mdp4_lvds_connector_best_encoder, }; /* initialize connector */ diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 8c3b463..4a8a6f1 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -238,7 +238,7 @@ int msm_atomic_commit(struct drm_device *dev, * the software side now. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); /* * Everything below can be run asynchronously without the need to grab diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 7c77f96..6072fe2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -760,12 +760,11 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) - { { }, event, nouveau_crtc(crtc)->index, - fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, + { { }, event, crtc, fb->bits_per_pixel, fb->pitches[0], new_bo->bo.offset }; /* Keep vblanks on during flip, for the target crtc of this flip */ - drm_vblank_get(dev, nouveau_crtc(crtc)->index); + drm_crtc_vblank_get(crtc); /* Emit a page flip */ if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { @@ -810,7 +809,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, return 0; fail_unreserve: - drm_vblank_put(dev, nouveau_crtc(crtc)->index); + drm_crtc_vblank_put(crtc); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&cli->mutex); @@ -842,17 +841,17 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { - drm_arm_vblank_event(dev, s->crtc, s->event); + drm_crtc_arm_vblank_event(s->crtc, s->event); } else { - drm_send_vblank_event(dev, s->crtc, s->event); + drm_crtc_send_vblank_event(s->crtc, s->event); /* Give up ownership of vblank for page-flipped crtc */ - drm_vblank_put(dev, s->crtc); + drm_crtc_vblank_put(s->crtc); } } else { /* Give up ownership of vblank for page-flipped crtc */ - drm_vblank_put(dev, s->crtc); + drm_crtc_vblank_put(s->crtc); } list_del(&s->head); @@ -873,9 +872,10 @@ nouveau_flip_complete(struct nvif_notify *notify) if (!nouveau_finish_page_flip(chan, &state)) { if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { - nv_set_crtc_base(drm->dev, state.crtc, state.offset + - state.y * state.pitch + - state.x * state.bpp / 8); + nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), + state.offset + state.crtc->y * + state.pitch + state.crtc->x * + state.bpp / 8); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 24273ba..0420ee8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -28,7 +28,8 @@ int nouveau_framebuffer_init(struct drm_device *, struct nouveau_framebuffer *, struct nouveau_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; - int crtc, bpp, pitch, x, y; + struct drm_crtc *crtc; + int bpp, pitch; u64 offset; }; diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index ce2d67b..137fe69 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -32,7 +32,6 @@ struct omap_connector { struct drm_connector base; struct omap_dss_device *dssdev; - struct drm_encoder *encoder; bool hdmi_mode; }; @@ -256,13 +255,6 @@ static int omap_connector_mode_valid(struct drm_connector *connector, return ret; } -struct drm_encoder *omap_connector_attached_encoder( - struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - return omap_connector->encoder; -} - static const struct drm_connector_funcs omap_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .reset = drm_atomic_helper_connector_reset, @@ -276,7 +268,6 @@ static const struct drm_connector_funcs omap_connector_funcs = { static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { .get_modes = omap_connector_get_modes, .mode_valid = omap_connector_mode_valid, - .best_encoder = omap_connector_attached_encoder, }; /* initialize connector */ @@ -296,7 +287,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, goto fail; omap_connector->dssdev = dssdev; - omap_connector->encoder = encoder; connector = &omap_connector->base; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 3b70223..6b97011 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -174,7 +174,7 @@ static int omap_atomic_commit(struct drm_device *dev, spin_unlock(&priv->commit.lock); /* Swap the state, this is the point of no return. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) schedule_work(&commit->work); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 2e216e2..e91763d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -276,14 +276,14 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); if (dev->num_crtcs > radeon_crtc->crtc_id) - drm_vblank_on(dev, radeon_crtc->crtc_id); + drm_crtc_vblank_on(crtc); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: if (dev->num_crtcs > radeon_crtc->crtc_id) - drm_vblank_off(dev, radeon_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (radeon_crtc->enabled) atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index e85c7a2..3965d19 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -627,7 +627,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, return 0; vblank_cleanup: - drm_crtc_vblank_put(&radeon_crtc->base); + drm_crtc_vblank_put(crtc); pflip_cleanup: if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) { diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 478d409..d0de4022 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -332,14 +332,14 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); } if (dev->num_crtcs > radeon_crtc->crtc_id) - drm_vblank_on(dev, radeon_crtc->crtc_id); + drm_crtc_vblank_on(crtc); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: if (dev->num_crtcs > radeon_crtc->crtc_id) - drm_vblank_off(dev, radeon_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (radeon_crtc->crtc_id) WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask)); else { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 4e939e4..55149e9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -27,18 +27,6 @@ #include "rcar_du_vgacon.h" /* ----------------------------------------------------------------------------- - * Common connector functions - */ - -struct drm_encoder * -rcar_du_connector_best_encoder(struct drm_connector *connector) -{ - struct rcar_du_connector *rcon = to_rcar_connector(connector); - - return rcar_encoder_to_drm_encoder(rcon->encoder); -} - -/* ----------------------------------------------------------------------------- * Encoder */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index 719b6f2a..a8669c3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h @@ -49,9 +49,6 @@ struct rcar_du_connector { #define to_rcar_connector(c) \ container_of(c, struct rcar_du_connector, connector) -struct drm_encoder * -rcar_du_connector_best_encoder(struct drm_connector *connector); - int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_encoder_type type, enum rcar_du_output output, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c index 6c92714..612b4d5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -52,7 +52,6 @@ static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector, static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = rcar_du_hdmi_connector_get_modes, .mode_valid = rcar_du_hdmi_connector_mode_valid, - .best_encoder = rcar_du_connector_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 86c109b..6bb032d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -327,7 +327,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev, } /* Swap the state, this is the point of no return. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) schedule_work(&commit->work); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c index e905f5d..6afd0af 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c @@ -59,7 +59,6 @@ static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector) static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = rcar_du_lvds_connector_get_modes, - .best_encoder = rcar_du_connector_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 9d7e5c9..8d6125c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c @@ -28,7 +28,6 @@ static int rcar_du_vga_connector_get_modes(struct drm_connector *connector) static const struct drm_connector_helper_funcs connector_helper_funcs = { .get_modes = rcar_du_vga_connector_get_modes, - .best_encoder = rcar_du_connector_best_encoder, }; static enum drm_connector_status @@ -79,7 +78,5 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, if (ret < 0) return ret; - rcon->encoder = renc; - return 0; } diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 7f6a55c..c120172 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -349,20 +349,11 @@ static int rockchip_dp_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops rockchip_dp_pm_ops = { #ifdef CONFIG_PM_SLEEP -static int rockchip_dp_suspend(struct device *dev) -{ - return analogix_dp_suspend(dev); -} - -static int rockchip_dp_resume(struct device *dev) -{ - return analogix_dp_resume(dev); -} + .suspend = analogix_dp_suspend, + .resume_early = analogix_dp_resume, #endif - -static const struct dev_pm_ops rockchip_dp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume) }; static const struct of_device_id rockchip_dp_dt_ids[] = { diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index dedc65b..ca22e5e 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -964,18 +964,9 @@ static enum drm_mode_status dw_mipi_dsi_mode_valid( return mode_status; } -static struct drm_encoder *dw_mipi_dsi_connector_best_encoder( - struct drm_connector *connector) -{ - struct dw_mipi_dsi *dsi = con_to_dsi(connector); - - return &dsi->encoder; -} - static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = { .get_modes = dw_mipi_dsi_connector_get_modes, .mode_valid = dw_mipi_dsi_mode_valid, - .best_encoder = dw_mipi_dsi_connector_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f8b4feb..006260d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -579,14 +579,6 @@ inno_hdmi_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder * -inno_hdmi_connector_best_encoder(struct drm_connector *connector) -{ - struct inno_hdmi *hdmi = to_inno_hdmi(connector); - - return &hdmi->encoder; -} - static int inno_hdmi_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) @@ -613,7 +605,6 @@ static struct drm_connector_funcs inno_hdmi_connector_funcs = { static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { .get_modes = inno_hdmi_connector_get_modes, .mode_valid = inno_hdmi_connector_mode_valid, - .best_encoder = inno_hdmi_connector_best_encoder, }; static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 09a4d42..c2bcc5e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/of_graph.h> #include <linux/component.h> +#include <linux/console.h> #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" @@ -38,6 +39,7 @@ #define DRIVER_MINOR 0 static bool is_support_iommu = true; +static struct drm_driver rockchip_drm_driver; /* * Attach a (component) device to the shared drm dma mapping from master drm @@ -133,20 +135,28 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, priv->crtc_funcs[pipe]->disable_vblank(crtc); } -static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) +static int rockchip_drm_bind(struct device *dev) { + struct drm_device *drm_dev; struct rockchip_drm_private *private; struct dma_iommu_mapping *mapping = NULL; - struct device *dev = drm_dev->dev; - struct drm_connector *connector; int ret; - private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); - if (!private) + drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); + if (!drm_dev) return -ENOMEM; - mutex_init(&private->commit.lock); - INIT_WORK(&private->commit.work, rockchip_drm_atomic_work); + ret = drm_dev_register(drm_dev, 0); + if (ret) + goto err_free; + + dev_set_drvdata(dev, drm_dev); + + private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); + if (!private) { + ret = -ENOMEM; + goto err_unregister; + } drm_dev->dev_private = private; @@ -187,21 +197,10 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) if (ret) goto err_detach_device; - /* - * All components are now added, we can publish the connector sysfs - * entries to userspace. This will generate hotplug events and so - * userspace will expect to be able to access DRM at this point. - */ - list_for_each_entry(connector, &drm_dev->mode_config.connector_list, - head) { - ret = drm_connector_register(connector); - if (ret) { - dev_err(drm_dev->dev, - "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n", - connector->base.id, - connector->name, ret); - goto err_unbind; - } + ret = drm_connector_register_all(drm_dev); + if (ret) { + dev_err(dev, "failed to register connectors\n"); + goto err_unbind; } /* init kms poll for handling hpd */ @@ -241,12 +240,16 @@ err_release_mapping: err_config_cleanup: drm_mode_config_cleanup(drm_dev); drm_dev->dev_private = NULL; +err_unregister: + drm_dev_unregister(drm_dev); +err_free: + drm_dev_unref(drm_dev); return ret; } -static int rockchip_drm_unload(struct drm_device *drm_dev) +static void rockchip_drm_unbind(struct device *dev) { - struct device *dev = drm_dev->dev; + struct drm_device *drm_dev = dev_get_drvdata(dev); rockchip_drm_fbdev_fini(drm_dev); drm_vblank_cleanup(drm_dev); @@ -256,29 +259,9 @@ static int rockchip_drm_unload(struct drm_device *drm_dev) arm_iommu_detach_device(dev); drm_mode_config_cleanup(drm_dev); drm_dev->dev_private = NULL; - - return 0; -} - -static void rockchip_drm_crtc_cancel_pending_vblank(struct drm_crtc *crtc, - struct drm_file *file_priv) -{ - struct rockchip_drm_private *priv = crtc->dev->dev_private; - int pipe = drm_crtc_index(crtc); - - if (pipe < ROCKCHIP_MAX_CRTC && - priv->crtc_funcs[pipe] && - priv->crtc_funcs[pipe]->cancel_pending_vblank) - priv->crtc_funcs[pipe]->cancel_pending_vblank(crtc, file_priv); -} - -static void rockchip_drm_preclose(struct drm_device *dev, - struct drm_file *file_priv) -{ - struct drm_crtc *crtc; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv); + drm_dev_unregister(drm_dev); + drm_dev_unref(drm_dev); + dev_set_drvdata(dev, NULL); } void rockchip_drm_lastclose(struct drm_device *dev) @@ -304,9 +287,6 @@ static const struct file_operations rockchip_drm_driver_fops = { static struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, - .load = rockchip_drm_load, - .unload = rockchip_drm_unload, - .preclose = rockchip_drm_preclose, .lastclose = rockchip_drm_lastclose, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rockchip_drm_crtc_enable_vblank, @@ -333,25 +313,38 @@ static struct drm_driver rockchip_drm_driver = { }; #ifdef CONFIG_PM_SLEEP -static int rockchip_drm_sys_suspend(struct device *dev) +void rockchip_drm_fb_suspend(struct drm_device *drm) { - struct drm_device *drm = dev_get_drvdata(dev); - struct drm_connector *connector; + struct rockchip_drm_private *priv = drm->dev_private; - if (!drm) - return 0; + console_lock(); + drm_fb_helper_set_suspend(&priv->fbdev_helper, 1); + console_unlock(); +} + +void rockchip_drm_fb_resume(struct drm_device *drm) +{ + struct rockchip_drm_private *priv = drm->dev_private; - drm_modeset_lock_all(drm); - list_for_each_entry(connector, &drm->mode_config.connector_list, head) { - int old_dpms = connector->dpms; + console_lock(); + drm_fb_helper_set_suspend(&priv->fbdev_helper, 0); + console_unlock(); +} + +static int rockchip_drm_sys_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct rockchip_drm_private *priv = drm->dev_private; - if (connector->funcs->dpms) - connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); + drm_kms_helper_poll_disable(drm); + rockchip_drm_fb_suspend(drm); - /* Set the old mode back to the connector for resume */ - connector->dpms = old_dpms; + priv->state = drm_atomic_helper_suspend(drm); + if (IS_ERR(priv->state)) { + rockchip_drm_fb_resume(drm); + drm_kms_helper_poll_enable(drm); + return PTR_ERR(priv->state); } - drm_modeset_unlock_all(drm); return 0; } @@ -359,47 +352,11 @@ static int rockchip_drm_sys_suspend(struct device *dev) static int rockchip_drm_sys_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct drm_connector *connector; - enum drm_connector_status status; - bool changed = false; + struct rockchip_drm_private *priv = drm->dev_private; - if (!drm) - return 0; - - drm_modeset_lock_all(drm); - list_for_each_entry(connector, &drm->mode_config.connector_list, head) { - int desired_mode = connector->dpms; - - /* - * at suspend time, we save dpms to connector->dpms, - * restore the old_dpms, and at current time, the connector - * dpms status must be DRM_MODE_DPMS_OFF. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - - /* - * If the connector has been disconnected during suspend, - * disconnect it from the encoder and leave it off. We'll notify - * userspace at the end. - */ - if (desired_mode == DRM_MODE_DPMS_ON) { - status = connector->funcs->detect(connector, true); - if (status == connector_status_disconnected) { - connector->encoder = NULL; - connector->status = status; - changed = true; - continue; - } - } - if (connector->funcs->dpms) - connector->funcs->dpms(connector, desired_mode); - } - drm_modeset_unlock_all(drm); - - drm_helper_resume_force_mode(drm); - - if (changed) - drm_kms_helper_hotplug_event(drm); + drm_atomic_helper_resume(drm, priv->state); + rockchip_drm_fb_resume(drm); + drm_kms_helper_poll_enable(drm); return 0; } @@ -440,37 +397,6 @@ static void rockchip_add_endpoints(struct device *dev, } } -static int rockchip_drm_bind(struct device *dev) -{ - struct drm_device *drm; - int ret; - - drm = drm_dev_alloc(&rockchip_drm_driver, dev); - if (!drm) - return -ENOMEM; - - ret = drm_dev_register(drm, 0); - if (ret) - goto err_free; - - dev_set_drvdata(dev, drm); - - return 0; - -err_free: - drm_dev_unref(drm); - return ret; -} - -static void rockchip_drm_unbind(struct device *dev) -{ - struct drm_device *drm = dev_get_drvdata(dev); - - drm_dev_unregister(drm); - drm_dev_unref(drm); - dev_set_drvdata(dev, NULL); -} - static const struct component_master_ops rockchip_drm_ops = { .bind = rockchip_drm_bind, .unbind = rockchip_drm_unbind, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 56f43a3..ea39329 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -40,14 +40,6 @@ struct rockchip_crtc_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); void (*wait_for_update)(struct drm_crtc *crtc); - void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv); -}; - -struct rockchip_atomic_commit { - struct work_struct work; - struct drm_atomic_state *state; - struct drm_device *dev; - struct mutex lock; }; struct rockchip_crtc_state { @@ -68,11 +60,9 @@ struct rockchip_drm_private { struct drm_fb_helper fbdev_helper; struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; - - struct rockchip_atomic_commit commit; + struct drm_atomic_state *state; }; -void rockchip_drm_atomic_work(struct work_struct *work); int rockchip_register_crtc_funcs(struct drm_crtc *crtc, const struct rockchip_crtc_funcs *crtc_funcs); void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 755cfdb..20f12bc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -228,87 +228,32 @@ rockchip_atomic_wait_for_complete(struct drm_device *dev, struct drm_atomic_stat } static void -rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit) +rockchip_atomic_commit_tail(struct drm_atomic_state *state) { - struct drm_atomic_state *state = commit->state; - struct drm_device *dev = commit->dev; + struct drm_device *dev = state->dev; - /* - * TODO: do fence wait here. - */ - - /* - * Rockchip crtc support runtime PM, can't update display planes - * when crtc is disabled. - * - * drm_atomic_helper_commit comments detail that: - * For drivers supporting runtime PM the recommended sequence is - * - * drm_atomic_helper_commit_modeset_disables(dev, state); - * - * drm_atomic_helper_commit_modeset_enables(dev, state); - * - * drm_atomic_helper_commit_planes(dev, state, true); - * - * See the kerneldoc entries for these three functions for more details. - */ drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_modeset_enables(dev, state); drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_hw_done(state); + rockchip_atomic_wait_for_complete(dev, state); drm_atomic_helper_cleanup_planes(dev, state); - - drm_atomic_state_free(state); -} - -void rockchip_drm_atomic_work(struct work_struct *work) -{ - struct rockchip_atomic_commit *commit = container_of(work, - struct rockchip_atomic_commit, work); - - rockchip_atomic_commit_complete(commit); } -int rockchip_drm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - struct rockchip_drm_private *private = dev->dev_private; - struct rockchip_atomic_commit *commit = &private->commit; - int ret; - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - /* serialize outstanding nonblocking commits */ - mutex_lock(&commit->lock); - flush_work(&commit->work); - - drm_atomic_helper_swap_state(dev, state); - - commit->dev = dev; - commit->state = state; - - if (nonblock) - schedule_work(&commit->work); - else - rockchip_atomic_commit_complete(commit); - - mutex_unlock(&commit->lock); - - return 0; -} +struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = { + .atomic_commit_tail = rockchip_atomic_commit_tail, +}; static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { .fb_create = rockchip_user_fb_create, .output_poll_changed = rockchip_drm_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = rockchip_drm_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; struct drm_framebuffer * @@ -339,4 +284,5 @@ void rockchip_drm_mode_config_init(struct drm_device *dev) dev->mode_config.max_height = 4096; dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; + dev->mode_config.helper_private = &rockchip_mode_config_helpers; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index f261512..207e01d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -108,7 +108,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, fbi->screen_size = rk_obj->base.size; fbi->fix.smem_len = rk_obj->base.size; - DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%d\n", + DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%zu\n", fb->width, fb->height, fb->depth, rk_obj->kvaddr, offset, size); @@ -156,9 +156,6 @@ int rockchip_drm_fbdev_init(struct drm_device *dev) goto err_drm_fb_helper_fini; } - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { dev_err(dev->dev, "Failed to set initial hw config - %d.\n", diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 9c2d8a8..059e902 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -38,7 +38,7 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj, &rk_obj->dma_addr, GFP_KERNEL, &rk_obj->dma_attrs); if (!rk_obj->kvaddr) { - DRM_ERROR("failed to allocate %#x byte dma buffer", obj->size); + DRM_ERROR("failed to allocate %zu byte dma buffer", obj->size); return -ENOMEM; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 5567fb4..8cd840f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -98,7 +98,9 @@ struct vop_win { const struct vop_win_data *data; struct vop *vop; - struct vop_plane_state state; + /* protected by dev->event_lock */ + bool enable; + dma_addr_t yrgb_mst; }; struct vop { @@ -112,6 +114,8 @@ struct vop { bool vsync_work_pending; struct completion dsp_hold_completion; struct completion wait_update_complete; + + /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; const struct vop_data *data; @@ -431,9 +435,6 @@ static void vop_enable(struct drm_crtc *crtc) struct vop *vop = to_vop(crtc); int ret; - if (vop->is_enabled) - return; - ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); @@ -501,8 +502,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc) struct vop *vop = to_vop(crtc); int i; - if (!vop->is_enabled) - return; + WARN_ON(vop->event); /* * We need to make sure that all windows are disabled before we @@ -553,6 +553,14 @@ static void vop_crtc_disable(struct drm_crtc *crtc) clk_disable(vop->aclk); clk_disable(vop->hclk); pm_runtime_put(vop->dev); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + + crtc->state->event = NULL; + } } static void vop_plane_destroy(struct drm_plane *plane) @@ -658,6 +666,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, if (!old_state->crtc) return; + spin_lock_irq(&plane->dev->event_lock); + vop_win->enable = false; + vop_win->yrgb_mst = 0; + spin_unlock_irq(&plane->dev->event_lock); + spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, enable, 0); @@ -692,7 +705,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, /* * can't update plane when vop is disabled. */ - if (!crtc) + if (WARN_ON(!crtc)) return; if (WARN_ON(!vop->is_enabled)) @@ -721,6 +734,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, offset += (src->y1 >> 16) * fb->pitches[0]; vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; + spin_lock_irq(&plane->dev->event_lock); + vop_win->enable = true; + vop_win->yrgb_mst = vop_plane_state->yrgb_mst; + spin_unlock_irq(&plane->dev->event_lock); + spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, format, vop_plane_state->format); @@ -876,30 +894,10 @@ static void vop_crtc_wait_for_update(struct drm_crtc *crtc) WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100)); } -static void vop_crtc_cancel_pending_vblank(struct drm_crtc *crtc, - struct drm_file *file_priv) -{ - struct drm_device *drm = crtc->dev; - struct vop *vop = to_vop(crtc); - struct drm_pending_vblank_event *e; - unsigned long flags; - - spin_lock_irqsave(&drm->event_lock, flags); - e = vop->event; - if (e && e->base.file_priv == file_priv) { - vop->event = NULL; - - kfree(&e->base); - file_priv->event_space += sizeof(e->event); - } - spin_unlock_irqrestore(&drm->event_lock, flags); -} - static const struct rockchip_crtc_funcs private_crtc_funcs = { .enable_vblank = vop_crtc_enable_vblank, .disable_vblank = vop_crtc_disable_vblank, .wait_for_update = vop_crtc_wait_for_update, - .cancel_pending_vblank = vop_crtc_cancel_pending_vblank, }; static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, @@ -931,6 +929,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) u16 vact_end = vact_st + vdisplay; uint32_t val; + WARN_ON(vop->event); + vop_enable(crtc); /* * If dclk rate is zero, mean that scanout is stop, @@ -1027,12 +1027,15 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc, { struct vop *vop = to_vop(crtc); + spin_lock_irq(&crtc->dev->event_lock); if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc) != 0); + WARN_ON(vop->event); vop->event = crtc->state->event; crtc->state->event = NULL; } + spin_unlock_irq(&crtc->dev->event_lock); } static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { @@ -1080,16 +1083,14 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { static bool vop_win_pending_is_complete(struct vop_win *vop_win) { - struct drm_plane *plane = &vop_win->base; - struct vop_plane_state *state = to_vop_plane_state(plane->state); dma_addr_t yrgb_mst; - if (!state->enable) + if (!vop_win->enable) return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0; yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data); - return yrgb_mst == state->yrgb_mst; + return yrgb_mst == vop_win->yrgb_mst; } static void vop_handle_vblank(struct vop *vop) @@ -1104,15 +1105,16 @@ static void vop_handle_vblank(struct vop *vop) return; } + spin_lock_irqsave(&drm->event_lock, flags); if (vop->event) { - spin_lock_irqsave(&drm->event_lock, flags); drm_crtc_send_vblank_event(crtc, vop->event); drm_crtc_vblank_put(crtc); vop->event = NULL; - spin_unlock_irqrestore(&drm->event_lock, flags); } + spin_unlock_irqrestore(&drm->event_lock, flags); + if (!completion_done(&vop->wait_update_complete)) complete(&vop->wait_update_complete); } diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index b440617..dd2c400 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -215,7 +215,7 @@ static int sti_atomic_commit(struct drm_device *drm, * the software side now. */ - drm_atomic_helper_swap_state(drm, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) sti_atomic_schedule(private, state); diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index d439128..e290166 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -377,20 +377,10 @@ static int sti_dvo_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector) -{ - struct sti_dvo_connector *dvo_connector - = to_sti_dvo_connector(connector); - - /* Best encoder is the one associated during connector creation */ - return dvo_connector->encoder; -} - static const struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = { .get_modes = sti_dvo_connector_get_modes, .mode_valid = sti_dvo_connector_mode_valid, - .best_encoder = sti_dvo_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 9f49c00..dcec5a8 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -669,20 +669,10 @@ static int sti_hda_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector) -{ - struct sti_hda_connector *hda_connector - = to_sti_hda_connector(connector); - - /* Best encoder is the one associated during connector creation */ - return hda_connector->encoder; -} - static const struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = { .get_modes = sti_hda_connector_get_modes, .mode_valid = sti_hda_connector_mode_valid, - .best_encoder = sti_hda_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 85545eb..36d9d66 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -890,20 +890,10 @@ static int sti_hdmi_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector) -{ - struct sti_hdmi_connector *hdmi_connector - = to_sti_hdmi_connector(connector); - - /* Best encoder is the one associated during connector creation */ - return hdmi_connector->encoder; -} - static const struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = { .get_modes = sti_hdmi_connector_get_modes, .mode_valid = sti_hdmi_connector_mode_valid, - .best_encoder = sti_hdmi_best_encoder, }; /* get detection status of display device */ diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 4182a21..f628b6d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -51,10 +51,22 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, { struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); struct sun4i_drv *drv = scrtc->drv; + struct drm_pending_vblank_event *event = crtc->state->event; DRM_DEBUG_DRIVER("Committing plane changes\n"); sun4i_backend_commit(drv->backend); + + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } } static void sun4i_crtc_disable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index ab64948..442cfe2 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -90,19 +90,9 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder * -sun4i_rgb_best_encoder(struct drm_connector *connector) -{ - struct sun4i_rgb *rgb = - drm_connector_to_sun4i_rgb(connector); - - return &rgb->encoder; -} - static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { .get_modes = sun4i_rgb_get_modes, .mode_valid = sun4i_rgb_mode_valid, - .best_encoder = sun4i_rgb_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index bc047f9..b841478 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -526,18 +526,9 @@ static int sun4i_tv_comp_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_encoder * -sun4i_tv_comp_best_encoder(struct drm_connector *connector) -{ - struct sun4i_tv *tv = drm_connector_to_sun4i_tv(connector); - - return &tv->encoder; -} - static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = { .get_modes = sun4i_tv_comp_get_modes, .mode_valid = sun4i_tv_comp_mode_valid, - .best_encoder = sun4i_tv_comp_best_encoder, }; static enum drm_connector_status diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index b59c3bf0..a177a42 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -93,7 +93,7 @@ static int tegra_atomic_commit(struct drm_device *drm, * the software side now. */ - drm_atomic_helper_swap_state(drm, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) tegra_atomic_schedule(tegra, state); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index f52d6cb2..0ddcce1 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -239,8 +239,6 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output); void tegra_output_exit(struct tegra_output *output); int tegra_output_connector_get_modes(struct drm_connector *connector); -struct drm_encoder * -tegra_output_connector_best_encoder(struct drm_connector *connector); enum drm_connector_status tegra_output_connector_detect(struct drm_connector *connector, bool force); void tegra_output_connector_destroy(struct drm_connector *connector); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index d1239eb..099cccb 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -794,7 +794,6 @@ tegra_dsi_connector_mode_valid(struct drm_connector *connector, static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = { .get_modes = tegra_output_connector_get_modes, .mode_valid = tegra_dsi_connector_mode_valid, - .best_encoder = tegra_output_connector_best_encoder, }; static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = { diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index b7ef492..2fdb879 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -806,7 +806,6 @@ static const struct drm_connector_helper_funcs tegra_hdmi_connector_helper_funcs = { .get_modes = tegra_output_connector_get_modes, .mode_valid = tegra_hdmi_connector_mode_valid, - .best_encoder = tegra_output_connector_best_encoder, }; static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = { diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 46664b6..1480f6a 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -42,14 +42,6 @@ int tegra_output_connector_get_modes(struct drm_connector *connector) return err; } -struct drm_encoder * -tegra_output_connector_best_encoder(struct drm_connector *connector) -{ - struct tegra_output *output = connector_to_output(connector); - - return &output->encoder; -} - enum drm_connector_status tegra_output_connector_detect(struct drm_connector *connector, bool force) { diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index e246334..a131b44 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -112,7 +112,6 @@ tegra_rgb_connector_mode_valid(struct drm_connector *connector, static const struct drm_connector_helper_funcs tegra_rgb_connector_helper_funcs = { .get_modes = tegra_output_connector_get_modes, .mode_valid = tegra_rgb_connector_mode_valid, - .best_encoder = tegra_output_connector_best_encoder, }; static const struct drm_encoder_funcs tegra_rgb_encoder_funcs = { diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 757c6e8..34958d7 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1087,7 +1087,6 @@ tegra_sor_connector_mode_valid(struct drm_connector *connector, static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = { .get_modes = tegra_sor_connector_get_modes, .mode_valid = tegra_sor_connector_mode_valid, - .best_encoder = tegra_output_connector_best_encoder, }; static const struct drm_encoder_funcs tegra_sor_encoder_funcs = { diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 9817dbf..dba1114 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -208,14 +208,6 @@ static int vc4_dpi_connector_get_modes(struct drm_connector *connector) return 0; } -static struct drm_encoder * -vc4_dpi_connector_best_encoder(struct drm_connector *connector) -{ - struct vc4_dpi_connector *dpi_connector = - to_vc4_dpi_connector(connector); - return dpi_connector->encoder; -} - static const struct drm_connector_funcs vc4_dpi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = vc4_dpi_connector_detect, @@ -228,7 +220,6 @@ static const struct drm_connector_funcs vc4_dpi_connector_funcs = { static const struct drm_connector_helper_funcs vc4_dpi_connector_helper_funcs = { .get_modes = vc4_dpi_connector_get_modes, - .best_encoder = vc4_dpi_connector_best_encoder, }; static struct drm_connector *vc4_dpi_connector_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index fd2644d..68df91c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -208,14 +208,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } -static struct drm_encoder * -vc4_hdmi_connector_best_encoder(struct drm_connector *connector) -{ - struct vc4_hdmi_connector *hdmi_connector = - to_vc4_hdmi_connector(connector); - return hdmi_connector->encoder; -} - static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = vc4_hdmi_connector_detect, @@ -228,7 +220,6 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { .get_modes = vc4_hdmi_connector_get_modes, - .best_encoder = vc4_hdmi_connector_best_encoder, }; static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 39c0b20..8f4d5ff 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -148,7 +148,7 @@ static int vc4_atomic_commit(struct drm_device *dev, * the software side now. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); /* * Everything below can be run asynchronously without the need to grab diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index d82ae1c..ac758cd 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -38,56 +38,11 @@ #define XRES_MAX 8192 #define YRES_MAX 8192 -static int virtio_gpu_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t flags) -{ - struct virtio_gpu_device *vgdev = crtc->dev->dev_private; - struct virtio_gpu_output *output = - container_of(crtc, struct virtio_gpu_output, crtc); - struct drm_plane *plane = crtc->primary; - struct virtio_gpu_framebuffer *vgfb; - struct virtio_gpu_object *bo; - unsigned long irqflags; - uint32_t handle; - - plane->fb = fb; - vgfb = to_virtio_gpu_framebuffer(plane->fb); - bo = gem_to_virtio_gpu_obj(vgfb->obj); - handle = bo->hw_res_handle; - - DRM_DEBUG("handle 0x%x%s, crtc %dx%d\n", handle, - bo->dumb ? ", dumb" : "", - crtc->mode.hdisplay, crtc->mode.vdisplay); - if (bo->dumb) { - virtio_gpu_cmd_transfer_to_host_2d - (vgdev, handle, 0, - cpu_to_le32(crtc->mode.hdisplay), - cpu_to_le32(crtc->mode.vdisplay), - 0, 0, NULL); - } - virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, - crtc->mode.hdisplay, - crtc->mode.vdisplay, 0, 0); - virtio_gpu_cmd_resource_flush(vgdev, handle, 0, 0, - crtc->mode.hdisplay, - crtc->mode.vdisplay); - - if (event) { - spin_lock_irqsave(&crtc->dev->event_lock, irqflags); - drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irqrestore(&crtc->dev->event_lock, irqflags); - } - - return 0; -} - static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, - .page_flip = virtio_gpu_page_flip, + .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, @@ -185,6 +140,7 @@ static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock_irqsave(&crtc->dev->event_lock, flags); if (crtc->state->event) drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } @@ -259,15 +215,6 @@ static int virtio_gpu_conn_mode_valid(struct drm_connector *connector, return MODE_BAD; } -static struct drm_encoder* -virtio_gpu_best_encoder(struct drm_connector *connector) -{ - struct virtio_gpu_output *virtio_gpu_output = - drm_connector_to_virtio_gpu_output(connector); - - return &virtio_gpu_output->enc; -} - static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs = { .mode_set = virtio_gpu_enc_mode_set, .enable = virtio_gpu_enc_enable, @@ -277,7 +224,6 @@ static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs = { static const struct drm_connector_helper_funcs virtio_gpu_conn_helper_funcs = { .get_modes = virtio_gpu_conn_get_modes, .mode_valid = virtio_gpu_conn_mode_valid, - .best_encoder = virtio_gpu_best_encoder, }; static enum drm_connector_status virtio_gpu_conn_detect( @@ -388,30 +334,28 @@ virtio_gpu_user_framebuffer_create(struct drm_device *dev, return &virtio_gpu_fb->base; } -static int vgdev_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) +static void vgdev_atomic_commit_tail(struct drm_atomic_state *state) { - if (nonblock) - return -EBUSY; - - drm_atomic_helper_swap_state(dev, state); - drm_atomic_helper_wait_for_fences(dev, state); + struct drm_device *dev = state->dev; drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_modeset_enables(dev, state); drm_atomic_helper_commit_planes(dev, state, true); + drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - return 0; } +struct drm_mode_config_helper_funcs virtio_mode_config_helpers = { + .atomic_commit_tail = vgdev_atomic_commit_tail, +}; + static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = { .fb_create = virtio_gpu_user_framebuffer_create, .atomic_check = drm_atomic_helper_check, - .atomic_commit = vgdev_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) @@ -419,7 +363,8 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) int i; drm_mode_config_init(vgdev->ddev); - vgdev->ddev->mode_config.funcs = (void *)&virtio_gpu_mode_funcs; + vgdev->ddev->mode_config.funcs = &virtio_gpu_mode_funcs; + vgdev->ddev->mode_config.helper_private = &virtio_mode_config_helpers; /* modes will be validated against the framebuffer size */ vgdev->ddev->mode_config.min_width = XRES_MIN; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 67cebb2..aa04fb0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -293,13 +293,10 @@ static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header) struct vmw_cmdbuf_man *man = header->man; u32 val; - if (sizeof(header->handle) > 4) - val = (header->handle >> 32); - else - val = 0; + val = upper_32_bits(header->handle); vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val); - val = (header->handle & 0xFFFFFFFFULL); + val = lower_32_bits(header->handle); val |= header->cb_context & SVGA_CB_CONTEXT_MASK; vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 9e5eefd..04310cb 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -68,6 +68,7 @@ #include <drm/drm_agpsupport.h> #include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> #include <drm/drm_global.h> #include <drm/drm_hashtab.h> #include <drm/drm_mem_util.h> @@ -283,6 +284,7 @@ struct drm_ioctl_desc { /* Event queued up for userspace to read */ struct drm_pending_event { + struct completion *completion; struct drm_event *event; struct fence *fence; struct list_head link; @@ -417,8 +419,6 @@ struct drm_driver { void (*postclose) (struct drm_device *, struct drm_file *); void (*lastclose) (struct drm_device *); int (*unload) (struct drm_device *); - int (*suspend) (struct drm_device *, pm_message_t state); - int (*resume) (struct drm_device *); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); int (*dma_quiescent) (struct drm_device *); int (*context_dtor) (struct drm_device *dev, int context); @@ -969,18 +969,12 @@ extern u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, struct timeval *vblanktime); extern u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, struct timeval *vblanktime); -extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe, - struct drm_pending_vblank_event *e); extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e); -extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, - struct drm_pending_vblank_event *e); extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe); extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc); -extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe); -extern void drm_vblank_put(struct drm_device *dev, unsigned int pipe); extern int drm_crtc_vblank_get(struct drm_crtc *crtc); extern void drm_crtc_vblank_put(struct drm_crtc *crtc); extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index d12cfb9..856a9c8 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -30,6 +30,12 @@ #include <drm/drm_crtc.h> +void drm_crtc_commit_put(struct drm_crtc_commit *commit); +static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit) +{ + kref_get(&commit->ref); +} + struct drm_atomic_state * __must_check drm_atomic_state_alloc(struct drm_device *dev); void drm_atomic_state_clear(struct drm_atomic_state *state); @@ -198,6 +204,16 @@ int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); (plane_state) = (__state)->planes[__i].state, 1); \ (__i)++) \ for_each_if (plane_state) + +/** + * drm_atomic_crtc_needs_modeset - compute combined modeset need + * @state: &drm_crtc_state for the CRTC + * + * To give drivers flexibility struct &drm_crtc_state has 3 booleans to track + * whether the state CRTC changed enough to need a full modeset cycle: + * connectors_changed, mode_changed and active_change. This helper simply + * combines these three to compute the overall need for a modeset for @state. + */ static inline bool drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 1877a7c..d86ae5d 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -38,6 +38,7 @@ int drm_atomic_helper_check_planes(struct drm_device *dev, struct drm_atomic_state *state); int drm_atomic_helper_check(struct drm_device *dev, struct drm_atomic_state *state); +void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); int drm_atomic_helper_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock); @@ -71,8 +72,15 @@ void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_sta void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, bool atomic); -void drm_atomic_helper_swap_state(struct drm_device *dev, - struct drm_atomic_state *state); +void drm_atomic_helper_swap_state(struct drm_atomic_state *state, + bool stall); + +/* nonblocking commit helpers */ +int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, + bool nonblock); +void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state); +void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state); +void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state); /* implementations for legacy interfaces */ int drm_atomic_helper_update_plane(struct drm_plane *plane, @@ -159,7 +167,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * This iterates over the current state, useful (for example) when applying * atomic state after it has been checked and swapped. To iterate over the * planes which *will* be attached (for ->atomic_check()) see - * drm_crtc_for_each_pending_plane(). + * drm_atomic_crtc_state_for_each_plane(). */ #define drm_atomic_crtc_for_each_plane(plane, crtc) \ drm_for_each_plane_mask(plane, (crtc)->dev, (crtc)->state->plane_mask) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1a8d66c..914baa8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -728,9 +728,6 @@ struct drm_crtc_funcs { * @gamma_store: gamma ramp values * @helper_private: mid-layer private data * @properties: property tracking for this CRTC - * @state: current atomic state for this CRTC - * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for - * legacy IOCTLs * * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. @@ -787,11 +784,37 @@ struct drm_crtc { struct drm_object_properties properties; + /** + * @state: + * + * Current atomic state for this CRTC. + */ struct drm_crtc_state *state; - /* - * For legacy crtc IOCTLs so that atomic drivers can get at the locking - * acquire context. + /** + * @commit_list: + * + * List of &drm_crtc_commit structures tracking pending commits. + * Protected by @commit_lock. This list doesn't hold its own full + * reference, but burrows it from the ongoing commit. Commit entries + * must be removed from this list once the commit is fully completed, + * but before it's correspoding &drm_atomic_state gets destroyed. + */ + struct list_head commit_list; + + /** + * @commit_lock: + * + * Spinlock to protect @commit_list. + */ + spinlock_t commit_lock; + + /** + * @acquire_ctx: + * + * Per-CRTC implicit acquire context used by atomic drivers for legacy + * IOCTLs, so that atomic drivers can get at the locking acquire + * context. */ struct drm_modeset_acquire_ctx *acquire_ctx; }; @@ -1733,6 +1756,111 @@ struct drm_bridge { void *driver_private; }; +/** + * struct drm_crtc_commit - track modeset commits on a CRTC + * + * This structure is used to track pending modeset changes and atomic commit on + * a per-CRTC basis. Since updating the list should never block this structure + * is reference counted to allow waiters to safely wait on an event to complete, + * without holding any locks. + * + * It has 3 different events in total to allow a fine-grained synchronization + * between outstanding updates:: + * + * atomic commit thread hardware + * + * write new state into hardware ----> ... + * signal hw_done + * switch to new state on next + * ... v/hblank + * + * wait for buffers to show up ... + * + * ... send completion irq + * irq handler signals flip_done + * cleanup old buffers + * + * signal cleanup_done + * + * wait for flip_done <---- + * clean up atomic state + * + * The important bit to know is that cleanup_done is the terminal event, but the + * ordering between flip_done and hw_done is entirely up to the specific driver + * and modeset state change. + * + * For an implementation of how to use this look at + * drm_atomic_helper_setup_commit() from the atomic helper library. + */ +struct drm_crtc_commit { + /** + * @crtc: + * + * DRM CRTC for this commit. + */ + struct drm_crtc *crtc; + + /** + * @ref: + * + * Reference count for this structure. Needed to allow blocking on + * completions without the risk of the completion disappearing + * meanwhile. + */ + struct kref ref; + + /** + * @flip_done: + * + * Will be signaled when the hardware has flipped to the new set of + * buffers. Signals at the same time as when the drm event for this + * commit is sent to userspace, or when an out-fence is singalled. Note + * that for most hardware, in most cases this happens after @hw_done is + * signalled. + */ + struct completion flip_done; + + /** + * @hw_done: + * + * Will be signalled when all hw register changes for this commit have + * been written out. Especially when disabling a pipe this can be much + * later than than @flip_done, since that can signal already when the + * screen goes black, whereas to fully shut down a pipe more register + * I/O is required. + * + * Note that this does not need to include separately reference-counted + * resources like backing storage buffer pinning, or runtime pm + * management. + */ + struct completion hw_done; + + /** + * @cleanup_done: + * + * Will be signalled after old buffers have been cleaned up by calling + * drm_atomic_helper_cleanup_planes(). Since this can only happen after + * a vblank wait completed it might be a bit later. This completion is + * useful to throttle updates and avoid hardware updates getting ahead + * of the buffer cleanup too much. + */ + struct completion cleanup_done; + + /** + * @commit_entry: + * + * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock. + */ + struct list_head commit_entry; + + /** + * @event: + * + * &drm_pending_vblank_event pointer to clean up private events. + */ + struct drm_pending_vblank_event *event; +}; + struct __drm_planes_state { struct drm_plane *ptr; struct drm_plane_state *state; @@ -1741,6 +1869,7 @@ struct __drm_planes_state { struct __drm_crtcs_state { struct drm_crtc *ptr; struct drm_crtc_state *state; + struct drm_crtc_commit *commit; }; struct __drm_connnectors_state { @@ -1771,6 +1900,14 @@ struct drm_atomic_state { struct __drm_connnectors_state *connectors; struct drm_modeset_acquire_ctx *acquire_ctx; + + /** + * @commit_work: + * + * Work item which can be used by the driver or helpers to execute the + * commit without blocking. + */ + struct work_struct commit_work; }; @@ -2111,6 +2248,7 @@ struct drm_mode_config_funcs { * @async_page_flip: does this device support async flips on the primary plane? * @cursor_width: hint to userspace for max cursor width * @cursor_height: hint to userspace for max cursor height + * @helper_private: mid-layer private data * * Core mode resource tracking structure. All CRTC, encoders, and connectors * enumerated by the driver are added here, as are global properties. Some @@ -2254,6 +2392,8 @@ struct drm_mode_config { /* cursor size */ uint32_t cursor_width, cursor_height; + + struct drm_mode_config_helper_funcs *helper_private; }; /** @@ -2645,15 +2785,6 @@ extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, extern int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, - int *bpp); -extern int drm_format_num_planes(uint32_t format); -extern int drm_format_plane_cpp(uint32_t format, int plane); -extern int drm_format_horz_chroma_subsampling(uint32_t format); -extern int drm_format_vert_chroma_subsampling(uint32_t format); -extern int drm_format_plane_width(int width, uint32_t format, int plane); -extern int drm_format_plane_height(int height, uint32_t format, int plane); -extern const char *drm_get_format_name(uint32_t format); extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, unsigned int supported_rotations); extern unsigned int drm_rotation_simplify(unsigned int rotation, diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 5b4aa35..db8d478 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -212,17 +212,6 @@ struct drm_fb_helper { * needs to be reprobe when fbdev is in control again. */ bool delayed_hotplug; - - /** - * @atomic: - * - * Use atomic updates for restore_fbdev_mode(), etc. This defaults to - * true if driver has DRIVER_ATOMIC feature flag, but drivers can - * override it to true after drm_fb_helper_init() if they support atomic - * modeset but do not yet advertise DRIVER_ATOMIC (note that fb-helper - * does not require ASYNC commits). - */ - bool atomic; }; #ifdef CONFIG_DRM_FBDEV_EMULATION diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h new file mode 100644 index 0000000..7f90a39 --- /dev/null +++ b/include/drm/drm_fourcc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#ifndef __DRM_FOURCC_H__ +#define __DRM_FOURCC_H__ + +#include <linux/types.h> +#include <uapi/drm/drm_fourcc.h> + +void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); +int drm_format_num_planes(uint32_t format); +int drm_format_plane_cpp(uint32_t format, int plane); +int drm_format_horz_chroma_subsampling(uint32_t format); +int drm_format_vert_chroma_subsampling(uint32_t format); +int drm_format_plane_width(int width, uint32_t format, int plane); +int drm_format_plane_height(int height, uint32_t format, int plane); +const char *drm_get_format_name(uint32_t format); + +#endif /* __DRM_FOURCC_H__ */ diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index ec55285..72f5b15 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -180,6 +180,8 @@ struct mipi_dsi_device { unsigned long mode_flags; }; +#define MIPI_DSI_MODULE_PREFIX "mipi-dsi:" + static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev) { return container_of(dev, struct mipi_dsi_device, dev); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 4e7a53b..b55f218 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -931,4 +931,43 @@ static inline void drm_plane_helper_add(struct drm_plane *plane, plane->helper_private = funcs; } +/** + * struct drm_mode_config_helper_funcs - global modeset helper operations + * + * These helper functions are used by the atomic helpers. + */ +struct drm_mode_config_helper_funcs { + /** + * @atomic_commit_tail: + * + * This hook is used by the default atomic_commit() hook implemented in + * drm_atomic_helper_commit() together with the nonblocking commit + * helpers (see drm_atomic_helper_setup_commit() for a starting point) + * to implement blocking and nonblocking commits easily. It is not used + * by the atomic helpers + * + * This hook should first commit the given atomic state to the hardware. + * But drivers can add more waiting calls at the start of their + * implementation, e.g. to wait for driver-internal request for implicit + * syncing, before starting to commit the update to the hardware. + * + * After the atomic update is committed to the hardware this hook needs + * to call drm_atomic_helper_commit_hw_done(). Then wait for the upate + * to be executed by the hardware, for example using + * drm_atomic_helper_wait_for_vblanks(), and then clean up the old + * framebuffers using drm_atomic_helper_cleanup_planes(). + * + * When disabling a CRTC this hook _must_ stall for the commit to + * complete. Vblank waits don't work on disabled CRTC, hence the core + * can't take care of this. And it also can't rely on the vblank event, + * since that can be signalled already when the screen shows black, + * which can happen much earlier than the last hardware access needed to + * shut off the display pipeline completely. + * + * This hook is optional, the default implementation is + * drm_atomic_helper_commit_tail(). + */ + void (*atomic_commit_tail)(struct drm_atomic_state *state); +}; + #endif diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h new file mode 100644 index 0000000..2690397 --- /dev/null +++ b/include/drm/drm_simple_kms_helper.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 Noralf Trønnes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_DRM_SIMPLE_KMS_HELPER_H +#define __LINUX_DRM_SIMPLE_KMS_HELPER_H + +struct drm_simple_display_pipe; + +/** + * struct drm_simple_display_pipe_funcs - helper operations for a simple + * display pipeline + */ +struct drm_simple_display_pipe_funcs { + /** + * @enable: + * + * This function should be used to enable the pipeline. + * It is called when the underlying crtc is enabled. + * This hook is optional. + */ + void (*enable)(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state); + /** + * @disable: + * + * This function should be used to disable the pipeline. + * It is called when the underlying crtc is disabled. + * This hook is optional. + */ + void (*disable)(struct drm_simple_display_pipe *pipe); + + /** + * @check: + * + * This function is called in the check phase of an atomic update, + * specifically when the underlying plane is checked. + * The simple display pipeline helpers already check that the plane is + * not scaled, fills the entire visible area and is always enabled + * when the crtc is also enabled. + * This hook is optional. + * + * RETURNS: + * + * 0 on success, -EINVAL if the state or the transition can't be + * supported, -ENOMEM on memory allocation failure and -EDEADLK if an + * attempt to obtain another state object ran into a &drm_modeset_lock + * deadlock. + */ + int (*check)(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state, + struct drm_crtc_state *crtc_state); + /** + * @update: + * + * This function is called when the underlying plane state is updated. + * This hook is optional. + */ + void (*update)(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state); +}; + +/** + * struct drm_simple_display_pipe - simple display pipeline + * @crtc: CRTC control structure + * @plane: Plane control structure + * @encoder: Encoder control structure + * @connector: Connector control structure + * @funcs: Pipeline control functions (optional) + * + * Simple display pipeline with plane, crtc and encoder collapsed into one + * entity. It should be initialized by calling drm_simple_display_pipe_init(). + */ +struct drm_simple_display_pipe { + struct drm_crtc crtc; + struct drm_plane plane; + struct drm_encoder encoder; + struct drm_connector *connector; + + const struct drm_simple_display_pipe_funcs *funcs; +}; + +int drm_simple_display_pipe_init(struct drm_device *dev, + struct drm_simple_display_pipe *pipe, + const struct drm_simple_display_pipe_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + struct drm_connector *connector); + +#endif /* __LINUX_DRM_SIMPLE_KMS_HELPER_H */ diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 2fc8fad..27757c21 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -59,6 +59,12 @@ Output format selection (mutually exclusive): -text Output plain text format. Output selection (mutually exclusive): + -export Only output documentation for symbols that have been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in the same FILE. + -internal Only output documentation for symbols that have NOT been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in the same FILE. -function NAME Only output documentation for the given function(s) or DOC: section title(s). All other functions and DOC: sections are ignored. May be specified multiple times. @@ -68,6 +74,8 @@ Output selection (mutually exclusive): Output selection modifiers: -no-doc-sections Do not output DOC: sections. + -enable-lineno Enable output of #define LINENO lines. Only works with + reStructuredText format. Other parameters: -v Verbose output, more warnings and other information. @@ -206,6 +214,10 @@ my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; my $type_enum_full = '\&(enum)\s*([_\w]+)'; my $type_struct_full = '\&(struct)\s*([_\w]+)'; +my $type_typedef_full = '\&(typedef)\s*([_\w]+)'; +my $type_union_full = '\&(union)\s*([_\w]+)'; +my $type_member = '\&([_\w]+)((\.|->)[_\w]+)'; +my $type_member_func = $type_member . '\(\)'; # Output conversion substitutions. # One for each output format @@ -274,10 +286,16 @@ my $blankline_text = ""; # rst-mode my @highlights_rst = ( [$type_constant, "``\$1``"], - [$type_func, "\\:c\\:func\\:`\$1`"], + # Note: need to escape () to avoid func matching later + [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"], + [$type_func, "\\:c\\:func\\:`\$1()`"], [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], - [$type_struct, "\\:c\\:type\\:`struct \$1 <\$1>`"], + [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + # in rst this can refer to any type + [$type_struct, "\\:c\\:type\\:`\$1`"], [$type_param, "**\$1**"] ); my $blankline_rst = "\n"; @@ -303,10 +321,19 @@ my $verbose = 0; my $output_mode = "man"; my $output_preformatted = 0; my $no_doc_sections = 0; +my $enable_lineno = 0; my @highlights = @highlights_man; my $blankline = $blankline_man; my $modulename = "Kernel API"; -my $function_only = 0; + +use constant { + OUTPUT_ALL => 0, # output all symbols and doc sections + OUTPUT_INCLUDE => 1, # output only specified symbols + OUTPUT_EXCLUDE => 2, # output everything except specified symbols + OUTPUT_EXPORTED => 3, # output exported symbols + OUTPUT_INTERNAL => 4, # output non-exported symbols +}; +my $output_selection = OUTPUT_ALL; my $show_not_found = 0; my @build_time; @@ -327,6 +354,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', # CAVEAT EMPTOR! Some of the others I localised may not want to be, which # could cause "use of undefined value" or other bugs. my ($function, %function_table, %parametertypes, $declaration_purpose); +my $declaration_start_line; my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $brcount, %source_map); @@ -344,52 +372,62 @@ my $section_counter = 0; my $lineprefix=""; -# states -# 0 - normal code -# 1 - looking for function name -# 2 - scanning field start. -# 3 - scanning prototype. -# 4 - documentation block -# 5 - gathering documentation outside main block +# Parser states +use constant { + STATE_NORMAL => 0, # normal code + STATE_NAME => 1, # looking for function name + STATE_FIELD => 2, # scanning field start + STATE_PROTO => 3, # scanning prototype + STATE_DOCBLOCK => 4, # documentation block + STATE_INLINE => 5, # gathering documentation outside main block +}; my $state; my $in_doc_sect; -# Split Doc State -# 0 - Invalid (Before start or after finish) -# 1 - Is started (the /** was found inside a struct) -# 2 - The @parameter header was found, start accepting multi paragraph text. -# 3 - Finished (the */ was found) -# 4 - Error - Comment without header was found. Spit a warning as it's not -# proper kernel-doc and ignore the rest. -my $split_doc_state; +# Inline documentation state +use constant { + STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE) + STATE_INLINE_NAME => 1, # looking for member name (@foo:) + STATE_INLINE_TEXT => 2, # looking for member documentation + STATE_INLINE_END => 3, # done + STATE_INLINE_ERROR => 4, # error - Comment without header was found. + # Spit a warning as it's not + # proper kernel-doc and ignore the rest. +}; +my $inline_doc_state; #declaration types: can be # 'function', 'struct', 'union', 'enum', 'typedef' my $decl_type; -my $doc_special = "\@\%\$\&"; - my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; -my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; +# @params and a strictly limited set of supported section names +my $doc_sect = $doc_com . + '\s*(\@\w+|description|context|returns?|notes?|examples?)\s*:(.*)'; my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; -my $doc_split_start = '^\s*/\*\*\s*$'; -my $doc_split_sect = '\s*\*\s*(@[\w\s]+):(.*)'; -my $doc_split_end = '^\s*\*/\s*$'; +my $doc_inline_start = '^\s*/\*\*\s*$'; +my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)'; +my $doc_inline_end = '^\s*\*/\s*$'; +my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; -my %constants; my %parameterdescs; +my %parameterdesc_start_lines; my @parameterlist; my %sections; my @sectionlist; +my %section_start_lines; my $sectcheck; my $struct_actual; my $contents = ""; +my $new_start_line = 0; + +# the canonical section names. see also $doc_sect above. my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; @@ -437,19 +475,27 @@ while ($ARGV[0] =~ m/^-(.*)/) { } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document $modulename = shift @ARGV; } elsif ($cmd eq "-function") { # to only output specific functions - $function_only = 1; + $output_selection = OUTPUT_INCLUDE; $function = shift @ARGV; $function_table{$function} = 1; - } elsif ($cmd eq "-nofunction") { # to only output specific functions - $function_only = 2; + } elsif ($cmd eq "-nofunction") { # output all except specific functions + $output_selection = OUTPUT_EXCLUDE; $function = shift @ARGV; $function_table{$function} = 1; + } elsif ($cmd eq "-export") { # only exported symbols + $output_selection = OUTPUT_EXPORTED; + %function_table = () + } elsif ($cmd eq "-internal") { # only non-exported symbols + $output_selection = OUTPUT_INTERNAL; + %function_table = () } elsif ($cmd eq "-v") { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq '-no-doc-sections') { $no_doc_sections = 1; + } elsif ($cmd eq '-enable-lineno') { + $enable_lineno = 1; } elsif ($cmd eq '-show-not-found') { $show_not_found = 1; } @@ -467,6 +513,13 @@ sub get_kernel_version() { return $version; } +# +sub print_lineno { + my $lineno = shift; + if ($enable_lineno && defined($lineno)) { + print "#define LINENO " . $lineno . "\n"; + } +} ## # dumps section contents to arrays/hashes intended for that purpose. # @@ -475,28 +528,32 @@ sub dump_section { my $name = shift; my $contents = join "\n", @_; - if ($name =~ m/$type_constant/) { - $name = $1; -# print STDERR "constant section '$1' = '$contents'\n"; - $constants{$name} = $contents; - } elsif ($name =~ m/$type_param/) { + if ($name =~ m/$type_param/) { # print STDERR "parameter def '$1' = '$contents'\n"; $name = $1; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } elsif ($name eq "@\.\.\.") { # print STDERR "parameter def '...' = '$contents'\n"; $name = "..."; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } else { # print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { - print STDERR "${file}:$.: error: duplicate section name '$name'\n"; - ++$errors; + print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; + ++$warnings; + $sections{$name} .= $contents; + } else { + $sections{$name} = $contents; + push @sectionlist, $name; + $section_start_lines{$name} = $new_start_line; + $new_start_line = 0; } - $sections{$name} = $contents; - push @sectionlist, $name; } } @@ -512,15 +569,17 @@ sub dump_doc_section { return; } - if (($function_only == 0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !defined($function_table{$name}))) + if (($output_selection == OUTPUT_ALL) || + ($output_selection == OUTPUT_INCLUDE && + defined($function_table{$name})) || + ($output_selection == OUTPUT_EXCLUDE && + !defined($function_table{$name}))) { dump_section($file, $name, $contents); output_blockhead({'sectionlist' => \@sectionlist, 'sections' => \%sections, 'module' => $modulename, - 'content-only' => ($function_only != 0), }); + 'content-only' => ($output_selection != OUTPUT_ALL), }); } } @@ -1736,7 +1795,10 @@ sub output_blockhead_rst(%) { my ($parameter, $section); foreach $section (@{$args{'sectionlist'}}) { - print "**$section**\n\n"; + if ($output_selection != OUTPUT_INCLUDE) { + print "**$section**\n\n"; + } + print_lineno($section_start_lines{$section}); output_highlight_rst($args{'sections'}{$section}); print "\n"; } @@ -1753,19 +1815,14 @@ sub output_highlight_rst { die $@ if $@; foreach $line (split "\n", $contents) { - if ($line eq "") { - print $lineprefix, $blankline; - } else { - $line =~ s/\\\\\\/\&/g; - print $lineprefix, $line; - } - print "\n"; + print $lineprefix . $line . "\n"; } } sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); + my $oldprefix = $lineprefix; my $start; print ".. c:function:: "; @@ -1790,29 +1847,37 @@ sub output_function_rst(%) { print $type . " " . $parameter; } } - print ")\n\n " . $args{'purpose'} . "\n\n"; + print ")\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print ":Parameters:\n\n"; + print "**Parameters**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; #$parameter_name =~ s/\[.*//; $type = $args{'parametertypes'}{$parameter}; if ($type ne "") { - print " ``$type $parameter``\n"; + print "``$type $parameter``\n"; } else { - print " ``$parameter``\n"; + print "``$parameter``\n"; } - if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) { - my $oldprefix = $lineprefix; - $lineprefix = " "; + + print_lineno($parameterdesc_start_lines{$parameter_name}); + + if (defined($args{'parameterdescs'}{$parameter_name}) && + $args{'parameterdescs'}{$parameter_name} ne $undescribed) { output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = $oldprefix; } else { - print "\n _undescribed_\n"; + print " *undescribed*\n"; } print "\n"; } + + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1820,10 +1885,11 @@ sub output_section_rst(%) { my %args = %{$_[0]}; my $section; my $oldprefix = $lineprefix; - $lineprefix = " "; + $lineprefix = ""; foreach $section (@{$args{'sectionlist'}}) { - print ":$section:\n\n"; + print "**$section**\n\n"; + print_lineno($section_start_lines{$section}); output_highlight_rst($args{'sections'}{$section}); print "\n"; } @@ -1834,24 +1900,28 @@ sub output_section_rst(%) { sub output_enum_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; my $count; my $name = "enum " . $args{'enum'}; print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print "..\n\n:Constants:\n\n"; - my $oldprefix = $lineprefix; - $lineprefix = " "; + print "**Constants**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { - print " `$parameter`\n"; + print "``$parameter``\n"; if ($args{'parameterdescs'}{$parameter} ne $undescribed) { output_highlight_rst($args{'parameterdescs'}{$parameter}); } else { - print " undescribed\n"; + print " *undescribed*\n"; } print "\n"; } + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1859,30 +1929,37 @@ sub output_enum_rst(%) { sub output_typedef_rst(%) { my %args = %{$_[0]}; my ($parameter); - my $count; + my $oldprefix = $lineprefix; my $name = "typedef " . $args{'typedef'}; - ### FIXME: should the name below contain "typedef" or not? print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; + $lineprefix = $oldprefix; output_section_rst(@_); } sub output_struct_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; my $name = $args{'type'} . " " . $args{'struct'}; print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print ":Definition:\n\n"; - print " ::\n\n"; + print "**Definition**\n\n"; + print "::\n\n"; print " " . $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { - print " " . "$parameter\n"; + print " " . "$parameter\n"; next; } @@ -1903,7 +1980,8 @@ sub output_struct_rst(%) { } print " };\n\n"; - print ":Members:\n\n"; + print "**Members**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; @@ -1912,14 +1990,14 @@ sub output_struct_rst(%) { ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; - print " `$type $parameter`" . "\n"; - my $oldprefix = $lineprefix; - $lineprefix = " "; + print_lineno($parameterdesc_start_lines{$parameter_name}); + print "``$type $parameter``\n"; output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = $oldprefix; print "\n"; } print "\n"; + + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1969,9 +2047,13 @@ sub output_declaration { my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; - if (($function_only==0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !($functype eq "function" && defined($function_table{$name})))) + if (($output_selection == OUTPUT_ALL) || + (($output_selection == OUTPUT_INCLUDE || + $output_selection == OUTPUT_EXPORTED) && + defined($function_table{$name})) || + (($output_selection == OUTPUT_EXCLUDE || + $output_selection == OUTPUT_INTERNAL) && + !($functype eq "function" && defined($function_table{$name})))) { &$func(@_); $section_counter++; @@ -2471,7 +2553,6 @@ sub dump_function($$) { sub reset_state { $function = ""; - %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); @@ -2481,8 +2562,8 @@ sub reset_state { $struct_actual = ""; $prototype = ""; - $state = 0; - $split_doc_state = 0; + $state = STATE_NORMAL; + $inline_doc_state = STATE_INLINE_NA; } sub tracepoint_munge($) { @@ -2545,7 +2626,7 @@ sub syscall_munge() { } } -sub process_state3_function($$) { +sub process_proto_function($$) { my $x = shift; my $file = shift; @@ -2575,7 +2656,7 @@ sub process_state3_function($$) { } } -sub process_state3_type($$) { +sub process_proto_type($$) { my $x = shift; my $file = shift; @@ -2657,6 +2738,7 @@ sub process_file($) { my $in_purpose = 0; my $initial_section_counter = $section_counter; my ($orig_file) = @_; + my $leading_space; if (defined($ENV{'SRCTREE'})) { $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; @@ -2674,6 +2756,17 @@ sub process_file($) { return; } + # two passes for -export and -internal + if ($output_selection == OUTPUT_EXPORTED || + $output_selection == OUTPUT_INTERNAL) { + while (<IN>) { + if (/$export_symbol/o) { + $function_table{$2} = 1; + } + } + seek(IN, 0, 0); + } + $. = 1; $section_counter = 0; @@ -2681,15 +2774,18 @@ sub process_file($) { while (s/\\\s*$//) { $_ .= <IN>; } - if ($state == 0) { + if ($state == STATE_NORMAL) { if (/$doc_start/o) { - $state = 1; # next line is always the function name + $state = STATE_NAME; # next line is always the function name $in_doc_sect = 0; + $declaration_start_line = $. + 1; } - } elsif ($state == 1) { # this line is the function name (always) + } elsif ($state == STATE_NAME) {# this line is the function name (always) if (/$doc_block/o) { - $state = 4; + $state = STATE_DOCBLOCK; $contents = ""; + $new_start_line = $. + 1; + if ( $1 eq "" ) { $section = $section_intro; } else { @@ -2702,7 +2798,12 @@ sub process_file($) { $identifier = $1; } - $state = 2; + $state = STATE_FIELD; + # if there's no @param blocks need to set up default section + # here + $contents = ""; + $section = $section_default; + $new_start_line = $. + 1; if (/-(.*)/) { # strip leading/trailing/multiple spaces $descr= $1; @@ -2740,13 +2841,25 @@ sub process_file($) { print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", " - I thought it was a doc line\n"; ++$warnings; - $state = 0; + $state = STATE_NORMAL; } - } elsif ($state == 2) { # look for head: lines, and include content - if (/$doc_sect/o) { + } elsif ($state == STATE_FIELD) { # look for head: lines, and include content + if (/$doc_sect/i) { # case insensitive for supported section names $newsection = $1; $newcontents = $2; + # map the supported section names to the canonical names + if ($newsection =~ m/^description$/i) { + $newsection = $section_default; + } elsif ($newsection =~ m/^context$/i) { + $newsection = $section_context; + } elsif ($newsection =~ m/^returns?$/i) { + $newsection = $section_return; + } elsif ($newsection =~ m/^\@return$/) { + # special: @return is a section, not a param description + $newsection = $section_return; + } + if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { print STDERR "${file}:$.: warning: contents before sections\n"; @@ -2759,14 +2872,16 @@ sub process_file($) { $in_doc_sect = 1; $in_purpose = 0; $contents = $newcontents; + $new_start_line = $.; + while ((substr($contents, 0, 1) eq " ") || + substr($contents, 0, 1) eq "\t") { + $contents = substr($contents, 1); + } if ($contents ne "") { - while ((substr($contents, 0, 1) eq " ") || - substr($contents, 0, 1) eq "\t") { - $contents = substr($contents, 1); - } $contents .= "\n"; } $section = $newsection; + $leading_space = undef; } elsif (/$doc_end/) { if (($contents ne "") && ($contents ne "\n")) { dump_section($file, $section, xml_escape($contents)); @@ -2780,7 +2895,7 @@ sub process_file($) { } $prototype = ""; - $state = 3; + $state = STATE_PROTO; $brcount = 0; # print STDERR "end of doc comment, looking for prototype\n"; } elsif (/$doc_content/) { @@ -2791,6 +2906,7 @@ sub process_file($) { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; + $new_start_line = $.; } else { $contents .= "\n"; } @@ -2801,87 +2917,86 @@ sub process_file($) { $declaration_purpose .= " " . xml_escape($1); $declaration_purpose =~ s/\s+/ /g; } else { - $contents .= $1 . "\n"; + my $cont = $1; + if ($section =~ m/^@/ || $section eq $section_context) { + if (!defined $leading_space) { + if ($cont =~ m/^(\s+)/) { + $leading_space = $1; + } else { + $leading_space = ""; + } + } + + $cont =~ s/^$leading_space//; + } + $contents .= $cont . "\n"; } } else { # i dont know - bad line? ignore. print STDERR "${file}:$.: warning: bad line: $_"; ++$warnings; } - } elsif ($state == 5) { # scanning for split parameters + } elsif ($state == STATE_INLINE) { # scanning for inline parameters # First line (state 1) needs to be a @parameter - if ($split_doc_state == 1 && /$doc_split_sect/o) { + if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { $section = $1; $contents = $2; + $new_start_line = $.; if ($contents ne "") { while ((substr($contents, 0, 1) eq " ") || substr($contents, 0, 1) eq "\t") { $contents = substr($contents, 1); } - $contents .= "\n"; + $contents .= "\n"; } - $split_doc_state = 2; + $inline_doc_state = STATE_INLINE_TEXT; # Documentation block end */ - } elsif (/$doc_split_end/) { + } elsif (/$doc_inline_end/) { if (($contents ne "") && ($contents ne "\n")) { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } - $state = 3; - $split_doc_state = 0; + $state = STATE_PROTO; + $inline_doc_state = STATE_INLINE_NA; # Regular text } elsif (/$doc_content/) { - if ($split_doc_state == 2) { + if ($inline_doc_state == STATE_INLINE_TEXT) { $contents .= $1 . "\n"; - } elsif ($split_doc_state == 1) { - $split_doc_state = 4; + # nuke leading blank lines + if ($contents =~ /^\s*$/) { + $contents = ""; + } + } elsif ($inline_doc_state == STATE_INLINE_NAME) { + $inline_doc_state = STATE_INLINE_ERROR; print STDERR "Warning(${file}:$.): "; print STDERR "Incorrect use of kernel-doc format: $_"; ++$warnings; } } - } elsif ($state == 3) { # scanning for function '{' (end of prototype) - if (/$doc_split_start/) { - $state = 5; - $split_doc_state = 1; + } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype) + if (/$doc_inline_start/) { + $state = STATE_INLINE; + $inline_doc_state = STATE_INLINE_NAME; } elsif ($decl_type eq 'function') { - process_state3_function($_, $file); + process_proto_function($_, $file); } else { - process_state3_type($_, $file); + process_proto_type($_, $file); } - } elsif ($state == 4) { - # Documentation block - if (/$doc_block/) { - dump_doc_section($file, $section, xml_escape($contents)); - $contents = ""; - $function = ""; - %constants = (); - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } - } - elsif (/$doc_end/) + } elsif ($state == STATE_DOCBLOCK) { + if (/$doc_end/) { dump_doc_section($file, $section, xml_escape($contents)); + $section = $section_default; $contents = ""; $function = ""; - %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $prototype = ""; - $state = 0; + $state = STATE_NORMAL; } elsif (/$doc_content/) { @@ -2898,7 +3013,7 @@ sub process_file($) { } if ($initial_section_counter == $section_counter) { print STDERR "${file}:1: warning: no structured comments found\n"; - if (($function_only == 1) && ($show_not_found == 1)) { + if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) { print STDERR " Was looking for '$_'.\n" for keys %function_table; } if ($output_mode eq "xml") { |