summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/.gitignore1
-rw-r--r--Documentation/DocBook/Makefile7
-rw-r--r--Documentation/DocBook/gpu.tmpl11
-rw-r--r--Documentation/Makefile.sphinx63
-rw-r--r--Documentation/conf.py414
-rw-r--r--Documentation/dmaengine/provider.txt2
-rw-r--r--Documentation/index.rst23
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/mic/mpssd/mpssd.c4
-rw-r--r--Documentation/security/self-protection.txt28
-rw-r--r--Documentation/sphinx/convert_template.sed18
-rw-r--r--Documentation/sphinx/kernel-doc.py127
-rw-r--r--Documentation/sphinx/post_convert.sed23
-rwxr-xr-xDocumentation/sphinx/tmplcvt19
-rw-r--r--Documentation/sync_file.txt6
-rw-r--r--Documentation/zh_CN/CodingStyle581
-rw-r--r--Makefile5
-rw-r--r--drivers/gpu/drm/Makefile5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c4
-rw-r--r--drivers/gpu/drm/arc/arcpgu.h1
-rw-r--r--drivers/gpu/drm/arc/arcpgu_crtc.c16
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c27
-rw-r--r--drivers/gpu/drm/arc/arcpgu_hdmi.c18
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c8
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c12
-rw-r--r--drivers/gpu/drm/bridge/analogix-anx78xx.c8
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi.c11
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c8
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c10
-rw-r--r--drivers/gpu/drm/drm_atomic.c22
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c491
-rw-r--r--drivers/gpu/drm/drm_crtc.c292
-rw-r--r--drivers/gpu/drm/drm_drv.c2
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c1
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c6
-rw-r--r--drivers/gpu/drm/drm_fops.c6
-rw-r--r--drivers/gpu/drm/drm_fourcc.c320
-rw-r--r--drivers/gpu/drm/drm_irq.c80
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c16
-rw-r--r--drivers/gpu/drm/drm_prime.c10
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c205
-rw-r--r--drivers/gpu/drm/drm_sysfs.c71
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c8
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c23
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c9
-rw-r--r--drivers/gpu/drm/gma500/gma_display.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c20
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c10
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c1
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c1
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c1
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c9
-rw-r--r--drivers/gpu/drm/msm/edp/edp_connector.c10
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c8
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c9
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h3
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c10
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c12
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.h3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vgacon.c3
-rw-r--r--drivers/gpu/drm/rockchip/analogix_dp-rockchip.c15
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi.c9
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.c9
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c194
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h12
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.c72
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c5
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c68
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c2
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c10
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c10
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c10
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_crtc.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c10
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tv.c9
-rw-r--r--drivers/gpu/drm/tegra/drm.c2
-rw-r--r--drivers/gpu/drm/tegra/drm.h2
-rw-r--r--drivers/gpu/drm/tegra/dsi.c1
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c1
-rw-r--r--drivers/gpu/drm/tegra/output.c8
-rw-r--r--drivers/gpu/drm/tegra/rgb.c1
-rw-r--r--drivers/gpu/drm/tegra/sor.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c81
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c7
-rw-r--r--include/drm/drmP.h10
-rw-r--r--include/drm/drm_atomic.h16
-rw-r--r--include/drm/drm_atomic_helper.h14
-rw-r--r--include/drm/drm_crtc.h161
-rw-r--r--include/drm/drm_fb_helper.h11
-rw-r--r--include/drm/drm_fourcc.h37
-rw-r--r--include/drm/drm_mipi_dsi.h2
-rw-r--r--include/drm/drm_modeset_helper_vtables.h39
-rw-r--r--include/drm/drm_simple_kms_helper.h94
-rwxr-xr-xscripts/kernel-doc393
125 files changed, 2935 insertions, 1640 deletions
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 000000000000..53752db253e3
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1 @@
+output
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index d70f9b68174e..e0c7e1e0590b 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 dac18b4ff090..d09536c91717 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 000000000000..addf32309bc3
--- /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 000000000000..6cc41a0555a3
--- /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 122b7f4876bb..91ce82d5f0c4 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 000000000000..71a276f34c7f
--- /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 82b42c958d1c..a2a662d4da83 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 30fb842a976d..49db1def1721 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 babd6378ec05..3010576c9fca 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 000000000000..c1503fcca4ec
--- /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 000000000000..4adfb0e91ecc
--- /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 000000000000..392770bac53b
--- /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 000000000000..909a73065e0a
--- /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 eaf8297dbca2..e8e2ebafe5fa 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 654afd72eb24..bbb9d6ae05ca 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æ—¥ă€‚
diff --git a/Makefile b/Makefile
index 8d1301ab59fd..801457b847a4 100644
--- a/Makefile
+++ b/Makefile
@@ -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 be43afb08c69..e3dba6f44a79 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 0b5f3accb1e4..a6eecf6f9065 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 112e358f0f9b..c1b04e9aab57 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 b522fa2435a8..c90408bc0fde 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 b50ed72feedb..300ff4aab0fd 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 329ac7570911..e8fcf3ab1d9a 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 92f8beff8e60..ee0a61c2861b 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 07c1bdeca489..381c5fcbf903 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 08b6baeb320d..b7a8b2ac4055 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 49e586d67595..74279be20b75 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 6485fa5bee8b..9ecf16c7911d 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 39802c0539b6..473a475f27b1 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 d087b054c360..f9f03bcba0af 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 c9d941283d30..70b1f7d4270b 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 7ecd59f70b8e..93f3dacf9e27 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 be881e9fef8f..5cd8dd7e5904 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 5e4b820a977c..d99ab2f6663f 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 bb98d74d1a2e..de7fddce3cef 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 df91dfe506eb..4ec35f9e6de5 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 bff89226a344..8b2582aeaab6 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 2e7ef0b325e2..c0b0c718994a 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 ba5aac7276e4..0bac5246e5a7 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 64121f567234..a27bc7cda975 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 000000000000..0645c85d5f95
--- /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 4dc41ff388f9..76e39c50c90c 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 7938ce7ebed8..49311fc61d5d 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 aab0f3f1f42d..780589b420a4 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 000000000000..b2071d495ada
--- /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 fa7fadce8063..32dd821b7202 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 5e38e749ac17..ad6b73c7fc59 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 843b21c540b3..4a679fb9bb02 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 601ecf8006a7..e07cb1fe4860 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 55f1d37c666a..77f12c00abf9 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 608b0afa337f..e8f6c92b2a36 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 58de5a430508..1625d7c8a319 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 89c0084c2814..706de3278f1c 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 98c998da91eb..0b0989e503ea 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 5b636bf0b467..1a1cf7a3b5ef 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 fba6372d060e..ed76baad525f 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 e4f2c55d9697..614ac085e51f 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 622968161ac7..9465de4135aa 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 60cba1956c0d..49322f6cfa2b 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 f97cd5305e4c..be083519dac9 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 ebe7b3427e2e..270da8de0acf 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 c70132aa91d5..a2ead5eac336 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 a456f2eb68b6..c86f88ed92fd 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 ef8e67690f3d..4c725ad6fb54 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 eb455ea6ea92..6b29da9bba38 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 62eaa895fe5b..e06b9036bebc 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 1a71456bd12a..ab2d0658abe6 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 1f3a0e1e1a1f..7ac9e9b0e2c3 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 06a417b2f91e..c33bf98c5d5e 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 769559124562..28b2044ed9f2 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 72360cd038c0..5960628ceb93 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 b15d72683112..a2515b466ce5 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 2648cd7631ef..353429b05733 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 8c3b463620bd..4a8a6f1f1151 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 7c77f960c8b8..6072fe292db8 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 24273bacd885..0420ee861ea4 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 ce2d67b6a8c7..137fe690a0da 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 3b702230a88c..6b97011154bf 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 2e216e2ea78c..e91763d5d800 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 e85c7a2f565b..3965d1916b9c 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 478d4099b0d0..d0de4022fff9 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 4e939e41f030..55149e9ce28e 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 719b6f2a031c..a8669c3e0dd5 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 6c927144b5c9..612b4d5ae098 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 86c109b16876..6bb032d8ac6b 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 e905f5da7aaa..6afd0af312ba 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 9d7e5c99caf6..8d6125c1c0f9 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 7f6a55cae27a..c120172add5c 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 dedc65b40f36..ca22e5ee89ca 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 f8b4feb60b25..006260de9dbd 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 09a4d429c0f0..c2bcc5ea1abe 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 56f43a364c7f..ea3932940061 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 755cfdba61cd..20f12bc5a386 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 f261512bb4a0..207e01de6e32 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 9c2d8a894093..059e902f872d 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 5567fb43e674..8cd840f602b7 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 b440617a7019..dd2c400c4a46 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 d439128e6309..e2901667eceb 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 9f49c00f1a02..dcec5a8eda59 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 85545ebf88d3..36d9d6635784 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 4182a21f5923..f628b6d8f23f 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 ab6494818050..442cfe271688 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 bc047f923508..b84147896294 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 b59c3bf0df44..a177a42a9849 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 f52d6cb24ff5..0ddcce1b420d 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 d1239ebc190f..099cccb2fbcb 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 b7ef4929e347..2fdb8796443e 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 46664b622270..1480f6aaffe4 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 e246334e0252..a131b44e2d6f 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 757c6e8603af..34958d71284b 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 9817dbfa4ac3..dba1114297e4 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 fd2644d231ff..68df91c3f860 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 39c0b2048bfd..8f4d5ffc32be 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 d82ae1cddfcf..ac758cdbc1bc 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 67cebb23c940..aa04fb0159a7 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 9e5eefd6f733..04310cb08111 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 d12cfb9c6062..856a9c85a838 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 1877a7c18d8e..d86ae5dcd7b4 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 1a8d66ca677c..914baa8c161d 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 5b4aa35026a3..db8d4780eaa2 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 000000000000..7f90a396cf2b
--- /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 ec552854a8f8..72f5b15e0738 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 4e7a53b12632..b55f21857a98 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 000000000000..269039722f91
--- /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 2fc8fad5195e..27757c21551a 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 = '\\&amp;((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") {